—#!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
# Note: This completer script is generated by App::GenPericmdCompleterScript version 0.11
# on Tue Jan 16 16:16:04 2018. You probably should not manually edit this file.
# NO_PERINCI_CMDLINE_SCRIPT
# PERINCI_CMDLINE_COMPLETER_SCRIPT: {program_name=>"genpw-base56",read_config=>0,read_env=>0,skip_format=>undef,subcommands=>undef,url=>"/App/genpw/base56/genpw"}
# FRAGMENT id=shcompgen-hint completer=1 for=genpw-base56
our
$DATE
=
'2018-01-16'
;
# DATE
our
$VERSION
=
'0.001'
;
# VERSION
# PODNAME: _genpw-base56
# ABSTRACT: Completer script for genpw-base56
use
5.010;
use
strict;
use
warnings;
die
"Please run this script under shell completion\n"
unless
$ENV
{COMP_LINE} ||
$ENV
{COMMAND_LINE};
my
$args
= {
program_name
=>
"genpw-base56"
,
read_config
=>0,
read_env
=>0,
skip_format
=>
undef
,
subcommands
=>
undef
,
url
=>
"/App/genpw/base56/genpw"
};
my
$meta
= {
_orig_args_as
=>
undef
,
_orig_result_naked
=>
undef
,
args
=>{
len
=>{
cmdline_aliases
=>{
l
=>{}},
schema
=>[
"posint"
,{
req
=>1},{}],
summary
=>
"If no pattern is supplied, will generate random alphanum characters with this exact length"
},
max_len
=>{
schema
=>[
"posint"
,{
req
=>1},{}],
summary
=>
"If no pattern is supplied, will generate random alphanum characters with this maximum length"
},
min_len
=>{
schema
=>[
"posint"
,{
req
=>1},{}],
summary
=>
"If no pattern is supplied, will generate random alphanum characters with this minimum length"
},
num
=>{
cmdline_aliases
=>{
n
=>{}},
default
=>1,
pos
=>0,
schema
=>[
"int"
,{
min
=>1,
req
=>1},{}]}},
args_as
=>
"hash"
,
description
=>
"\n"
,
entity_date
=>
undef
,
entity_v
=>
undef
,
examples
=>[],
result_naked
=>0,
summary
=>
"Generate random password using base56 characters"
,
v
=>1.1};
my
$sc_metas
= {};
my
$copts
= {
format
=>{
default
=>
undef
,
getopt
=>
"format=s"
,
handler
=>
sub
{
package
Perinci::CmdLine::Base;
use
warnings;
use
strict;
no
feature;
use
feature
':5.10'
;
my
(
$go
,
$val
,
$r
) =
@_
;
$$r
{
'format'
} =
$val
},
is_settable_via_config
=>1,
schema
=>[
"str*"
,
"in"
,[
"text"
,
"text-simple"
,
"text-pretty"
,
"json"
,
"json-pretty"
,
"csv"
,
"html"
,
"html+datatables"
,
"perl"
]],
summary
=>
"Choose output format, e.g. json, text"
,
tags
=>[
"category:output"
]},
help
=>{
getopt
=>
"help|h|?"
,
handler
=>
sub
{
package
Perinci::CmdLine::Base;
use
warnings;
use
strict;
no
feature;
use
feature
':5.10'
;
my
(
$go
,
$val
,
$r
) =
@_
;
$$r
{
'action'
} =
'help'
;
$$r
{
'skip_parse_subcommand_argv'
} = 1},
order
=>0,
summary
=>
"Display help message and exit"
,
usage
=>
"--help (or -h, -?)"
},
json
=>{
getopt
=>
"json"
,
handler
=>
sub
{
package
Perinci::CmdLine::Base;
use
warnings;
use
strict;
no
feature;
use
feature
':5.10'
;
my
(
$go
,
$val
,
$r
) =
@_
;
$$r
{
'format'
} = -t STDOUT ?
'json-pretty'
:
'json'
},
summary
=>
"Set output format to json"
,
tags
=>[
"category:output"
]},
naked_res
=>{
default
=>0,
description
=>
"\nBy default, when outputing as JSON, the full enveloped result is returned, e.g.:\n\n [200,\"OK\",[1,2,3],{\"func.extra\"=>4}]\n\nThe reason is so you can get the status (1st element), status message (2nd\nelement) as well as result metadata/extra result (4th element) instead of just\nthe result (3rd element). However, sometimes you want just the result, e.g. when\nyou want to pipe the result for more post-processing. In this case you can use\n`--naked-res` so you just get:\n\n [1,2,3]\n\n"
,
getopt
=>
"naked-res!"
,
handler
=>
sub
{
package
Perinci::CmdLine::Base;
use
warnings;
use
strict;
no
feature;
use
feature
':5.10'
;
my
(
$go
,
$val
,
$r
) =
@_
;
$$r
{
'naked_res'
} =
$val
? 1 : 0},
is_settable_via_config
=>1,
summary
=>
"When outputing as JSON, strip result envelope"
,
"summary.alt.bool.not"
=>
"When outputing as JSON, add result envelope"
,
tags
=>[
"category:output"
]},
version
=>{
getopt
=>
"version|v"
,
handler
=>
sub
{
package
Perinci::CmdLine::Base;
use
warnings;
use
strict;
no
feature;
use
feature
':5.10'
;
my
(
$go
,
$val
,
$r
) =
@_
;
$$r
{
'action'
} =
'version'
;
$$r
{
'skip_parse_subcommand_argv'
} = 1},
summary
=>
"Display program's version and exit"
,
usage
=>
"--version (or -v)"
}};
my
$r
= {};
# get words
my
$shell
;
my
(
$words
,
$cword
);
if
(
$ENV
{COMP_LINE}) {
$shell
=
"bash"
;
require
Complete::Bash;
require
Encode; (
$words
,
$cword
) = @{ Complete::Bash::parse_cmdline() }; (
$words
,
$cword
) = @{ Complete::Bash::join_wordbreak_words(
$words
,
$cword
) };
$words
= [
map
{Encode::decode(
"UTF-8"
,
$_
)}
@$words
]; }
elsif
(
$ENV
{COMMAND_LINE}) {
$shell
=
"tcsh"
;
require
Complete::Tcsh; (
$words
,
$cword
) = @{ Complete::Tcsh::parse_cmdline() }; }
@ARGV
=
@$words
;
# strip program name
shift
@$words
;
$cword
--;
# parse common_opts which potentially sets subcommand
{
my
$old_go_conf
= Getopt::Long::Configure(
'pass_through'
,
'no_ignore_case'
,
'bundling'
,
'no_auto_abbrev'
,
'no_getopt_compat'
,
'gnu_compat'
);
my
@go_spec
;
for
my
$k
(
keys
%$copts
) {
push
@go_spec
,
$copts
->{
$k
}{getopt} =>
sub
{
my
(
$go
,
$val
) =
@_
;
$copts
->{
$k
}{handler}->(
$go
,
$val
,
$r
); } }
Getopt::Long::GetOptions(
@go_spec
);
Getopt::Long::Configure(
$old_go_conf
);
}
# select subcommand
my
$scn
=
$r
->{subcommand_name};
my
$scn_from
=
$r
->{subcommand_name_from};
if
(!
defined
(
$scn
) &&
defined
(
$args
->{default_subcommand})) {
# get from default_subcommand
if
(
$args
->{get_subcommand_from_arg} == 1) {
$scn
=
$args
->{default_subcommand};
$scn_from
=
"default_subcommand"
;
}
elsif
(
$args
->{get_subcommand_from_arg} == 2 && !
@ARGV
) {
$scn
=
$args
->{default_subcommand};
$scn_from
=
"default_subcommand"
;
}
}
if
(!
defined
(
$scn
) &&
$args
->{subcommands} &&
@ARGV
) {
# get from first command-line arg
$scn
=
shift
@ARGV
;
$scn_from
=
"arg"
;
}
if
(
defined
(
$scn
) && !
$sc_metas
->{
$scn
}) {
undef
$scn
}
# unknown subcommand name
# XXX read_env
# complete with periscomp
my
$compres
;
{
$compres
= Perinci::Sub::Complete::complete_cli_arg(
meta
=>
defined
(
$scn
) ?
$sc_metas
->{
$scn
} :
$meta
,
words
=>
$words
,
cword
=>
$cword
,
common_opts
=>
$copts
,
riap_server_url
=>
undef
,
riap_uri
=>
undef
,
extras
=> {
r
=>
$r
,
cmdline
=>
undef
},
func_arg_starts_at
=> ((
$scn_from
//
""
) eq
"arg"
? 1:0),
completion
=>
sub
{
my
%args
=
@_
;
my
$type
=
$args
{type};
# user specifies custom completion routine, so use that first
if
(
$args
->{completion}) {
my
$res
=
$args
->{completion}->(
%args
);
return
$res
if
$res
;
}
# if subcommand name has not been supplied and we're at arg#0,
# complete subcommand name
if
(
$args
->{subcommands} &&
$scn_from
ne
"--cmd"
&&
$type
eq
"arg"
&&
$args
{argpos}==0) {
return
Complete::Util::complete_array_elem(
array
=> [
keys
%{
$args
->{subcommands} }],
word
=>
$words
->[
$cword
]);
}
# otherwise let periscomp do its thing
return
undef
;
},
);
}
# display result
if
(
$shell
eq
"bash"
) {
Complete::Bash::format_completion(
$compres
, {
word
=>
$words
->[
$cword
]}) }
elsif
(
$shell
eq
"tcsh"
) {
Complete::Tcsh::format_completion(
$compres
) }
=pod
=encoding UTF-8
=head1 NAME
_genpw-base56 - Completer script for genpw-base56
=head1 VERSION
This document describes version 0.001 of Perinci::CmdLine::Base (from Perl distribution App-genpw-base56), released on 2018-01-16.
=head1 HOMEPAGE
Please visit the project's homepage at L<https://metacpan.org/release/App-genpw-base56>.
=head1 SOURCE
Source repository is at L<https://github.com/perlancar/perl-App-genpw-base56>.
=head1 BUGS
Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=App-genpw-base56>
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) 2018 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__
Data::Section::Seekable v1
Clone/PP.pm,20,1884,0;0
Complete/Bash.pm,1929,17459,1;71
Complete/Common.pm,19415,945,2;596
Complete/Env.pm,20384,2999,3;635
Complete/File.pm,23408,8536,4;760
Complete/Getopt/Long.pm,31976,18507,5;1033
Complete/Path.pm,50508,7961,6;1587
Complete/Tcsh.pm,58494,2757,7;1847
Complete/Util.pm,61276,21457,8;1952
Data/Clean.pm,82755,7950,9;2696
Data/Clean/FromJSON.pm,90736,536,10;2968
Data/Clean/JSON.pm,91299,1140,11;3000
Data/Dmp.pm,92459,4396,12;3052
Data/ModeMerge.pm,96881,10593,13;3236
Data/ModeMerge/Config.pm,107507,2140,14;3554
Data/ModeMerge/Mode/ADD.pm,109682,1373,15;3625
Data/ModeMerge/Mode/Base.pm,111091,16705,16;3694
Data/ModeMerge/Mode/CONCAT.pm,127834,442,17;4224
Data/ModeMerge/Mode/DELETE.pm,128314,1218,18;4252
Data/ModeMerge/Mode/KEEP.pm,129568,1174,19;4327
Data/ModeMerge/Mode/NORMAL.pm,130780,1501,20;4395
Data/ModeMerge/Mode/SUBTRACT.pm,132321,2064,21;4488
Data/Sah/Normalize.pm,134415,6073,22;4580
Data/Sah/Resolve.pm,140516,3692,23;4761
Data/Sah/Util/Type.pm,144238,3406,24;4869
Function/Fallback/CoreOrPP.pm,147682,1761,25;4998
Getopt/Long/Negate/EN.pm,149476,1797,26;5089
Getopt/Long/Util.pm,151301,9133,27;5141
Lingua/EN/PluralToSingular.pm,160472,6120,28;5474
Log/ger.pm,166611,3553,29;5907
Log/ger/Format.pm,170190,184,30;6044
Log/ger/Format/None.pm,170405,281,31;6057
Log/ger/Heavy.pm,170711,14829,32;6076
Log/ger/Layout.pm,185566,197,33;6415
Log/ger/Output.pm,185789,195,34;6428
Log/ger/Output/Array.pm,186016,565,35;6441
Log/ger/Output/ArrayML.pm,186615,685,36;6473
Log/ger/Output/Null.pm,187331,328,37;6507
Log/ger/Output/String.pm,187692,981,38;6527
Log/ger/Plugin.pm,188699,1096,39;6568
Log/ger/Plugin/MultilevelLog.pm,189835,552,40;6628
Log/ger/Util.pm,190411,8411,41;6658
Mo.pm,198836,591,42;6932
Mo/Golf.pm,199446,7519,43;6936
Mo/Inline.pm,206986,2047,44;7153
Mo/Moose.pm,209053,533,45;7239
Mo/Mouse.pm,209606,563,46;7244
Mo/build.pm,210189,248,47;7249
Mo/builder.pm,210459,338,48;7253
Mo/chain.pm,210817,216,49;7257
Mo/coerce.pm,211054,330,50;7261
Mo/default.pm,211406,435,51;7265
Mo/exporter.pm,211864,176,52;7269
Mo/import.pm,212061,185,53;7273
Mo/importer.pm,212269,207,54;7277
Mo/is.pm,212493,228,55;7281
Mo/nonlazy.pm,212743,129,56;7285
Mo/option.pm,212893,259,57;7289
Mo/required.pm,213175,340,58;7293
Mo/xs.pm,213532,256,59;7297
Module/Installed/Tiny.pm,213821,3030,60;7301
Perinci/Sub/Complete.pm,216883,45843,61;7418
Perinci/Sub/GetArgs/Argv.pm,262762,38489,62;8629
Perinci/Sub/GetArgs/Array.pm,301288,3800,63;9689
Perinci/Sub/Normalize.pm,305121,4885,64;9820
Perinci/Sub/Util.pm,310034,12303,65;9972
Perinci/Sub/Util/Args.pm,322370,3131,66;10410
Perinci/Sub/Util/ResObj.pm,325536,243,67;10527
Perinci/Sub/Util/Sort.pm,325812,463,68;10542
Regexp/Stringify.pm,326303,2473,69;10571
Sah/Schema/rinci/function_meta.pm,328818,3632,70;10670
Sah/Schema/rinci/meta.pm,332483,683,71;10808
Sah/Schema/rinci/result_meta.pm,333206,611,72;10851
Sah/SchemaR/rinci/function_meta.pm,333860,7833,73;10886
Sah/SchemaR/rinci/meta.pm,341727,1990,74;11057
Sah/SchemaR/rinci/result_meta.pm,343758,960,75;11116
Sah/Schemas/Rinci.pm,344747,108,76;11157
String/LineNumber.pm,344884,859,77;11166
String/PerlQuote.pm,345771,890,78;11206
String/Wildcard/Bash.pm,346693,2159,79;11256
YAML/Old.pm,348872,2970,80;11344
YAML/Old/Dumper.pm,351869,15162,81;11457
YAML/Old/Dumper/Base.pm,367063,3525,82;11980
YAML/Old/Error.pm,370614,5985,83;12086
YAML/Old/Loader.pm,376626,22219,84;12277
YAML/Old/Loader/Base.pm,398877,1235,85;12989
YAML/Old/Marshall.pm,400141,934,86;13026
YAML/Old/Mo.pm,401098,3050,87;13073
YAML/Old/Node.pm,404173,4409,88;13144
YAML/Old/Tag.pm,408606,240,89;13359
YAML/Old/Types.pm,408872,5904,90;13378
### Clone/PP.pm ###
#package Clone::PP;
#
#use 5.006;
#use strict;
#use warnings;
#use vars qw($VERSION @EXPORT_OK);
#use Exporter;
#
#$VERSION = 1.07;
#
#@EXPORT_OK = qw( clone );
#sub import { goto &Exporter::import }
#
#use vars qw( $CloneSelfMethod $CloneInitMethod );
#$CloneSelfMethod ||= 'clone_self';
#$CloneInitMethod ||= 'clone_init';
#
#use vars qw( %CloneCache );
#
#sub clone {
# my $source = shift;
#
# return undef if not defined($source);
#
# my $depth = shift;
# return $source if ( defined $depth and $depth -- < 1 );
#
# local %CloneCache = ( undef => undef ) unless ( exists $CloneCache{undef} );
#
# return $CloneCache{ $source } if ( defined $CloneCache{ $source } );
#
# my $ref_type = ref $source or return $source;
#
# my $class_name;
# if ( "$source" =~ /^\Q$ref_type\E\=([A-Z]+)\(0x[0-9a-f]+\)$/ ) {
# $class_name = $ref_type;
# $ref_type = $1;
# return $CloneCache{ $source } = $source->$CloneSelfMethod()
# if $source->can($CloneSelfMethod);
# }
#
#
# 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 {
# $CloneCache{ $source } = $copy = $source;
# }
#
# if ( $class_name ) {
# bless $copy, $class_name;
# $copy->$CloneInitMethod() if $copy->can($CloneInitMethod);
# }
#
# return $copy;
#}
#
#1;
#
#__END__
#
### Complete/Bash.pm ###
#package Complete::Bash;
#
#our $DATE = '2016-12-28';
#our $VERSION = '0.31';
#
#use 5.010001;
#use strict;
#use warnings;
#
#require Exporter;
#our @ISA = qw(Exporter);
#our @EXPORT_OK = qw(
# point
# parse_cmdline
# join_wordbreak_words
# format_completion
# );
#
#our %SPEC;
#
#$SPEC{':package'} = {
# v => 1.1,
# summary => 'Completion routines for bash shell',
#};
#
#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";
#}
#
#sub _add_unquoted {
# no warnings 'uninitialized';
#
# my ($word, $is_cur_word, $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{point} = {
# v => 1.1,
# summary => 'Return line with point marked by a marker',
# description => <<'_',
#
#This is a utility function useful for testing/debugging. `parse_cmdline()`
#expects a command-line and a cursor position (`$line`, `$point`). This routine
#expects `$line` with a marker character (by default it's the caret, `^`) and
#return (`$line`, `$point`) to feed to `parse_cmdline()`.
#
#Example:
#
# point("^foo") # => ("foo", 0)
# point("fo^o") # => ("foo", 2)
#
#_
# args_as => 'array',
# args => {
# cmdline => {
# summary => 'Command-line which contains a marker character',
# schema => 'str*',
# pos => 0,
# },
# marker => {
# summary => 'Marker character',
# schema => ['str*', len=>1],
# default => '^',
# pos => 1,
# },
# },
# result_naked => 1,
#};
#sub point {
# my ($line, $marker) = @_;
# $marker //= '^';
#
# my $point = index($line, $marker);
# die "BUG: No marker '$marker' in line <$line>" unless $point >= 0;
# $line =~ s/\Q$marker\E//;
# ($line, $point);
#}
#
#$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; this comparison is made against
#bash versions 4.2-4.3):
#
#1) quotes and backslashes are stripped (bash's `COMP_WORDS` contains all the
# quotes and backslashes);
#
#2) quoted phrase that contains spaces, or phrase that contains escaped spaces is
# parsed as a single word. For example:
#
# command "First argument" Second\ argument
#
# bash would split it as (represented as Perl):
#
# ["command", "\"First", "argument\"", "Second\\", "argument"]
#
# which is not very convenient. We parse it into:
#
# ["command", "First argument", "Second argument"]
#
#3) 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.
#
#4) tildes (`~`) are expanded with user's home directory except for the current
# word (bash does not perform tilde expansion for `COMP_WORDS`);
#
#Caveats:
#
#* Like bash, we group non-whitespace word-breaking characters into its own word.
# By default `COMP_WORDBREAKS` is:
#
# "'@><=;|&(:
#
# So if raw command-line is:
#
# command --foo=bar http://example.com:80 mail@example.org Foo::Bar
#
# then the parse result will be:
#
# ["command", "--foo", "=", "bar", "http", ":", "//example.com", ":", "80", "Foo", "::", "Bar"]
#
# which is annoying sometimes. But we follow bash here so we can more easily
# accept input from a joined `COMP_WORDS` if we write completion bash functions,
# e.g. (in the example, `foo` is a Perl script):
#
# _foo ()
# {
# local words=(${COMP_CWORDS[@]})
# # add things to words, etc
# local point=... # calculate the new point
# COMPREPLY=( `COMP_LINE="foo ${words[@]}" COMP_POINT=$point foo` )
# }
#
# To avoid these word-breaking characters to be split/grouped, we can escape
# them with backslash or quote them, e.g.:
#
# command "http://example.com:80" Foo\:\:Bar
#
# which bash will parse as:
#
# ["command", "\"http://example.com:80\"", "Foo\\:\\:Bar"]
#
# and we parse as:
#
# ["command", "http://example.com:80", "Foo::Bar"]
#
#* Due to the way bash parses the command line (see above), the two below are
# equivalent:
#
# % cmd --foo=bar
# % cmd --foo = bar
#
#Because they both expand to `['--foo', '=', 'bar']`. But obviously
#<pm: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,
# },
# opts => {
# summary => 'Options',
# schema => 'hash*',
# description => <<'_',
#
#Optional. Known options:
#
#* `truncate_current_word` (bool). If set to 1, will truncate current word to the
# position of cursor, for example (`^` marks the position of cursor):
# `--vers^oo` to `--vers` instead of `--versoo`. This is more convenient when
# doing tab completion.
#
#_
# schema => 'hash*',
# pos => 2,
# },
# },
# 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, roughly 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, $opts) = @_;
#
# $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
# ([\@><=|&\(:]+) | # 10) non-whitespace word-breaking characters
# \s+
# )!
# $pos += length($1);
# #say "D: \$1=<$1> \$2=<$3> \$3=<$3> \$4=<$4> \$5=<$5> \$6=<$6> \$7=<$7> \$8=<$8> \$9=<$9> \$10=<$10>";
# #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;
# }
# #say "D:is_cur_word=$is_cur_word";
# $chunk =
# $2 ? _add_double_quoted($3, $is_cur_word) :
# $5 ? _add_single_quoted($6) :
# _add_unquoted($8, $is_cur_word, $after_ws);
# if ($opts && $opts->{truncate_current_word} &&
# $is_cur_word && $pos > $point) {
# $chunk = substr(
# $chunk, 0, length($chunk)-($pos_min_ws-$point));
# #say "D:truncating current word to <$chunk>";
# }
# 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 ($10) {
# # non-whitespace word-breaking characters
# push @words, $10;
# $after_ws = 1;
# } else {
# # whitespace
# $after_ws = 1;
# }
# !egx;
#
# $cword //= @words;
# $words[$cword] //= '';
#
# [\@words, $cword];
#}
#
#$SPEC{join_wordbreak_words} = {
# v => 1.1,
# summary => 'Post-process parse_cmdline() result by joining some words',
# description => <<'_',
#
#`parse_cmdline()`, like bash, splits some characters that are considered as
#word-breaking characters:
#
# "'@><=;|&(:
#
#So if command-line is:
#
# command -MData::Dump bob@example.org
#
#then they will be parsed as:
#
# ["command", "-MData", "::", "Dump", "bob", '@', "example.org"]
#
#Normally in Perl applications, we want `:`, `@` to be part of word. So this
#routine will convert the above into:
#
# ["command", "-MData::Dump", 'bob@example.org']
#
#_
#};
#sub join_wordbreak_words {
# my ($words, $cword) = @_;
# my $new_words = [];
# my $i = -1;
# while (++$i < @$words) {
# my $w = $words->[$i];
# if ($w =~ /\A[\@=:]+\z/) {
# if (@$new_words and $#$new_words != $cword) {
# $new_words->[-1] .= $w;
# $cword-- if $cword >= $i || $cword >= @$new_words;
# } else {
# push @$new_words, $w;
# }
# if ($i+1 < @$words) {
# $i++;
# $new_words->[-1] .= $words->[$i];
# $cword-- if $cword >= $i || $cword >= @$new_words;
# }
# } else {
# push @$new_words, $w;
# }
# }
# [$new_words, $cword];
#}
#
#$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';
# 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;
# }
# }
#
# 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') {
# $word =~ s!([^A-Za-z0-9,+._/\$~-])!\\$1!g;
# } elsif ($esc_mode eq 'none') {
# } else {
# $word =~ s!([^A-Za-z0-9,+._/:~-])!\\$1!g;
# }
# push @res, $word;
# }
#
# if ($as eq 'array') {
# return \@res;
# } else {
# return join("", map {($_, "\n")} @res);
# }
#}
#
#1;
#
#__END__
#
### Complete/Common.pm ###
#package Complete::Common;
#
#our $DATE = '2016-01-05';
#our $VERSION = '0.22';
#
#use 5.010001;
#use strict;
#use warnings;
#
#use Exporter qw(import);
#our @EXPORT_OK = qw(
# %arg_word
# );
#
#our %EXPORT_TAGS = (
# all => \@EXPORT_OK
#);
#
#our %arg_word = (
# word => {
# summary => 'Word to complete',
# schema => ['str', default=>''],
# pos=>0,
# req=>1,
# },
#);
#
#our $OPT_CI = ($ENV{COMPLETE_OPT_CI} // 1) ? 1:0;
#our $OPT_WORD_MODE = ($ENV{COMPLETE_OPT_WORD_MODE} // 1) ? 1:0;
#our $OPT_CHAR_MODE = ($ENV{COMPLETE_OPT_CHAR_MODE} // 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;
#
#__END__
#
### Complete/Env.pm ###
#package Complete::Env;
#
#our $DATE = '2016-10-18';
#our $VERSION = '0.39';
#
#use 5.010001;
#use strict;
#use warnings;
#
#use Complete::Common qw(:all);
#
#require Exporter;
#our @ISA = qw(Exporter);
#our @EXPORT_OK = qw(
# complete_env
# complete_env_elem
# complete_path_env_elem
# );
#
#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 },
# },
# result_naked => 1,
# result => {
# schema => 'array',
# },
#};
#sub complete_env {
# require Complete::Util;
#
# my %args = @_;
# my $word = $args{word} // "";
# if ($word =~ /^\$/) {
# Complete::Util::complete_array_elem(
# word=>$word, array=>[map {"\$$_"} keys %ENV],
# );
# } else {
# Complete::Util::complete_array_elem(
# word=>$word, array=>[keys %ENV],
# );
# }
#}
#
#$SPEC{complete_env_elem} = {
# v => 1.1,
# summary => 'Complete from elements of an environment variable',
# description => <<'_',
#
#An environment variable like PATH contains colon- (or, on Windows, semicolon-)
#separated elements. This routine complete from the elements of such variable.
#
#_
# args => {
# word => { schema=>[str=>{default=>''}], pos=>0, req=>1 },
# env => {
# summary => 'Name of environment variable to use',
# schema => 'str*',
# req => 1,
# pos => 1,
# },
# },
# result_naked => 1,
# result => {
# schema => 'array',
# },
#};
#sub complete_env_elem {
# require Complete::Util;
#
# my %args = @_;
# my $word = $args{word} // "";
# my $env = $args{env};
# my @elems;
# if ($^O eq 'MSWin32') {
# @elems = split /;/, ($ENV{$env} // '');
# } else {
# @elems = split /:/, ($ENV{$env} // '');
# }
# Complete::Util::complete_array_elem(
# word=>$word, array=>\@elems,
# );
#}
#
#$SPEC{complete_path_env_elem} = {
# v => 1.1,
# summary => 'Complete from elements of PATH environment variable',
# description => <<'_',
#
#PATH environment variable contains colon- (or, on Windows, semicolon-) separated
#elements. This routine complete from those elements.
#
#_
# args => {
# word => { schema=>[str=>{default=>''}], pos=>0, req=>1 },
# },
# result_naked => 1,
# result => {
# schema => 'array',
# },
#};
#sub complete_path_env_elem {
# my %args = @_;
# complete_env_elem(word => $args{word}, env => 'PATH');
#}
#
#1;
#
#__END__
#
### Complete/File.pm ###
#package Complete::File;
#
#our $DATE = '2017-07-14';
#our $VERSION = '0.43';
#
#use 5.010001;
#use strict;
#use warnings;
#
#use Complete::Common qw(:all);
#
#require Exporter;
#our @ISA = qw(Exporter);
#our @EXPORT_OK = qw(
# complete_file
# complete_dir
# );
#
#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 => {
# %arg_word,
# 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*']}],
# tags => ['category:filtering'],
# },
# 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*',
# tags => ['category:filtering'],
# },
# exclude_dir => {
# schema => 'bool*',
# description => <<'_',
#
#This is also an alternative to specifying full `filter`. Set this to true if you
#do not want directories.
#
#If you only want directories, take a look at `complete_dir()`.
#
#_
# tags => ['category:filtering'],
# },
# file_ext_filter => {
# schema => ['any*', of=>['re*', ['array*',of=>'str*']]],
# description => <<'_',
#
#This is also an alternative to specifying full `filter` or `file_regex_filter`.
#You can set this to a regex or a set of extensions to accept. Note that like in
#`file_regex_filter`, directories of any name is also still allowed.
#
#_
# tags => ['category:filtering'],
# },
# 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 Encode;
# require File::Glob;
#
# my %args = @_;
# my $word = $args{word} // "";
# my $handle_tilde = $args{handle_tilde} // 1;
# my $allow_dot = $args{allow_dot} // 1;
#
# my $result_prefix;
# my $starting_path = $args{starting_path} // '.';
# if ($handle_tilde && $word =~ s!\A(~[^/]*)/!!) {
# $result_prefix = "$1/";
# my @dir = File::Glob::bsd_glob($1);
# return [] unless @dir;
# $starting_path = Encode::decode('UTF-8', $dir[0]);
# } elsif ($allow_dot && $word =~ s!\A((?:\.\.?/+)+|/+)!!) {
# $starting_path = $1;
# $result_prefix = $1;
# $starting_path =~ s#/+\z## unless $starting_path =~ m!\A/!;
# }
#
# return [] if !$allow_dot &&
# $word =~ m!(?:\A|/)\.\.?(?:\z|/)!;
#
# my $list = sub {
# my ($path, $intdir, $isint) = @_;
# opendir my($dh), $path or return undef;
# my @res;
# for (sort readdir $dh) {
# next if ($_ eq '.' || $_ eq '..') && $intdir eq '';
# next if $isint && !(-d "$path/$_");
# push @res, Encode::decode('UTF-8', $_);
# }
# \@res;
# };
#
#
# my $filter;
# if ($args{filter} && !ref($args{filter})) {
# my @seqs = split /\s*\|\s*/, $args{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 ($args{filter} && ref($args{filter}) eq 'CODE') {
# $filter = $args{filter};
# }
#
# my $filter_fregex;
# if ($args{file_regex_filter}) {
# $filter_fregex = sub {
# my $name = shift;
# return 1 if -d $name;
# return 0 unless -f _;
# return 1 if $name =~ $args{file_regex_filter};
# 0;
# };
# }
#
# my $filter_fext;
# if ($args{file_ext_filter} && ref $args{file_ext_filter} eq 'Regexp') {
# $filter_fext = sub {
# my $name = shift;
# return 1 if -d $name;
# return 0 unless -f _;
# my $ext = $name =~ /\.(\w+)\z/ ? $1 : '';
# return 1 if $ext =~ $args{file_ext_filter};
# 0;
# };
# } elsif ($args{file_ext_filter} && ref $args{file_ext_filter} eq 'ARRAY') {
# $filter_fext = sub {
# my $name = shift;
# return 1 if -d $name;
# return 0 unless -f _;
# my $ext = $name =~ /\.(\w+)\z/ ? $1 : '';
# if ($Complete::Common::OPT_CI) {
# $ext = lc($ext);
# for my $e (@{ $args{file_ext_filter} }) {
# return 1 if $ext eq lc($e);
# }
# } else {
# for my $e (@{ $args{file_ext_filter} }) {
# return 1 if $ext eq $e;
# }
# }
# 0;
# };
# }
#
# my $filter_dir;
# if ($args{_dir}) {
# $filter_dir = sub { return 0 unless (-d $_[0]); 1 };
# }
#
# my $filter_xdir;
# if ($args{exclude_dir}) {
# $filter_xdir = sub { return 0 if (-d $_[0]); 1 };
# }
#
# my $final_filter = sub {
# my $name = shift;
# if ($filter_dir) { return 0 unless $filter_dir->($name) }
# if ($filter_xdir) { return 0 unless $filter_xdir->($name) }
# if ($filter) { return 0 unless $filter->($name) }
# if ($filter_fregex) { return 0 unless $filter_fregex->($name) }
# if ($filter_fext) { return 0 unless $filter_fext->($name) }
# 1;
# };
#
# Complete::Path::complete_path(
# word => $word,
# list_func => $list,
# is_dir_func => sub { -d $_[0] },
# filter_func => $final_filter,
# starting_path => $starting_path,
# result_prefix => $result_prefix,
# );
#}
#
#$SPEC{complete_dir} = do {
# my $spec = {%{ $SPEC{complete_file} }};
#
# $spec->{summary} = 'Complete directory from local filesystem '.
# '(wrapper for complete_dir() that only picks directories)';
# $spec->{args} = { %{$spec->{args}} };
# delete $spec->{args}{file_regex_filter};
# delete $spec->{args}{file_ext_filter};
# delete $spec->{args}{exclude_dir};
#
# $spec;
#};
#sub complete_dir {
# my %args = @_;
#
# complete_file(%args, _dir=>1);
#}
#
#1;
#
#__END__
#
### Complete/Getopt/Long.pm ###
#package Complete::Getopt::Long;
#
#our $DATE = '2017-01-13';
#our $VERSION = '0.46';
#
#use 5.010001;
#use strict;
#use warnings;
#
#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;
#
# if ($word =~ /\A\$/) {
# {
# my $compres = Complete::Env::complete_env(
# word=>$word);
# last unless @$compres;
# $fres = {words=>$compres, esc_mode=>'shellvar'};
# goto RETURN_RES;
# }
# }
#
# if ($word =~ m!\A~([^/]*)\z!) {
# {
# 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 ($word =~ m!\A(~[^/]*)/!) {
# $fres = {words=>Complete::File::complete_file(word=>$word),
# path_sep=>'/'};
# goto RETURN_RES;
# }
#
# require String::Wildcard::Bash;
# if (String::Wildcard::Bash::contains_wildcard($word)) {
# {
# my $compres = [glob("$word*")];
# last unless @$compres;
# for (@$compres) {
# $_ .= "/" if (-d $_);
# }
# $fres = {words=>$compres, path_sep=>'/'};
# goto RETURN_RES;
# }
# }
# $fres = {words=>Complete::File::complete_file(word=>$word),
# path_sep=>'/'};
# RETURN_RES:
# $fres;
#}
#
#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;
#}
#
#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 <pm: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 <pm: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 <pm: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 <pm: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 <pm: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 <pm: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";
# 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;
#
#
# 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'";
# next if $res->{is_arg};
# $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,
# parsed => $res,
# };
# }
# }
# }
# my @optnames = sort keys %opts;
#
# my %seen_opts;
#
#
# my @expects;
#
# my $i = -1;
# my $argpos = 0;
#
# WORD:
# while (1) {
# last WORD if ++$i >= @words;
# my $word = $words[$i];
#
# 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-/) {
#
# SHORT_OPTS:
# {
# last unless $opts{"-".substr($word,1,1)};
#
# last unless $bundling;
#
# my $j = $i;
# my $rest = substr($word, 1);
# my @inswords;
# my $encounter_equal_sign;
# EXPAND:
# while (1) {
# $rest =~ s/(.)// or last;
# my $opt = "-$1";
# my $opthash = $opts{$opt};
# unless ($opthash) {
# @inswords = ();
# $expects[$i]{short_only} = 0;
# $rest = $word;
# last EXPAND;
# }
# if ($opthash->{parsed}{max_vals}) {
# _mark_seen(\%seen_opts, $opt, \%opts);
#
# if ($i == $j) {
# $words[$i] = $opt;
# } else {
# push @inswords, $opt;
# $j++;
# }
#
# my $expand;
# if (length $rest) {
# $expand++;
# $expects[$j > $i ? $j+1 : $j+2]{do_complete_optname} = 0;
# $expects[$j > $i ? $j+1 : $j+2]{optval} = $opt;
# } else {
# $expects[$j > $i ? $j-1 : $j]{optname} = $opt;
# $expects[$j > $i ? $j-1 : $j]{comp_result} = [
# substr($word, 0, length($word)-length($rest))];
# }
#
# if ($rest =~ s/\A=//) {
# $encounter_equal_sign++;
# }
#
# if ($expand) {
# push @inswords, "=", $rest;
# $j+=2;
# }
# last EXPAND;
# }
# _mark_seen(\%seen_opts, $opt, \%opts);
# if ($i == $j) {
# $words[$i] = $opt;
# } else {
# push @inswords, $opt;
# }
# $j++;
# }
#
#
# my $prefix = $encounter_equal_sign ? '' :
# substr($word, 0, length($word)-length($rest));
# splice @words, $i+1, 0, @inswords;
# for (0..@inswords) {
# $expects[$i+$_]{prefix} = $prefix;
# $expects[$i+$_]{word} = $rest;
# }
# $cword += @inswords;
# $i += @inswords;
# $word = $words[$i];
# $expects[$i]{short_only} //= 1;
# }
#
# 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};
#
# if ($i+1 < @words && $words[$i+1] eq '=') {
# $i++;
# $expects[$i] = {separator=>1, optval=>$opt, word=>'', nth=>$nth};
# if (!$max_vals) { $min_vals = $max_vals = 1 }
# }
#
# for (1 .. $min_vals) {
# $i++;
# last WORD if $i >= @words;
# $expects[$i]{optval} = $opt;
# $expects[$i]{nth} = $nth;
# push @{ $parsed_opts{$opt} }, $words[$i];
# }
# for (1 .. $max_vals-$min_vals) {
# last if $i+$_ >= @words;
# last if $words[$i+$_] =~ /\A-/;
# $expects[$i+$_]{optval} = $opt;
# $expects[$i]{nth} = $nth;
# push @{ $parsed_opts{$opt} }, $words[$i+$_];
# }
# } else {
# $opt = undef;
# $expects[$i]{optname} = $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++;
# }
# }
#
# my $exp = $expects[$cword];
# my $word = $exp->{word} // $words[$cword];
#
#
# my @answers;
#
# {
# last if $word =~ /\A[^-]/;
# last unless exists $exp->{optname};
# last if defined($exp->{do_complete_optname}) &&
# !$exp->{do_complete_optname};
# if ($exp->{comp_result}) {
# push @answers, $exp->{comp_result};
# last;
# }
# my $opt = $exp->{optname};
# my @o;
# for (@optnames) {
# 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;
# }
# }
# next if $seen_opts{$_} && !$repeatable && (
# (!$opt || $opt ne $_) ||
# (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, $_;
# }
# }
# my $compres = Complete::Util::complete_array_elem(
# array => \@o, word => $word);
# push @answers, $compres;
# if (!exists($exp->{optval}) && !exists($exp->{arg})) {
# $fres = {words=>$compres, esc_mode=>'option'};
# goto RETURN_RES;
# }
# }
#
# {
# 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) {
# $compres = $comp->(%compargs);
# Complete::Util::modify_answer(answer=>$compres, prefix=>$exp->{prefix})
# if defined $exp->{prefix};
# }
# if (!$compres || !$comp) {
# $compres = _default_completion(%compargs);
# Complete::Util::modify_answer(answer=>$compres, prefix=>$exp->{prefix})
# if defined $exp->{prefix};
# }
# push @answers, $compres;
# }
#
# {
# 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,
# );
# my $compres = $comp->(%compargs) if $comp;
# if (!defined $compres) {
# $compres = _default_completion(%compargs);
# }
# push @answers, $compres;
# }
#
# $fres = Complete::Util::combine_answers(@answers) // [];
#
# RETURN_RES:
# $fres;
#}
#
#1;
#
#__END__
#
### Complete/Path.pm ###
#package Complete::Path;
#
#our $DATE = '2017-07-03';
#our $VERSION = '0.24';
#
#use 5.010001;
#use strict;
#use warnings;
#
#use Complete::Common qw(:all);
#
#our $COMPLETE_PATH_TRACE = $ENV{COMPLETE_PATH_TRACE} // 0;
#
#require Exporter;
#our @ISA = qw(Exporter);
#our @EXPORT_OK = qw(
# complete_path
# );
#
#sub _dig_leaf {
# my ($p, $list_func, $is_dir_func, $filter_func, $path_sep) = @_;
# my $num_dirs;
# my $listres = $list_func->($p, '', 0);
# return $p unless ref($listres) eq 'ARRAY' && @$listres;
# my @candidates;
# L1:
# for my $e (@$listres) {
# my $p2 = $p =~ m!\Q$path_sep\E\z! ? "$p$e" : "$p$path_sep$e";
# {
# local $_ = $p2;
# next L1 if $filter_func && !$filter_func->($p2);
# }
# push @candidates, $p2;
# }
# return $p unless @candidates == 1;
# my $p2 = $candidates[0];
# my $is_dir;
# if ($p2 =~ 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, $filter_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 => {
# %arg_word,
# 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 => '/',
# },
# },
# 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 $result_prefix = $args{result_prefix};
# my $starting_path = $args{starting_path} // '';
#
# my $ci = $Complete::Common::OPT_CI;
# my $word_mode = $Complete::Common::OPT_WORD_MODE;
# my $fuzzy = $Complete::Common::OPT_FUZZY;
# my $map_case = $Complete::Common::OPT_MAP_CASE;
# my $exp_im_path = $Complete::Common::OPT_EXP_IM_PATH;
# my $dig_leaf = $Complete::Common::OPT_DIG_LEAF;
#
# my $re_ends_with_path_sep = qr!\A\z|\Q$path_sep\E\z!;
#
# 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;
# }
#
# my $leaf = pop @intermediate_dirs;
# @intermediate_dirs = ('') if !@intermediate_dirs;
#
#
# 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) {
# @dirs = ($starting_path);
# } else {
# @dirs = @candidate_paths;
# }
#
# if ($i == $#intermediate_dirs && $intdir eq '') {
# @candidate_paths = @dirs;
# last;
# }
#
# my @new_candidate_paths;
# for my $dir (@dirs) {
# my $listres = $list_func->($dir, $intdir, 1);
# next unless $listres && @$listres;
# my $matches = Complete::Util::complete_array_elem(
# word => $intdir, array => $listres,
# );
# my $exact_matches = [grep {
# $_ eq $intdir || $_ eq $intdir_with_path_sep
# } @$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;
# }
#
# }
# 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) {
# my $listres = $list_func->($dir, $leaf, 0);
# next unless $listres && @$listres;
# my $matches = Complete::Util::complete_array_elem(
# word => $leaf, array => $listres,
# );
#
# L1:
# for my $e (@$matches) {
# my $p = $dir =~ $re_ends_with_path_sep ?
# "$dir$e" : "$dir$path_sep$e";
# {
# local $_ = $p;
# next L1 if $filter_func && !$filter_func->($p);
# }
#
# my $is_dir;
# if ($e =~ $re_ends_with_path_sep) {
# $is_dir = 1;
# } else {
# local $_ = $p;
# $is_dir = $is_dir_func->($p);
# }
#
# if ($is_dir && $dig_leaf) {
# {
# my $p2 = _dig_leaf($p, $list_func, $is_dir_func, $filter_func, $path_sep);
# last if $p2 eq $p;
# $p = $p2;
#
# if ($p =~ $re_ends_with_path_sep) {
# $is_dir = 1;
# } else {
# local $_ = $p;
# $is_dir = $is_dir_func->($p);
# }
# }
# }
#
# 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;
#
#__END__
#
### Complete/Tcsh.pm ###
#package Complete::Tcsh;
#
#our $DATE = '2015-09-09';
#our $VERSION = '0.02';
#
#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;
#
#__END__
#
### Complete/Util.pm ###
#package Complete::Util;
#
#our $DATE = '2017-07-03';
#our $VERSION = '0.59';
#
#use 5.010001;
#use strict;
#use warnings;
#use Log::ger;
#
#use Complete::Common qw(:all);
#
#use Exporter qw(import);
#our @EXPORT_OK = qw(
# hashify_answer
# arrayify_answer
# combine_answers
# modify_answer
# ununiquify_answer
# complete_array_elem
# complete_hash_key
# complete_comma_sep
# );
#
#our %SPEC;
#
#our $COMPLETE_UTIL_TRACE = $ENV{COMPLETE_UTIL_TRACE} // 0;
#
#$SPEC{':package'} = {
# v => 1.1,
# summary => 'General completion routine',
# description => <<'_',
#
#This package provides some generic completion routines that follow the
#<pm:Complete> convention. (If you are looking for bash/shell tab completion
#routines, take a look at the See Also section.) The main routine is
#`complete_array_elem` which tries to complete a word using choices from elements
#of supplied array. For example:
#
# complete_array_elem(word => "a", array => ["apple", "apricot", "banana"]);
#
#The routine will first try a simple substring prefix matching. If that fails,
#will try some other methods like word-mode, character-mode, or fuzzy matching.
#These methods can be disabled using settings.
#
#There are other utility routines e.g. for converting completion answer structure
#from hash to array/array to hash, combine or modify answer, etc. These routines
#are usually used by the other more specific or higher-level completion modules.
#
#_
#};
#
#$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,
# },
# },
# args_as => 'array',
# 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,
# },
# },
# args_as => 'array',
# 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;
#}
#
#our $code_editdist;
#our $editdist_flex;
#
#sub __editdist {
# my @a = split //, shift;
# my @b = split //, shift;
#
# 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];
#}
#
#my %complete_array_elem_args = (
# %arg_word,
# array => {
# schema => ['array*'=>{of=>'str*'}],
# req => 1,
# pos => 1,
# greedy => 1,
# },
# exclude => {
# schema => ['array*'],
# },
# replace_map => {
# schema => ['hash*', each_value=>['array*', of=>'str*']],
# description => <<'_',
#
#You can supply correction entries in this option. An example is when array if
#`['mount','unmount']` and `umount` is a popular "typo" for `unmount`. When
#someone already types `um` it cannot be completed into anything (even the
#current fuzzy mode will return *both* so it cannot complete immediately).
#
#One solution is to add replace_map `{'unmount'=>['umount']}`. This way, `umount`
#will be regarded the same as `unmount` and when user types `um` it can be
#completed unambiguously into `unmount`.
#
#_
# tags => ['experimental'],
# },
#);
#
#$SPEC{complete_array_elem} = {
# v => 1.1,
# summary => 'Complete from array',
# description => <<'_',
#
#Try to find completion from an array of strings. Will attempt several methods,
#from the cheapest and most discriminating to the most expensive and least
#discriminating: normal string prefix matching, word-mode matching (see
#`Complete::Common::OPT_WORD_MODE` for more details), char-mode matching (see
#`Complete::Common::OPT_CHAR_MODE` for more details), and fuzzy matching (see
#`Complete::Common::OPT_FUZZY` for more details).
#
#Will sort the resulting completion list, so you don't have to presort the array.
#
#_
# args => {
# %complete_array_elem_args,
# },
# result_naked => 1,
# result => {
# schema => 'array',
# },
#};
#sub complete_array_elem {
# my %args = @_;
#
# my $array0 = $args{array} or die "Please specify array";
# my $word = $args{word} // "";
#
# my $ci = $Complete::Common::OPT_CI;
# my $map_case = $Complete::Common::OPT_MAP_CASE;
# my $word_mode = $Complete::Common::OPT_WORD_MODE;
# my $char_mode = $Complete::Common::OPT_CHAR_MODE;
# my $fuzzy = $Complete::Common::OPT_FUZZY;
#
# log_trace("[computil] entering complete_array_elem(), word=<%s>", $word)
# if $COMPLETE_UTIL_TRACE;
#
# my $res;
#
# unless (@$array0) {
# $res = []; goto RETURN_RES;
# }
#
# my $wordn = $ci ? uc($word) : $word; $wordn =~ s/_/-/g if $map_case;
#
# my $excluden;
# if ($args{exclude}) {
# $excluden = {};
# for my $el (@{$args{exclude}}) {
# my $eln = $ci ? uc($el) : $el; $eln =~ s/_/-/g if $map_case;
# $excluden->{$eln} //= 1;
# }
# }
#
# my $rmapn;
# my $rev_rmapn;
# if (my $rmap = $args{replace_map}) {
# $rmapn = {};
# $rev_rmapn = {};
# for my $k (keys %$rmap) {
# my $kn = $ci ? uc($k) : $k; $kn =~ s/_/-/g if $map_case;
# my @vn;
# for my $v (@{ $rmap->{$k} }) {
# my $vn = $ci ? uc($v) : $v; $vn =~ s/_/-/g if $map_case;
# push @vn, $vn;
# $rev_rmapn->{$vn} //= $k;
# }
# $rmapn->{$kn} = \@vn;
# }
# }
#
# my @words;
# my @array ;
# my @arrayn;
#
# log_trace("[computil] Trying normal string-prefix matching ...") if $COMPLETE_UTIL_TRACE;
# for my $el (@$array0) {
# my $eln = $ci ? uc($el) : $el; $eln =~ s/_/-/g if $map_case;
# next if $excluden && $excluden->{$eln};
# push @array , $el;
# push @arrayn, $eln;
# push @words , $el if 0==index($eln, $wordn);
# if ($rmapn && $rmapn->{$eln}) {
# for my $vn (@{ $rmapn->{$eln} }) {
# push @array , $el;
# push @arrayn, $vn;
# push @words , $vn if 0==index($vn, $wordn);
# }
# }
# }
# log_trace("[computil] Result from normal string-prefix matching: %s", \@words) if @words && $COMPLETE_UTIL_TRACE;
#
# {
# last unless $word_mode && !@words;
# my @split_wordn = $wordn =~ /(\w+)/g;
# unshift @split_wordn, '' if $wordn =~ /\A\W/;
# last unless @split_wordn > 1;
# my $re = '\A';
# for my $i (0..$#split_wordn) {
# $re .= '(?:\W+\w+)*\W+' if $i;
# $re .= quotemeta($split_wordn[$i]).'\w*';
# }
# $re = qr/$re/;
# log_trace("[computil] Trying word-mode matching (re=%s) ...", $re) if $COMPLETE_UTIL_TRACE;
#
# for my $i (0..$#array) {
# my $match;
# {
# if ($arrayn[$i] =~ $re) {
# $match++;
# last;
# }
# my $tmp = $array[$i];
# if ($tmp =~ s/([a-z0-9_])([A-Z])/$1-$2/g) {
# $tmp = uc($tmp) if $ci; $tmp =~ s/_/-/g if $map_case;
# if ($tmp =~ $re) {
# $match++;
# last;
# }
# }
# }
# next unless $match;
# push @words, $array[$i];
# }
# log_trace("[computil] Result from word-mode matching: %s", \@words) if @words && $COMPLETE_UTIL_TRACE;
# }
#
# if ($char_mode && !@words && length($wordn) && length($wordn) <= 7) {
# my $re = join(".*", map {quotemeta} split(//, $wordn));
# $re = qr/$re/;
# log_trace("[computil] Trying char-mode matching (re=%s) ...", $re) if $COMPLETE_UTIL_TRACE;
# for my $i (0..$#array) {
# push @words, $array[$i] if $arrayn[$i] =~ $re;
# }
# log_trace("[computil] Result from char-mode matching: %s", \@words) if @words && $COMPLETE_UTIL_TRACE;
# }
#
# if ($fuzzy && !@words) {
# log_trace("[computil] Trying fuzzy matching ...") if $COMPLETE_UTIL_TRACE;
# $code_editdist //= do {
# my $env = $ENV{COMPLETE_UTIL_LEVENSHTEIN} // '';
# if ($env eq 'xs') {
# require Text::Levenshtein::XS;
# $editdist_flex = 0;
# \&Text::Levenshtein::XS::distance;
# } elsif ($env eq 'flexible') {
# require Text::Levenshtein::Flexible;
# $editdist_flex = 1;
# \&Text::Levenshtein::Flexible::levenshtein_l;
# } elsif ($env eq 'pp') {
# $editdist_flex = 0;
# \&__editdist;
# } elsif (eval { require Text::Levenshtein::Flexible; 1 }) {
# $editdist_flex = 1;
# \&Text::Levenshtein::Flexible::levenshtein_l;
# } else {
# $editdist_flex = 0;
# \&__editdist;
# }
# };
#
# my $factor = 1.3;
# my $x = -1;
# my $y = 1;
#
#
# my %editdists;
# ELEM:
# for my $i (0..$#array) {
# my $eln = $arrayn[$i];
#
# for my $l (length($wordn)-$y .. length($wordn)+$y) {
# next if $l <= 0;
# my $chopped = substr($eln, 0, $l);
# my $maxd = __min(
# __min(length($chopped), length($word))/$factor,
# $fuzzy,
# );
# my $d;
# unless (defined $editdists{$chopped}) {
# if ($editdist_flex) {
# $d = $code_editdist->($wordn, $chopped, $maxd);
# next ELEM unless defined $d;
# } else {
# $d = $code_editdist->($wordn, $chopped);
# }
# $editdists{$chopped} = $d;
# } else {
# $d = $editdists{$chopped};
# }
# next unless $d <= $maxd;
# push @words, $array[$i];
# next ELEM;
# }
# }
# log_trace("[computil] Result from fuzzy matching: %s", \@words) if @words && $COMPLETE_UTIL_TRACE;
# }
#
# if ($rmapn && @words) {
# my @wordsn;
# for my $el (@words) {
# my $eln = $ci ? uc($el) : $el; $eln =~ s/_/-/g if $map_case;
# push @wordsn, $eln;
# }
# for my $i (0..$#words) {
# if (my $w = $rev_rmapn->{$wordsn[$i]}) {
# $words[$i] = $w;
# }
# }
# }
#
# $res =$ci ? [sort {lc($a) cmp lc($b)} @words] : [sort @words];
#
# RETURN_RES:
# log_trace("[computil] leaving complete_array_elem(), res=%s", $res)
# if $COMPLETE_UTIL_TRACE;
# $res;
#}
#
#$SPEC{complete_hash_key} = {
# v => 1.1,
# summary => 'Complete from hash keys',
# args => {
# %arg_word,
# hash => { schema=>['hash*'=>{}], req=>1 },
# },
# 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} // "";
#
# complete_array_elem(
# word=>$word, array=>[sort keys %$hash],
# );
#}
#
#my %complete_comma_sep_args = (
# %complete_array_elem_args,
# sep => {
# schema => 'str*',
# default => ',',
# },
# uniq => {
# summary => 'Whether list should contain unique elements',
# description => <<'_',
#
#When this option is set to true, if the formed list in the current word already
#contains an element, the element will not be offered again as completion answer.
#For example, if `elems` is `[1,2,3,4]` and `word` is `2,3,` then without `uniq`
#set to true the completion answer is:
#
# 2,3,1
# 2,3,2
# 2,3,3
# 2,3,4
#
#but with `uniq` set to true, the completion answer becomes:
#
# 2,3,1
# 2,3,4
#
#See also the `remaining` option for a more general mechanism of offering fewer
#elements.
#
#_
# schema => ['bool*', is=>1],
# },
# remaining => {
# schema => ['code*'],
# summary => 'What elements should remain for completion',
# description => <<'_',
#
#This is a more general mechanism if the `uniq` option does not suffice. Suppose
#you are offering completion for sorting fields. The elements are field names as
#well as field names prefixed with dash (`-`) to mean sorting with a reverse
#order. So for example `elems` is `["name","-name","age","-age"]`. When current
#word is `name`, it doesn't make sense to offer `name` nor `-name` again as the
#next sorting field. So we can set `remaining` to this code:
#
# sub {
# my ($seen_elems, $elems) = @_;
#
# my %seen;
# for (@$seen_elems) {
# (my $nodash = $_) =~ s/^-//;
# $seen{$nodash}++;
# }
#
# my @remaining;
# for (@$elems) {
# (my $nodash = $_) =~ s/^-//;
# push @remaining, $_ unless $seen{$nodash};
# }
#
# \@remaining;
# }
#
#As you can see above, the code is given `$seen_elems` and `$elems` as arguments
#and is expected to return remaining elements to offer.
#
#_
# tags => ['hidden-cli'],
# },
#);
#$complete_comma_sep_args{elems} = delete $complete_comma_sep_args{array};
#
#$SPEC{complete_comma_sep} = {
# v => 1.1,
# summary => 'Complete a comma-separated list string',
# args => {
# %complete_comma_sep_args,
# },
# result_naked => 1,
# result => {
# schema => 'array',
# },
#};
#sub complete_comma_sep {
# my %args = @_;
# my $word = delete $args{word} // "";
# my $sep = delete $args{sep} // ',';
# my $elems = delete $args{elems} or die "Please specify elems";
# my $uniq = delete $args{uniq};
# my $remaining = delete $args{remaining};
#
# my $ci = $Complete::Common::OPT_CI;
#
# my @mentioned_elems = split /\Q$sep\E/, $word, -1;
# my $cae_word = @mentioned_elems ? pop(@mentioned_elems) : '';
#
# my $remaining_elems;
# if ($remaining) {
# $remaining_elems = $remaining->(\@mentioned_elems, $elems);
# } elsif ($uniq) {
# my %mem;
# $remaining_elems = [];
# for (@mentioned_elems) {
# if ($ci) { $mem{lc $_}++ } else { $mem{$_}++ }
# }
# for (@$elems) {
# push @$remaining_elems, $_ unless ($ci ? $mem{lc $_} : $mem{$_});
# }
# } else {
# $remaining_elems = $elems;
# }
#
# my $cae_res = complete_array_elem(
# %args,
# word => $cae_word,
# array => $remaining_elems,
# );
#
# my $prefix = join($sep, @mentioned_elems);
# $prefix .= $sep if @mentioned_elems;
# $cae_res = [map { "$prefix$_" } @$cae_res];
#
# {
# last unless @$cae_res == 1;
# last if @$remaining_elems <= 1;
# $cae_res->[0] .= $sep;
# }
# $cae_res;
#}
#
#$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 <prog: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),
# complete_module(word=>$word),
# );
#
#But 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*']],
# 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->{$_};
# }
# }
# }
# }
#
# if ($final->{words}) {
# $final->{words} = [
# sort {
# (ref($a) ? $a->{word} : $a) cmp
# (ref($b) ? $b->{word} : $b);
# }
# @{ $final->{words} }];
# }
#
# $encounter_hash ? $final : $final->{words};
#}
#
#$SPEC{modify_answer} = {
# v => 1.1,
# summary => 'Modify answer (add prefix/suffix, etc)',
# args => {
# answer => {
# schema => ['any*', of=>['hash*','array*']],
# req => 1,
# pos => 0,
# },
# suffix => {
# schema => 'str*',
# },
# prefix => {
# schema => 'str*',
# },
# },
# result_naked => 1,
# result => {
# schema => 'undef',
# },
#};
#sub modify_answer {
# my %args = @_;
#
# my $answer = $args{answer};
# my $words = ref($answer) eq 'HASH' ? $answer->{words} : $answer;
#
# if (defined(my $prefix = $args{prefix})) {
# $_ = "$prefix$_" for @$words;
# }
# if (defined(my $suffix = $args{suffix})) {
# $_ = "$_$suffix" for @$words;
# }
# undef;
#}
#
#$SPEC{ununiquify_answer} = {
# v => 1.1,
# summary => 'If answer contains only one item, make it two',
# description => <<'_',
#
#For example, if answer is `["a"]`, then will make answer become `["a","a "]`.
#This will prevent shell from automatically adding space.
#
#_
# args => {
# answer => {
# schema => ['any*', of=>['hash*','array*']],
# req => 1,
# pos => 0,
# },
# },
# result_naked => 1,
# result => {
# schema => 'undef',
# },
#};
#sub ununiquify_answer {
# my %args = @_;
#
# my $answer = $args{answer};
# my $words = ref($answer) eq 'HASH' ? $answer->{words} : $answer;
#
# if (@$words == 1) {
# push @$words, "$words->[0] ";
# }
# undef;
#}
#
#1;
#
#__END__
#
### Data/Clean.pm ###
#package Data::Clean;
#
#our $DATE = '2017-07-10';
#our $VERSION = '0.49';
#
#use 5.010001;
#use strict;
#use warnings;
#use Log::ger;
#
#sub new {
# my ($class, %opts) = @_;
# my $self = bless {_opts=>\%opts}, $class;
# log_trace("Cleanser options: %s", \%opts);
#
# my $cd = $self->_generate_cleanser_code;
# for my $mod (keys %{ $cd->{modules} }) {
# (my $mod_pm = "$mod.pm") =~ s!::!/!g;
# require $mod_pm;
# }
# $self->{_cd} = $cd;
# $self->{_code} = eval $cd->{src};
# {
# last unless $cd->{clone_func} =~ /(.+)::(.+)/;
# (my $mod_pm = "$1.pm") =~ s!::!/!g;
# require $mod_pm;
# }
# die "Can't generate code: $@" if $@;
#
# $self;
#}
#
#sub command_call_method {
# my ($self, $cd, $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, $cd, $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, $cd, $args) = @_;
# return "{{var}} = {{var}} ? 1:0; \$ref = ''";
#}
#
#sub command_deref_scalar {
# my ($self, $cd, $args) = @_;
# return '{{var}} = ${ {{var}} }; $ref = ref({{var}})';
#}
#
#sub command_stringify {
# my ($self, $cd, $args) = @_;
# return '{{var}} = "{{var}}"; $ref = ""';
#}
#
#sub command_replace_with_ref {
# my ($self, $cd, $args) = @_;
# return '{{var}} = $ref; $ref = ""';
#}
#
#sub command_replace_with_str {
# require String::PerlQuote;
#
# my ($self, $cd, $args) = @_;
# return "{{var}} = ".String::PerlQuote::double_quote($args->[0]).'; $ref=""';
#}
#
#sub command_unbless {
# my ($self, $cd, $args) = @_;
#
# return join(
# "",
# 'my $reftype = Scalar::Util::reftype({{var}}); ',
# '{{var}} = $reftype eq "HASH" ? {%{ {{var}} }} :',
# ' $reftype eq "ARRAY" ? [@{ {{var}} }] :',
# ' $reftype eq "SCALAR" ? \(my $copy = ${ {{var}} }) :',
# ' $reftype eq "CODE" ? sub { goto &{ {{var}} } } :',
# '(die "Cannot unbless object with type $ref")',
# );
#}
#
#sub command_clone {
# my ($self, $cd, $args) = @_;
#
# my $limit = $args->[0] // 1;
# return join(
# "",
# "if (++\$ctr_circ <= $limit) { ",
# "{{var}} = $cd->{clone_func}({{var}}); redo ",
# "} else { ",
# "{{var}} = 'CIRCULAR'; \$ref = '' }",
# );
#}
#
#sub command_die {
# my ($self, $cd, $args) = @_;
# return "die";
#}
#
#sub _generate_cleanser_code {
# my $self = shift;
# my $opts = $self->{_opts};
#
# my $cd = {
# modules => {},
# clone_func => $self->{_opts}{'!clone_func'},
# code => '',
# };
#
# $cd->{modules}{'Scalar::Util'} //= 0;
#
# if (!$cd->{clone_func}) {
# if (eval { require Data::Clone; 1 }) {
# $cd->{clone_func} = 'Data::Clone::clone';
# } else {
# $cd->{clone_func} = 'Clone::PP::clone';
# }
# }
# {
# last unless $cd->{clone_func} =~ /(.+)::(.+)/;
# $cd->{modules}{$1} //= 0;
# }
#
# 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;
# 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);
# };
#
# 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($cd, \@args);
# $add_new_if->('$ref && $refs{ {{var}} }++', $act);
# }
#
# 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($cd, \@args);
# $add_if_ref->($on, $act);
# }
#
# 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($cd, \@args));
# }
#
# if ($opts->{'!recurse_obj'}) {
# $add_stmt->('stmt', 'my $reftype=Scalar::Util::reftype({{var}})//""');
# $add_new_if->('$reftype eq "ARRAY"', '$process_array->({{var}})');
# $add_if->('$reftype eq "HASH"' , '$process_hash->({{var}})');
# } else {
# $add_new_if_ref->("ARRAY", '$process_array->({{var}})');
# $add_if_ref->("HASH" , '$process_hash->({{var}})');
# }
#
# 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($cd, \@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_trace("Cleanser code:\n%s",
# $ENV{LINENUM} // 1 ?
# String::LineNumber::linenum($code) : $code);
# }
#
# $cd->{src} = $code;
#
# $cd;
#}
#
#sub clean_in_place {
# my ($self, $data) = @_;
#
# $self->{_code}->($data);
#}
#
#sub clone_and_clean {
# no strict 'refs';
#
# my ($self, $data) = @_;
# my $clone = &{$self->{_cd}{clone_func}}($data);
# $self->clean_in_place($clone);
#}
#
#1;
#
#__END__
#
### Data/Clean/FromJSON.pm ###
#package Data::Clean::FromJSON;
#
#our $DATE = '2017-01-15';
#our $VERSION = '0.38';
#
#use 5.010001;
#use strict;
#use warnings;
#
#use parent qw(Data::Clean);
#
#sub new {
# my ($class, %opts) = @_;
# $opts{"JSON::PP::Boolean"} //= ['one_or_zero'];
#
# $opts{"JSON::XS::Boolean"} //= ['one_or_zero'];
#
# $opts{"Cpanel::JSON::XS::Boolean"} //= ['one_or_zero'];
#
# $class->SUPER::new(%opts);
#}
#
#sub get_cleanser {
# my $class = shift;
# state $singleton = $class->new;
# $singleton;
#}
#
#1;
#
#__END__
#
### Data/Clean/JSON.pm ###
#package Data::Clean::JSON;
#
#our $DATE = '2017-01-15';
#our $VERSION = '0.38';
#
#use 5.010001;
#use strict;
#use warnings;
#
#use parent qw(Data::Clean);
#
#use Exporter qw(import);
#our @EXPORT_OK = qw(
# clean_json_in_place
# clone_and_clean_json
# );
#
#sub new {
# my ($class, %opts) = @_;
# $opts{DateTime} //= [call_method => 'epoch'];
# $opts{'Time::Moment'} //= [call_method => 'epoch'];
# $opts{'Math::BigInt'} //= [call_method => 'bstr'];
# $opts{Regexp} //= ['stringify'];
# $opts{version} //= ['stringify'];
#
# $opts{SCALAR} //= ['deref_scalar'];
# $opts{-ref} //= ['replace_with_ref'];
# $opts{-circular} //= ['clone'];
# $opts{-obj} //= ['unbless'];
#
# $opts{'!recurse_obj'} //= 1;
# $class->SUPER::new(%opts);
#}
#
#sub get_cleanser {
# my $class = shift;
# state $singleton = $class->new;
# $singleton;
#}
#
#sub clean_json_in_place {
# __PACKAGE__->get_cleanser->clean_in_place(@_);
#}
#
#sub clone_and_clean_json {
# __PACKAGE__->get_cleanser->clone_and_clean(@_);
#}
#
#1;
#
#__END__
#
### Data/Dmp.pm ###
#package Data::Dmp;
#
#our $DATE = '2017-01-30';
#our $VERSION = '0.23';
#
#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);
#
#our %_seen_refaddrs;
#our %_subscripts;
#our @_fixups;
#
#our $OPT_PERL_VERSION = "5.010";
#our $OPT_REMOVE_PRAGMAS = 0;
#our $OPT_DEPARSE = 1;
#our $OPT_STRINGIFY_NUMBERS = 0;
#
#my %esc = (
# "\a" => "\\a",
# "\b" => "\\b",
# "\t" => "\\t",
# "\n" => "\\n",
# "\f" => "\\f",
# "\r" => "\\r",
# "\e" => "\\e",
#);
#
#sub _double_quote {
# local($_) = $_[0];
#
# s/([\\\"\@\$])/\\$1/g;
# return qq("$_") unless /[^\040-\176]/;
#
# s/([\a\b\t\n\f\r\e])/$esc{$1}/g;
#
# 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("$_");
#}
#
#sub _dump_code {
# my $code = shift;
#
# state $deparse = do {
# require B::Deparse;
# B::Deparse->new("-l");
# };
#
# my $res = $deparse->coderef2text($code);
#
# my ($res_before_first_line, $res_after_first_line) =
# $res =~ /(.+?)^(#line .+)/ms;
#
# if ($OPT_REMOVE_PRAGMAS) {
# $res_before_first_line = "{";
# } elsif ($OPT_PERL_VERSION < 5.016) {
# $res_before_first_line =~ s/no feature ':all';/no feature;/m;
# }
# $res_after_first_line =~ s/^#line .+//gm;
#
# $res = "sub" . $res_before_first_line . $res_after_first_line;
# $res =~ s/^\s+//gm;
# $res =~ s/\n+//g;
# $res =~ s/;\}\z/}/;
# $res;
#}
#
#sub _quote_key {
# $_[0] =~ /\A-?[A-Za-z_][A-Za-z0-9_]*\z/ ||
# $_[0] =~ /\A-?[1-9][0-9]{0,8}\z/ ? $_[0] : _double_quote($_[0]);
#}
#
#sub _dump {
# my ($val, $subscript) = @_;
#
# my $ref = ref($val);
# if ($ref eq '') {
# if (!defined($val)) {
# return "undef";
# } elsif (looks_like_number($val) && !$OPT_STRINGIFY_NUMBERS &&
# $val eq $val+0 &&
# $val !~ /\A-?(?:inf(?:inity)?|nan)\z/i
# ) {
# 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 = _quote_key($_);
# 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') {
# $res = $OPT_DEPARSE ? _dump_code($val) : 'sub{"DUMMY"}';
# } 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 wantarray() || @_ > 1 ? @_ : $_[0];
# } else {
# return $res;
# }
#}
#
#sub dd { local $_is_dd=1; _dd_or_dmp(@_) }
#sub dmp { goto &_dd_or_dmp }
#
#1;
#
#__END__
#
### Data/ModeMerge.pm ###
#package Data::ModeMerge;
#
#our $DATE = '2016-07-22';
#our $VERSION = '0.35';
#
#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");
#
#has modes => (is => 'rw', default => sub { {} });
#
#has combine_rules => (is => 'rw');
#
#has path => (is => "rw", default => sub { [] });
#has errors => (is => "rw", default => sub { [] });
#has mem => (is => "rw", default => sub { {} });
#has cur_mem_key => (is => "rw");
#
#sub _in($$) {
# state $load_dmp = do { require Data::Dmp };
# my ($self, $needle, $haystack) = @_;
# return 0 unless defined($needle);
# my $r1 = ref($needle);
# my $f1 = $r1 ? Data::Dmp::dmp($needle) : undef;
# for (@$haystack) {
# my $r2 = ref($_);
# next if $r1 xor $r2;
# return 1 if $r2 && $f1 eq Data::Dmp::dmp($_);
# return 1 if !$r2 && $needle eq $_;
# }
# 0;
#}
#
#sub BUILD {
# require Data::ModeMerge::Config;
#
# my ($self, $args) = @_;
#
# if ($self->config) {
# 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({
# 'ADD+ADD' => ['ADD' , 'ADD' ],
# 'ADD+DELETE' => ['DELETE' , 'DELETE'],
# 'ADD+NORMAL' => ['NORMAL' , 'NORMAL'],
# 'ADD+SUBTRACT' => ['SUBTRACT', 'ADD' ],
#
# 'CONCAT+CONCAT' => ['CONCAT' , 'CONCAT'],
# 'CONCAT+DELETE' => ['DELETE' , 'DELETE'],
# 'CONCAT+NORMAL' => ['NORMAL' , 'NORMAL'],
#
# '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+DELETE' => ['DELETE' , 'DELETE' ],
# '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,
# };
#}
#
#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} }) {
# 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;
#
# 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 }
#
# 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;
# }
# if ($memkey) {
# if (exists $self->mem->{$memkey}) {
# $self->_process_todo;
# if (defined $self->mem->{$memkey}{res}) {
# return @{ $self->mem->{$memkey}{res} };
# } else {
# return ($key, undef, undef, 1);
# }
# } else {
# $self->mem->{$memkey} = {res=>undef, todo=>[]};
# $self->cur_mem_key($memkey);
# my ($newkey, $res, $backup) = $mh->$meth($key, $l, $r);
# $self->mem->{$memkey}{res} = [$newkey, $res, $backup];
# $self->_process_todo;
# return ($newkey, $res, $backup);
# }
# } else {
# $self->_process_todo;
# return $mh->$meth($key, $l, $r);
# }
#}
#
#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];
# }
# $res;
#}
#
#1;
#
#__END__
#
### Data/ModeMerge/Config.pm ###
#package Data::ModeMerge::Config;
#
#our $DATE = '2016-07-22';
#our $VERSION = '0.35';
#
#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');
#
#sub _config_config {
# state $a = [qw/
# wanted_path
# options_key
# allow_override
# disallow_override
# /];
#}
#
#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;
#
#__END__
#
### Data/ModeMerge/Mode/ADD.pm ###
#package Data::ModeMerge::Mode::ADD;
#
#our $DATE = '2016-07-22';
#our $VERSION = '0.35';
#
#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;
#
#__END__
#
### Data/ModeMerge/Mode/Base.pm ###
#package Data::ModeMerge::Mode::Base;
#
#our $DATE = '2016-07-22';
#our $VERSION = '0.35';
#
#use 5.010;
#use strict;
#use warnings;
#
#
#use Mo qw(build default);
#
#
#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) {
# $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;
# push @{ $mm->mem->{ $mm->cur_mem_key }{todo} }, sub {
# my ($subnewkey, $subres, $subbackup) = @_;
# $res[$i] = $subres;
# }
# } else {
# push @res, $subres;
# }
# } 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;
#}
#
#sub _gen_left {
# my ($self, $l, $mode, $esub, $ep, $ip, $epr, $ipr) = @_;
# my $mm = $self->merger;
# my $c = $mm->config;
#
#
# 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->{$_}];
# }
# }
#
# $hl;
#}
#
#sub _gen_right {
# my ($self, $r, $mode, $esub, $ep, $ip, $epr, $ipr) = @_;
# my $mm = $self->merger;
# my $c = $mm->config;
#
#
# 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->{$_}}
# }
# }
# $hr;
#}
#
#sub _merge_gen {
# my ($self, $hl, $hr, $mode, $em, $im, $emr, $imr) = @_;
# my $mm = $self->merger;
# my $c = $mm->config;
#
#
# 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} };
# push @o, map { [$_, $hr->{$k}{$_}] } sort { $m{$b} <=> $m{$a} } keys %m;
# }
# my $final_mode;
# my $is_circular;
# my $v;
# 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")))) {
# my $meth = $hl->{$k} ? "merge_left_only" : "merge_right_only";
# my ($subnewkey, $v, $subbackup, $is_circular, $newmode) = $mh->$meth($k, $o[$i][1]);
# 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;
# };
# 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;
# }
# push @{ $mm->mem->{ $mm->cur_mem_key }{todo} }, sub {
# my ($subnewkey, $subres, $subbackup) = @_;
# my $final_mode = $m->[1];
# $res->{$k} = [$m->[1], $subres];
# if ($c->readd_prefix) {
# $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 };
# ($res, $backup);
#}
#
#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;
#
# 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);
#
# 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 };
#
#
# $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;
# 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;
# }
#
# 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;
# }
# }
#
# my $hl = $self->_gen_left ($l, $mode, sub {defined($ok) ? $_[0] ne $ok : 1}, $ep, $ip, $epr, $ipr);
# return if @{ $mm->errors };
#
# my $hr = $self->_gen_right($r, $mode, sub {defined($ok) ? $_[0] ne $ok : 1}, $ep, $ip, $epr, $ipr);
# return if @{ $mm->errors };
#
#
# 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;
# }
# }
#
# my ($res, $backup) = $self->_merge_gen($hl, $hr, $mode, $em, $im, $emr, $imr);
# return if @{ $mm->errors };
#
#
# 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});
# }
# }
#
# if ($config_replaced) {
# $mm->config($orig_c);
# }
#
# ($key, $res, $backup);
#}
#
#1;
#
#__END__
#
### Data/ModeMerge/Mode/CONCAT.pm ###
#package Data::ModeMerge::Mode::CONCAT;
#
#our $DATE = '2016-07-22';
#our $VERSION = '0.35';
#
#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;
#
#__END__
#
### Data/ModeMerge/Mode/DELETE.pm ###
#package Data::ModeMerge::Mode::DELETE;
#
#our $DATE = '2016-07-22';
#our $VERSION = '0.35';
#
#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/^!/ }
#
#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;
#
#__END__
#
### Data/ModeMerge/Mode/KEEP.pm ###
#package Data::ModeMerge::Mode::KEEP;
#
#our $DATE = '2016-07-22';
#our $VERSION = '0.35';
#
#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;
#
#__END__
#
### Data/ModeMerge/Mode/NORMAL.pm ###
#package Data::ModeMerge::Mode::NORMAL;
#
#our $DATE = '2016-07-22';
#our $VERSION = '0.35';
#
#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;
#
#__END__
#
### Data/ModeMerge/Mode/SUBTRACT.pm ###
#package Data::ModeMerge::Mode::SUBTRACT;
#
#our $DATE = '2016-07-22';
#our $VERSION = '0.35';
#
#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;
#
#__END__
#
### Data/Sah/Normalize.pm ###
#package Data::Sah::Normalize;
#
#use 5.010001;
#use strict;
#use warnings;
#
#our $DATE = '2015-09-06';
#our $VERSION = '0.04';
#
#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};
#
# my $expr;
# if ($c =~ s/=\z//) {
# $expr++;
# 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'";
# 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";
# }
# }
#
# 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};
#
#
# $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 {
# 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 = {};
# }
#
# 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;
#
#__END__
#
### Data/Sah/Resolve.pm ###
#package Data::Sah::Resolve;
#
#our $DATE = '2017-04-19';
#our $VERSION = '0.007';
#
#use 5.010001;
#use strict;
#use warnings;
#
#use Exporter qw(import);
#our @EXPORT_OK = qw(resolve_schema);
#
#sub _resolve {
# my ($opts, $type, $clsets, $seen) = @_;
#
# die "Recursive schema definition: ".join(" -> ", @$seen, $type)
# if grep { $type eq $_ } @$seen;
# push @$seen, $type;
#
# (my $typemod_pm = "Data/Sah/Type/$type.pm") =~ s!::!/!g;
# eval { require $typemod_pm; 1 };
# my $err = $@;
# return [$type, $clsets] unless $err;
# die "Can't check whether $type is a builtin Sah type: $err"
# unless $err =~ /\ACan't locate/;
#
# my $schmod = "Sah::Schema::$type";
# (my $schmod_pm = "$schmod.pm") =~ s!::!/!g;
# eval { require $schmod_pm; 1 };
# die "Not a known built-in Sah type '$type' (can't locate ".
# "Data::Sah::Type::$type) and not a known schema name '$type' ($@)"
# if $@;
# no strict 'refs';
# my $sch2 = ${"$schmod\::schema"};
# die "BUG: Schema module $schmod doesn't contain \$schema" unless $sch2;
# unshift @$clsets, $sch2->[1];
# _resolve($opts, $sch2->[0], $clsets, $seen);
#}
#
#sub resolve_schema {
# my $opts = ref($_[0]) eq 'HASH' ? shift : {};
# my $sch = shift;
#
# unless ($opts->{schema_is_normalized}) {
# require Data::Sah::Normalize;
# $sch = Data::Sah::Normalize::normalize_schema($sch);
# }
# $opts->{merge_clause_sets} //= 1;
#
# my $seen = [];
# my $res = _resolve($opts, $sch->[0], keys(%{$sch->[1]}) ? [$sch->[1]] : [], $seen);
#
# MERGE:
# {
# last unless $opts->{merge_clause_sets};
# last if @{ $res->[1] } < 2;
#
# my @clsets = (shift @{ $res->[1] });
# for my $clset (@{ $res->[1] }) {
# my $has_merge_mode_keys;
# for (keys %$clset) {
# if (/\Amerge\./) {
# $has_merge_mode_keys = 1;
# last;
# }
# }
# if ($has_merge_mode_keys) {
# state $merger = do {
# 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;
# };
# my $merge_res = $merger->merge($clsets[-1], $clset);
# unless ($merge_res->{success}) {
# die "Can't merge clause set: $merge_res->{error}";
# }
# $clsets[-1] = $merge_res->{result};
# } else {
# push @clsets, $clset;
# }
# }
#
# $res->[1] = \@clsets;
# }
#
# $res->[2] = $seen if $opts->{return_intermediates};
#
# $res;
#}
#
#1;
#
#__END__
#
### Data/Sah/Util/Type.pm ###
#package Data::Sah::Util::Type;
#
#our $DATE = '2016-12-09';
#our $VERSION = '0.46';
#
#use 5.010001;
#use strict;
#use warnings;
#
#require Exporter;
#our @ISA = qw(Exporter);
#our @EXPORT_OK = qw(get_type is_type is_simple is_numeric is_collection is_ref);
#
#our $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},
# date => {scalar=>1, numeric=>0, ref=>0},
# duration => {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);
#}
#
#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_type {
# my ($sch, $opts) = @_;
# $opts //= {};
#
# my $type = get_type($sch) or return undef;
# my $tmeta = $type_metas->{$type} or return undef;
# $type;
#}
#
#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;
#
#__END__
#
### Function/Fallback/CoreOrPP.pm ###
#package Function::Fallback::CoreOrPP;
#
#use 5.010001;
#use strict;
#use warnings;
#
#our $VERSION = '0.08';
#
#our $USE_NONCORE_XS_FIRST = 1;
#
#require Exporter;
#our @ISA = qw(Exporter);
#our @EXPORT_OK = qw(
# clone
# clone_list
# 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 clone_list {
# map { clone($_) } @_;
#}
#
#sub _unbless_fallback {
# my $ref = shift;
#
# my $r = ref($ref);
# return $ref unless $r;
#
# 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} );
# } elsif ($r3 eq 'CODE') {
# return sub { goto &$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;
#
#__END__
#
### Getopt/Long/Negate/EN.pm ###
#package Getopt::Long::Negate::EN;
#
#our $DATE = '2016-03-01';
#our $VERSION = '0.05';
#
#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 =~ /\Ahas([_-].+)/ ) { return ("hasnt$1") }
# elsif ($word =~ /\Ahave([_-].+)/ ) { return ("havent$1") }
# elsif ($word =~ /\Ahasnt([_-].+)/ ) { return ("has$1") }
# elsif ($word =~ /\Ahavent([_-].+)/ ) { return ("have$1") }
#
# elsif ($word =~ /\Acan([_-].+)/ ) { return ("cant$1") }
# elsif ($word =~ /\Acant([_-].+)/ ) { return ("can$1") }
#
# elsif ($word =~ /\Aenabled([_-].+)/ ) { return ("disabled$1") }
# elsif ($word =~ /\Adisabled([_-].+)/) { return ("enabled$1") }
# elsif ($word =~ /\Aenable([_-].+)/ ) { return ("disable$1") }
# elsif ($word =~ /\Adisable([_-].+)/) { return ("enable$1") }
#
# elsif ($word =~ /\Aallowed([_-].+)/ ) { return ("disallowed$1") }
# elsif ($word =~ /\Adisallowed([_-].+)/) { return ("allowed$1") }
# elsif ($word =~ /\Aallow([_-].+)/ ) { return ("disallow$1") }
# elsif ($word =~ /\Adisallow([_-].+)/) { return ("allow$1") }
#
# elsif ($word =~ /\Ano[_-](.+)/ ) { return ($1) }
#
# else {
# return ("no-$word", "no$word");
# }
#}
#
#1;
#
#__END__
#
### Getopt/Long/Util.pm ###
#package Getopt::Long::Util;
#
#our $DATE = '2017-08-10';
#our $VERSION = '0.890';
#
#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
# gen_getopt_long_spec_from_getopt_std_spec
# );
#
#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:
#
#* `is_arg` (if true, then option specification is the special `<>` for argument
# callback)
#* `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=>''},
# },
# ],
#};
#sub parse_getopt_long_opt_spec {
# my $optspec = shift;
# return {is_arg=>1, dash_prefix=>'', opts=>[]}
# if $optspec eq '<>';
# $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;
#}
#
#$SPEC{humanize_getopt_long_opt_spec} = {
# v => 1.1,
# description => <<'_',
#
#Convert <pm: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";
#
# return "argument" if $parse->{is_arg};
#
# 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*',
# pos => 0,
# cmdline_aliases => {f=>{}},
# },
# string => {
# summary => 'String to be checked',
# schema => 'buf*',
# },
# include_noexec => {
# summary => 'Include scripts that do not have +x mode bit set',
# schema => 'bool*',
# default => 1,
# },
# },
# args_rels => {
# 'req_one' => ['filename', 'string'],
# },
#};
#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 %extrameta;
#
# 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;
# }
# 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>;
# }
# close $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;
# }
#
#
#
# for (split /^/, $str) {
# if (/^\s*(use|require)\s+(Getopt::Long(?:::Complete|::Less|::EvenLess)?)(\s|;|$)/) {
# $yesno = 1;
# $extrameta{'func.module'} = $2;
# last DETECT;
# }
# }
#
# $reason = "Can't find any statement requiring Getopt::Long(?::Complete|::Less|::EvenLess)? module";
# }
#
# [200, "OK", $yesno, {"func.reason"=>$reason, %extrameta}];
#}
#
#$SPEC{gen_getopt_long_spec_from_getopt_std_spec} = {
# v => 1.1,
# summary => 'Generate Getopt::Long spec from Getopt::Std spec',
# args => {
# spec => {
# summary => 'Getopt::Std spec string',
# schema => 'str*',
# req => 1,
# pos => 0,
# },
# is_getopt => {
# summary => 'Whether to assume spec is for getopt() or getopts()',
# description => <<'_',
#
#By default spec is assumed to be for getopts() instead of getopt(). This means
#that for a spec like `abc:`, `a` and `b` don't take argument while `c` does. But
#if `is_getopt` is true, the meaning of `:` is reversed: `a` and `b` take
#arguments while `c` doesn't.
#
#_
# schema => 'bool',
# },
# },
# result_naked => 1,
# result => {
# schema => 'hash*',
# },
#};
#sub gen_getopt_long_spec_from_getopt_std_spec {
# my %args = @_;
#
# my $is_getopt = $args{is_getopt};
# my $spec = {};
#
# while ($args{spec} =~ /(.)(:?)/g) {
# $spec->{$1 . ($is_getopt ? ($2 ? "" : "=s") : ($2 ? "=s" : ""))} =
# sub {};
# }
#
# $spec;
#}
#
#1;
#
#__END__
#
### Lingua/EN/PluralToSingular.pm ###
#package Lingua::EN::PluralToSingular;
#use warnings;
#use strict;
#require Exporter;
#our @ISA = qw(Exporter);
#our @EXPORT_OK = qw/to_singular is_plural/;
#our $VERSION = '0.19';
#
#
#
#
#my %irregular = (qw/
# analyses analysis
# brethren brother
# children child
# corpora corpus
# craftsmen craftsman
# crises crisis
# criteria criterion
# curricula curriculum
# feet foot
# fungi fungus
# geese goose
# genera genus
# gentlemen gentleman
# indices index
# lice louse
# matrices matrix
# memoranda memorandum
# men man
# mice mouse
# monies money
# neuroses neurosis
# nuclei nucleus
# oases oasis
# oxen ox
# pence penny
# people person
# phenomena phenomenon
# quanta quantum
# strata stratum
# teeth tooth
# testes testis
# these this
# theses thesis
# those that
# women woman
#/);
#
#
#
#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
#/);
#
#
#my %plural = (
# 'menus' => 'menu',
# 'buses' => 'bus',
# %ves,
# %irregular,
#);
#
#
#my @no_change = qw/
# deer
# ides
# fish
# means
# offspring
# series
# sheep
# species
# /;
#
#@plural{@no_change} = @no_change;
#
#
#
#
#my @not_plural = (qw/
#Aries
#Charles
#Gonzales
#Hades
#Hercules
#Hermes
#Holmes
#Hughes
#Ives
#Jacques
#James
#Keyes
#Mercedes
#Naples
#Oates
#Raines
#Texas
#athletics
#bogus
#bus
#cactus
#cannabis
#caries
#chaos
#citrus
#clothes
#corps
#corpus
#devious
#dias
#facies
#famous
#hippopotamus
#homunculus
#iris
#lens
#mathematics
#metaphysics
#metropolis
#mews
#minus
#miscellaneous
#molasses
#mrs
#narcissus
#news
#octopus
#ourselves
#papyrus
#perhaps
#physics
#platypus
#plus
#previous
#pus
#rabies
#scabies
#sometimes
#stylus
#themselves
#this
#thus
#various
#yes
#nucleus
#synchronous
#/);
#
#my %not_plural;
#
#@not_plural{@not_plural} = (1) x @not_plural;
#
#
#
#
#
#my @oes = (qw/
#canoes
#does
#foes
#gumshoes
#hoes
#horseshoes
#oboes
#shoes
#snowshoes
#throes
#toes
#/);
#
#my %oes;
#
#@oes{@oes} = (1) x @oes;
#
#
#
#
#
#
#
#my @ies = (qw/
#Aussies
#Valkryies
#aunties
#bogies
#brownies
#calories
#charlies
#coolies
#coteries
#curies
#cuties
#dies
#genies
#goalies
#kilocalories
#lies
#magpies
#menagerie
#movies
#neckties
#pies
#porkpies
#prairies
#quickies
#reveries
#rookies
#sorties
#stogies
#talkies
#ties
#zombies
#/);
#
#my %ies;
#
#@ies{@ies} = (1) x @ies;
#
#
#my @ses = (qw/
#automates
#bases
#cases
#causes
#ceases
#closes
#cornflakes
#creases
#databases
#deceases
#flakes
#horses
#increases
#mates
#parses
#purposes
#races
#releases
#tenses
#/);
#
#my %ses;
#@ses{@ses} = (1) x @ses;
#
#my $es_re = qr/([^aeiou]s|ch|sh)es$/;
#
#
#my @i_to_us = (qw/
#abaci
#abaculi
#acanthi
#acini
#alumni
#anthocauli
#bacilli
#baetuli
#cacti
#calculi
#calli
#catheti
#emboli
#emeriti
#esophagi
#foci
#foeti
#fumuli
#fungi
#gonococci
#hippopotami
#homunculi
#incubi
#loci
#macrofungi
#macronuclei
#naevi
#nuclei
#obeli
#octopi
#oeconomi
#oesophagi
#panni
#periœci
#phocomeli
#phoeti
#platypi
#polypi
#precunei
#radii
#rhombi
#sarcophagi
#solidi
#stimuli
#succubi
#syllabi
#thesauri
#thrombi
#tori
#trophi
#uteri
#viri
#virii
#xiphopagi
#zygomatici
#/);
#
#my %i_to_us;
#@i_to_us{@i_to_us} = (1) x @i_to_us;
#
#my @i_to_o = (qw/
# alveoli
# ghetti
# manifesti
# ostinati
# pianissimi
# scenarii
# stiletti
# torsi
#/);
#
#my %i_to_o;
#@i_to_o{@i_to_o} = (1) x @i_to_o;
#
#
#my %i_to_other = (
# improvisatori => 'improvisatore',
# rhinoceri => 'rhinoceros',
# scaloppini => 'scaloppine'
#);
#
#
#sub to_singular
#{
# my ($word) = @_;
# my $singular = $word;
# if (! $not_plural{$word}) {
# if ($plural{$word}) {
# $singular = $plural{$word};
# }
# elsif ($word =~ /s$/) {
# if ($word =~ /'s$/) {
# ;
# }
# elsif (length ($word) <= 2) {
# ;
# }
# elsif ($word =~ /ss$/) {
# ;
# }
# elsif ($word =~ /sis$/) {
# ;
# }
# elsif ($word =~ /ies$/) {
# if ($ies{$word}) {
# $singular =~ s/ies$/ie/;
# }
# else {
# $singular =~ s/ies$/y/;
# }
# }
# elsif ($word =~ /oes$/) {
# if ($oes{$word}) {
# $singular =~ s/oes$/oe/;
# }
# else {
# $singular =~ s/oes$/o/;
# }
# }
# elsif ($word =~ /xes$/) {
# $singular =~ s/xes$/x/;
# }
# elsif ($word =~ /ses$/) {
# if ($ses{$word}) {
# $singular =~ s/ses$/se/;
# }
# else {
# $singular =~ s/ses$/s/;
# }
# }
# elsif ($word =~ $es_re) {
# $singular =~ s/$es_re/$1/;
# }
# else {
# $singular =~ s/s$//;
# }
# }
# elsif ($word =~ /i$/) {
# if ($i_to_us{$word}) {
# $singular =~ s/i$/us/;
# }
# elsif ($i_to_o{$word}) {
# $singular =~ s/i$/o/;
# }
# if ($i_to_other{$word}) {
# $singular = $i_to_other{$word};
# }
# }
#
# }
# 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;
### Log/ger.pm ###
#package Log::ger;
#
#our $DATE = '2017-08-03';
#our $VERSION = '0.023';
#
#
#our $re_addr = qr/\(0x([0-9a-f]+)/o;
#
#our %Levels = (
# fatal => 10,
# error => 20,
# warn => 30,
# info => 40,
# debug => 50,
# trace => 60,
#);
#
#our %Level_Aliases = (
# off => 0,
# warning => 30,
#);
#
#our $Current_Level = 30;
#
#our $Caller_Depth_Offset = 0;
#
#our $_logger_is_null;
#
#our $_dumper;
#
#our %Global_Hooks;
#
#
#our %Package_Targets;
#our %Per_Package_Hooks;
#
#our %Hash_Targets;
#our %Per_Hash_Hooks;
#
#our %Object_Targets;
#our %Per_Object_Hooks;
#
#my $sub0 = sub {0};
#my $sub1 = sub {1};
#my $default_null_routines;
#
#sub install_routines {
# my ($target, $target_arg, $routines) = @_;
#
# if ($target eq 'package') {
# for my $r (@$routines) {
# my ($code, $name, $lnum, $type) = @$r;
# next unless $type =~ /_sub\z/;
# *{"$target_arg\::$name"} = $code;
# }
# } elsif ($target eq 'object') {
# my $pkg = ref $target_arg;
# for my $r (@$routines) {
# my ($code, $name, $lnum, $type) = @$r;
# next unless $type =~ /_method\z/;
# *{"$pkg\::$name"} = $code;
# }
# } elsif ($target eq 'hash') {
# for my $r (@$routines) {
# my ($code, $name, $lnum, $type) = @$r;
# next unless $type =~ /_sub\z/;
# $target_arg->{$name} = $code;
# }
# }
#}
#
#sub add_target {
# my ($target, $target_arg, $args, $replace) = @_;
# $replace = 1 unless defined $replace;
#
# if ($target eq 'package') {
# unless ($replace) { return if $Package_Targets{$target_arg} }
# $Package_Targets{$target_arg} = $args;
# } elsif ($target eq 'object') {
# my ($addr) = "$target_arg" =~ $re_addr;
# unless ($replace) { return if $Object_Targets{$addr} }
# $Object_Targets{$addr} = [$target_arg, $args];
# } elsif ($target eq 'hash') {
# my ($addr) = "$target_arg" =~ $re_addr;
# unless ($replace) { return if $Hash_Targets{$addr} }
# $Hash_Targets{$addr} = [$target_arg, $args];
# }
#}
#
#sub _set_default_null_routines {
# $default_null_routines ||= [
# (map {(
# [$sub0, "log_$_", $Levels{$_}, 'log_sub'],
# [$Levels{$_} > $Current_Level ? $sub0 : $sub1, "log_is_$_", $Levels{$_}, 'is_sub'],
# [$sub0, $_, $Levels{$_}, 'log_method'],
# [$Levels{$_} > $Current_Level ? $sub0 : $sub1, "is_$_", $Levels{$_}, 'is_method'],
# )} keys %Levels),
# ];
#}
#
#sub get_logger {
# my ($package, %args) = @_;
#
# my $caller = caller(0);
# $args{category} = $caller if !defined($args{category});
# my $obj = []; $obj =~ $re_addr;
# my $pkg = "Log::ger::Obj$1"; bless $obj, $pkg;
# add_target(object => $obj, \%args);
# if (keys %Global_Hooks) {
# require Log::ger::Heavy;
# init_target(object => $obj, \%args);
# } else {
# _set_default_null_routines();
# install_routines(object => $obj, $default_null_routines);
# }
# $obj;
#}
#
#sub import {
# my ($package, %args) = @_;
#
# my $caller = caller(0);
# $args{category} = $caller if !defined($args{category});
# add_target(package => $caller, \%args);
# if (keys %Global_Hooks) {
# require Log::ger::Heavy;
# init_target(package => $caller, \%args);
# } else {
# _set_default_null_routines();
# install_routines(package => $caller, $default_null_routines);
# }
#}
#
#1;
#
#__END__
#
### Log/ger/Format.pm ###
#package Log::ger::Format;
#
#our $DATE = '2017-08-03';
#our $VERSION = '0.023';
#
#use parent qw(Log::ger::Plugin);
#
#sub _import_sets_for_current_package { 1 }
#
#1;
#
#__END__
#
### Log/ger/Format/None.pm ###
#package Log::ger::Format::None;
#
#our $DATE = '2017-08-03';
#our $VERSION = '0.023';
#
#sub get_hooks {
# return {
# create_formatter => [
# __PACKAGE__, 50,
# sub {
# [sub {shift}];
# }],
# };
#}
#
#1;
#
#__END__
#
### Log/ger/Heavy.pm ###
#package Log::ger::Heavy;
#
#our $DATE = '2017-08-03';
#our $VERSION = '0.023';
#
#
#package
# Log::ger;
#
#
#our %Default_Hooks = (
# create_formatter => [
# [__PACKAGE__, 90,
# sub {
# my %args = @_;
#
# my $formatter = sub {
# return $_[0] if @_ < 2;
# my $fmt = shift;
# my @args;
# for (@_) {
# if (!defined($_)) {
# push @args, '<undef>';
# } elsif (ref $_) {
# require Log::ger::Util unless $_dumper;
# push @args, Log::ger::Util::_dump($_);
# } else {
# push @args, $_;
# }
# }
# sprintf $fmt, @args;
# };
# [$formatter];
# }],
# ],
#
# create_layouter => [],
#
# create_routine_names => [
# [__PACKAGE__, 90,
# sub {
# my %args = @_;
#
# my $levels = [keys %Levels];
#
# return [{
# log_subs => [map { ["log_$_", $_] } @$levels],
# is_subs => [map { ["log_is_$_", $_] } @$levels],
# log_methods => [map { ["$_", $_] } @$levels],
# is_methods => [map { ["is_$_", $_] } @$levels],
# }, 1];
# }],
# ],
#
# create_log_routine => [
# [__PACKAGE__, 10,
# sub {
# my %args = @_;
# my $level = $args{level};
# if (defined($level) && (
# $Current_Level < $level ||
# @{ $Global_Hooks{create_log_routine} } == 1)
# ) {
# $_logger_is_null = 1;
# return [sub {0}];
# }
# [undef];
# }],
# ],
#
# create_logml_routine => [],
#
# create_is_routine => [
# [__PACKAGE__, 90,
# sub {
# my %args = @_;
# my $level = $args{level};
# [sub { $Current_Level >= $level }];
# }],
# ],
#
# before_install_routines => [],
#
# after_install_routines => [],
#);
#
#for my $phase (keys %Default_Hooks) {
# $Global_Hooks{$phase} = [@{ $Default_Hooks{$phase} }];
#}
#
#sub run_hooks {
# my ($phase, $hook_args, $flow_control,
# $target, $target_arg) = @_;
#
# $Global_Hooks{$phase} or die "Unknown phase '$phase'";
# my @hooks = @{ $Global_Hooks{$phase} };
#
# if ($target eq 'package') {
# unshift @hooks, @{ $Per_Package_Hooks{$target_arg}{$phase} || [] };
# } elsif ($target eq 'hash') {
# my ($addr) = "$target_arg" =~ $re_addr;
# unshift @hooks, @{ $Per_Hash_Hooks{$addr}{$phase} || [] };
# } elsif ($target eq 'object') {
# my ($addr) = "$target_arg" =~ $re_addr;
# unshift @hooks, @{ $Per_Object_Hooks{$addr}{$phase} || [] };
# }
#
# my $res;
# for my $hook (sort {$a->[1] <=> $b->[1]} @hooks) {
# my $hook_res = $hook->[2]->(%$hook_args);
# if (defined $hook_res->[0]) {
# $res = $hook_res->[0];
# if (ref $flow_control eq 'CODE') {
# last if $flow_control->($hook, $hook_res);
# } else {
# last if $flow_control;
# }
# }
# last if $hook_res->[1];
# }
# return $res;
#}
#
#sub init_target {
# my ($target, $target_arg, $init_args) = @_;
#
# my %hook_args = (
# target => $target,
# target_arg => $target_arg,
# init_args => $init_args,
# );
#
# my %formatters;
# run_hooks(
# 'create_formatter', \%hook_args,
# sub {
# my ($hook, $hook_res) = @_;
# my ($formatter, $flow_control, $fmtname) = @$hook_res;
# $fmtname = 'default' if !defined($fmtname);
# $formatters{$fmtname} ||= $formatter;
# $flow_control;
# },
# $target, $target_arg);
#
# my $layouter =
# run_hooks('create_layouter', \%hook_args, 1, $target, $target_arg);
#
# my $routine_names = {};
# run_hooks(
# 'create_routine_names', \%hook_args,
# sub {
# my ($hook, $hook_res) = @_;
# my ($rn, $flow_control) = @$hook_res;
# $rn or return;
# for (keys %$rn) {
# push @{ $routine_names->{$_} }, @{ $rn->{$_} };
# }
# $flow_control;
# },
# $target, $target_arg);
#
# my @routines;
# my $object = $target eq 'object';
#
# CREATE_LOG_ROUTINES:
# {
# my @rn;
# if ($target eq 'package') {
# push @rn, @{ $routine_names->{log_subs} || [] };
# push @rn, @{ $routine_names->{logml_subs} || [] };
# } else {
# push @rn, @{ $routine_names->{log_methods} || [] };
# push @rn, @{ $routine_names->{logml_methods} || [] };
# }
# my $mllogger0;
# for my $rn (@rn) {
# my ($rname, $lname, $fmtname) = @$rn;
# my $lnum; $lnum = $Levels{$lname} if defined $lname;
# my $routine_name_is_ml = !defined($lname);
# $fmtname = 'default' if !defined($fmtname);
#
# my $logger;
# my ($logger0, $logger0_is_ml);
# $_logger_is_null = 0;
# for my $phase (qw/create_logml_routine create_log_routine/) {
# local $hook_args{name} = $rname;
# local $hook_args{level} = $lnum;
# local $hook_args{str_level} = $lname;
# $logger0_is_ml = $phase eq 'create_logml_routine';
# if ($mllogger0) {
# $logger0 = $mllogger0;
# last;
# }
# $logger0 = run_hooks(
# $phase, \%hook_args, 1, $target, $target_arg)
# or next;
# if ($logger0_is_ml) {
# $mllogger0 = $logger0;
# }
# last;
# }
# unless ($logger0) {
# $_logger_is_null = 1;
# $logger0 = sub {0};
# }
#
# require Log::ger::Util if !$logger0_is_ml && $routine_name_is_ml;
#
# {
# if ($_logger_is_null) {
# $logger = $logger0;
# last;
# }
#
# my $formatter = $formatters{$fmtname}
# or die "Formatter named '$fmtname' not available";
# if ($formatter) {
# if ($layouter) {
# if ($logger0_is_ml) {
# if ($routine_name_is_ml) {
# if ($object) { $logger = sub { shift; my $lnum=shift; my $lname = Log::ger::Util::string_level($lnum);
# $logger0->($init_args, $lnum, $layouter->($formatter->(@_), $init_args, $lnum, $lname)) };
# } else { $logger = sub { my $lnum=shift; my $lname = Log::ger::Util::string_level($lnum);
# $logger0->($init_args, $lnum, $layouter->($formatter->(@_), $init_args, $lnum, $lname)) }; }
# } else {
# if ($object) { $logger = sub { shift; $logger0->($init_args, $lnum, $layouter->($formatter->(@_), $init_args, $lnum, $lname)) };
# } else { $logger = sub { $logger0->($init_args, $lnum, $layouter->($formatter->(@_), $init_args, $lnum, $lname)) }; }
# }
# } else {
# if ($routine_name_is_ml) {
# if ($object) { $logger = sub { shift; return 0 if Log::ger::Util::numeric_level(shift) > $Current_Level;
# $logger0->($init_args, $layouter->($formatter->(@_), $init_args, $lnum, $lname)) };
# } else { $logger = sub { return 0 if Log::ger::Util::numeric_level(shift) > $Current_Level;
# $logger0->($init_args, $layouter->($formatter->(@_), $init_args, $lnum, $lname)) }; }
# } else {
# if ($object) { $logger = sub { shift; $logger0->($init_args, $layouter->($formatter->(@_), $init_args, $lnum, $lname)) };
# } else { $logger = sub { $logger0->($init_args, $layouter->($formatter->(@_), $init_args, $lnum, $lname)) }; }
# }
# }
# } else {
# if ($logger0_is_ml) {
# if ($routine_name_is_ml) {
# if ($object) { $logger = sub { shift; my $lnum=shift; $logger0->($init_args, $lnum, $formatter->(@_) ) };
# } else { $logger = sub { my $lnum=shift; $logger0->($init_args, $lnum, $formatter->(@_) ) }; }
# } else {
# if ($object) { $logger = sub { shift; $logger0->($init_args, $lnum, $formatter->(@_) ) };
# } else { $logger = sub { $logger0->($init_args, $lnum, $formatter->(@_) ) }; }
# }
# } else {
# if ($routine_name_is_ml) {
# if ($object) { $logger = sub { shift; return 0 if Log::ger::Util::numeric_level(shift) > $Current_Level;
# $logger0->($init_args, $formatter->(@_) ) };
# } else { $logger = sub { return 0 if Log::ger::Util::numeric_level(shift) > $Current_Level;
# $logger0->($init_args, $formatter->(@_) ) }; }
# } else {
# if ($object) { $logger = sub { shift; $logger0->($init_args, $formatter->(@_) ) };
# } else { $logger = sub { $logger0->($init_args, $formatter->(@_) ) }; }
# }
# }
# }
# } else {
# {
# if ($logger0_is_ml) {
# if ($routine_name_is_ml) {
# if ($object) { $logger = sub { shift; my $lnum=shift; $logger0->($init_args, $lnum, @_ ) };
# } else { $logger = sub { my $lnum=shift; $logger0->($init_args, $lnum, @_ ) }; }
# } else {
# if ($object) { $logger = sub { shift; $logger0->($init_args, $lnum, @_ ) };
# } else { $logger = sub { $logger0->($init_args, $lnum, @_ ) }; }
# }
# } else {
# if ($routine_name_is_ml) {
# if ($object) { $logger = sub { shift; return 0 if Log::ger::Util::numeric_level(shift) > $Current_Level;
# $logger0->($init_args, @_ ) };
# } else { $logger = sub { return 0 if Log::ger::Util::numeric_level(shift) > $Current_Level;
# $logger0->($init_args, @_ ) }; }
# } else {
# if ($object) { $logger = sub { shift; $logger0->($init_args, @_ ) };
# } else { $logger = sub { $logger0->($init_args, @_ ) }; }
# }
# }
# }
# }
# }
# L1:
# my $type = $routine_name_is_ml ?
# ($object ? 'logml_method' : 'logml_sub') :
# ($object ? 'log_method' : 'log_sub');
# push @routines, [$logger, $rname, $lnum, $type];
# }
# }
# CREATE_IS_ROUTINES:
# {
# my @rn;
# my $type;
# if ($target eq 'package') {
# push @rn, @{ $routine_names->{is_subs} || [] };
# $type = 'is_sub';
# } else {
# push @rn, @{ $routine_names->{is_methods} || [] };
# $type = 'is_method';
# }
# for my $rn (@rn) {
# my ($rname, $lname) = @$rn;
# my $lnum = $Levels{$lname};
#
# local $hook_args{name} = $rname;
# local $hook_args{level} = $lnum;
# local $hook_args{str_level} = $lname;
#
# my $code_is =
# run_hooks('create_is_routine', \%hook_args, 1,
# $target, $target_arg);
# next unless $code_is;
# push @routines, [$code_is, $rname, $lnum, $type];
# }
# }
#
# {
# local $hook_args{routines} = \@routines;
# local $hook_args{formatters} = \%formatters;
# local $hook_args{layouter} = $layouter;
# run_hooks('before_install_routines', \%hook_args, 0,
# $target, $target_arg);
# }
#
# install_routines($target, $target_arg, \@routines);
#
# {
# local $hook_args{routines} = \@routines;
# run_hooks('after_install_routines', \%hook_args, 0,
# $target, $target_arg);
# }
#}
#
#1;
#
#__END__
#
### Log/ger/Layout.pm ###
#package Log::ger::Layout;
#
#our $DATE = '2017-08-03';
#our $VERSION = '0.023';
#
#use parent qw(Log::ger::Plugin);
#
#sub _replace_package_regex { qr/\ALog::ger::Layout::/ }
#
#1;
#
#__END__
#
### Log/ger/Output.pm ###
#package Log::ger::Output;
#
#our $DATE = '2017-08-03';
#our $VERSION = '0.023';
#
#use parent 'Log::ger::Plugin';
#
#sub _replace_package_regex { qr/\ALog::ger::Output::/ }
#
#1;
#
#__END__
#
### Log/ger/Output/Array.pm ###
#package Log::ger::Output::Array;
#
#our $DATE = '2017-08-03';
#our $VERSION = '0.023';
#
#use strict;
#use warnings;
#
#sub get_hooks {
# my %conf = @_;
#
# $conf{array} or die "Please specify array";
#
# return {
# create_log_routine => [
# __PACKAGE__, 50,
# sub {
# my %args = @_;
#
# my $logger = sub {
# my ($ctx, $msg) = @_;
# push @{$conf{array}}, $msg;
# };
# [$logger];
# }],
# };
#}
#
#1;
#
#__END__
#
### Log/ger/Output/ArrayML.pm ###
#package Log::ger::Output::ArrayML;
#
#our $DATE = '2017-08-03';
#our $VERSION = '0.023';
#
#use strict;
#use warnings;
#
#use Log::ger::Util;
#
#sub get_hooks {
# my %conf = @_;
#
# $conf{array} or die "Please specify array";
#
# return {
# create_logml_routine => [
# __PACKAGE__, 50,
# sub {
# my %args = @_;
# my $logger = sub {
# my $level = Log::ger::Util::numeric_level($_[1]);
# return if $level > $Log::ger::Current_Level;
# push @{$conf{array}}, $_[2];
# };
# [$logger];
# }],
# };
#}
#
#1;
#
#__END__
#
### Log/ger/Output/Null.pm ###
#package Log::ger::Output::Null;
#
#our $DATE = '2017-08-03';
#our $VERSION = '0.023';
#
#sub get_hooks {
# return {
# create_log_routine => [
# __PACKAGE__, 50,
# sub {
# $Log::ger::_logger_is_null = 1;
# [sub {0}];
# }],
# };
#}
#
#1;
#
#__END__
#
### Log/ger/Output/String.pm ###
#package Log::ger::Output::String;
#
#our $DATE = '2017-08-03';
#our $VERSION = '0.023';
#
#use strict;
#use warnings;
#
#sub get_hooks {
# my %conf = @_;
#
# $conf{string} or die "Please specify string";
#
# my $formatter = $conf{formatter};
# my $append_newline = $conf{append_newline};
# $append_newline = 1 unless defined $append_newline;
#
# return {
# create_log_routine => [
# __PACKAGE__, 50,
# sub {
# my %args = @_;
# my $level = $args{level};
# my $logger = sub {
# my $msg = $_[1];
# if ($formatter) {
# $msg = $formatter->($msg);
# }
# ${ $conf{string} } .= $msg;
# ${ $conf{string} } .= "\n"
# unless !$append_newline || $msg =~ /\R\z/;
# };
# [$logger];
# }],
# };
#}
#
#1;
#
#__END__
#
### Log/ger/Plugin.pm ###
#package Log::ger::Plugin;
#
#our $DATE = '2017-08-03';
#our $VERSION = '0.023';
#
#use strict;
#use warnings;
#
#use Log::ger::Util;
#
#sub set {
# my $pkg = shift;
#
# my %args;
# if (ref $_[0] eq 'HASH') {
# %args = %{shift()};
# } else {
# %args = (name => shift, conf => {@_});
# }
#
# $args{prefix} ||= $pkg . '::';
# $args{replace_package_regex} = $pkg->_replace_package_regex;
# Log::ger::Util::set_plugin(%args);
#}
#
#sub set_for_current_package {
# my $pkg = shift;
#
# my %args;
# if (ref $_[0] eq 'HASH') {
# %args = %{shift()};
# } else {
# %args = (name => shift, conf => {@_});
# }
#
# my $caller = caller(0);
# $args{target} = 'package';
# $args{target_arg} = $caller;
#
# set($pkg, \%args);
#}
#
#sub _import_sets_for_current_package { 0 }
#
#sub _replace_package_regex { undef }
#
#sub import {
# if (@_ > 1) {
# if ($_[0]->_import_sets_for_current_package) {
# goto &set_for_current_package;
# } else {
# goto &set;
# }
# }
#}
#
#1;
#
#__END__
#
### Log/ger/Plugin/MultilevelLog.pm ###
#package Log::ger::Plugin::MultilevelLog;
#
#our $DATE = '2017-08-03';
#our $VERSION = '0.023';
#
#use strict;
#use warnings;
#
#use Log::ger::Util;
#
#sub get_hooks {
# my %conf = @_;
#
# return {
# create_routine_names => [
# __PACKAGE__, 50,
# sub {
# return [{
# logml_subs => [[$conf{sub_name} || 'log', undef]],
# logml_methods => [[$conf{method_name} || 'log', undef]],
# }];
# },
# ],
# };
#}
#
#1;
#
#__END__
#
### Log/ger/Util.pm ###
#package Log::ger::Util;
#
#our $DATE = '2017-08-03';
#our $VERSION = '0.023';
#
#use strict;
#use warnings;
#
#require Log::ger;
#require Log::ger::Heavy;
#
#sub _dump {
# unless ($Log::ger::_dumper) {
# eval {
# no warnings 'once';
# require Data::Dmp;
# $Data::Dmp::OPT_REMOVE_PRAGMAS = 1;
# 1;
# };
# if ($@) {
# no warnings 'once';
# require Data::Dumper;
# $Log::ger::_dumper = sub {
# local $Data::Dumper::Terse = 1;
# local $Data::Dumper::Indent = 0;
# local $Data::Dumper::Useqq = 1;
# local $Data::Dumper::Deparse = 1;
# local $Data::Dumper::Quotekeys = 0;
# local $Data::Dumper::Sortkeys = 1;
# local $Data::Dumper::Trailingcomma = 1;
# Data::Dumper::Dumper($_[0]);
# };
# } else {
# $Log::ger::_dumper = sub { Data::Dmp::dmp($_[0]) };
# }
# }
# $Log::ger::_dumper->($_[0]);
#}
#
#sub numeric_level {
# my $level = shift;
# return $level if $level =~ /\A\d+\z/;
# return $Log::ger::Levels{$level}
# if defined $Log::ger::Levels{$level};
# return $Log::ger::Level_Aliases{$level}
# if defined $Log::ger::Level_Aliases{$level};
# die "Unknown level '$level'";
#}
#
#sub string_level {
# my $level = shift;
# return $level if defined $Log::ger::Levels{$level};
# $level = $Log::ger::Level_Aliases{$level}
# if defined $Log::ger::Level_Aliases{$level};
# for (keys %Log::ger::Levels) {
# my $v = $Log::ger::Levels{$_};
# return $_ if $v == $level;
# }
# die "Unknown level '$level'";
#}
#
#sub set_level {
# no warnings 'once';
# $Log::ger::Current_Level = numeric_level(shift);
# reinit_all_targets();
#}
#
#sub _action_on_hooks {
# no warnings 'once';
#
# my ($action, $target, $target_arg, $phase) = splice @_, 0, 4;
#
# my $hooks = $Log::ger::Global_Hooks{$phase} or die "Unknown phase '$phase'";
# if ($target eq 'package') {
# $hooks = ($Log::ger::Per_Package_Hooks{$target_arg}{$phase} ||= []);
# } elsif ($target eq 'object') {
# my ($addr) = $target_arg =~ $Log::ger::re_addr;
# $hooks = ($Log::ger::Per_Object_Hooks{$addr}{$phase} ||= []);
# } elsif ($target eq 'hash') {
# my ($addr) = $target_arg =~ $Log::ger::re_addr;
# $hooks = ($Log::ger::Per_Hash_Hooks{$addr}{$phase} ||= []);
# }
#
# if ($action eq 'add') {
# my $hook = shift;
# unshift @$hooks, $hook;
# } elsif ($action eq 'remove') {
# my $code = shift;
# for my $i (reverse 0..$#{$hooks}) {
# splice @$hooks, $i, 1 if $code->($hooks->[$i]);
# }
# } elsif ($action eq 'reset') {
# my $saved = [@$hooks];
# splice @$hooks, 0, scalar(@$hooks),
# @{ $Log::ger::Default_Hooks{$phase} };
# return $saved;
# } elsif ($action eq 'empty') {
# my $saved = [@$hooks];
# splice @$hooks, 0;
# return $saved;
# } elsif ($action eq 'save') {
# return [@$hooks];
# } elsif ($action eq 'restore') {
# my $saved = shift;
# splice @$hooks, 0, scalar(@$hooks), @$saved;
# return $saved;
# }
#}
#
#sub add_hook {
# my ($phase, $hook) = @_;
# _action_on_hooks('add', '', undef, $phase, $hook);
#}
#
#sub add_per_target_hook {
# my ($target, $target_arg, $phase, $hook) = @_;
# _action_on_hooks('add', $target, $target_arg, $phase, $hook);
#}
#
#sub remove_hook {
# my ($phase, $code) = @_;
# _action_on_hooks('remove', '', undef, $phase, $code);
#}
#
#sub remove_per_target_hook {
# my ($target, $target_arg, $phase, $code) = @_;
# _action_on_hooks('remove', $target, $target_arg, $phase, $code);
#}
#
#sub reset_hooks {
# my ($phase) = @_;
# _action_on_hooks('reset', '', undef, $phase);
#}
#
#sub reset_per_target_hooks {
# my ($target, $target_arg, $phase) = @_;
# _action_on_hooks('reset', $target, $target_arg, $phase);
#}
#
#sub empty_hooks {
# my ($phase) = @_;
# _action_on_hooks('empty', '', undef, $phase);
#}
#
#sub empty_per_target_hooks {
# my ($target, $target_arg, $phase) = @_;
# _action_on_hooks('empty', $target, $target_arg, $phase);
#}
#
#sub save_hooks {
# my ($phase) = @_;
# _action_on_hooks('save', '', undef, $phase);
#}
#
#sub save_per_target_hooks {
# my ($target, $target_arg, $phase) = @_;
# _action_on_hooks('save', $target, $target_arg, $phase);
#}
#
#sub restore_hooks {
# my ($phase, $saved) = @_;
# _action_on_hooks('restore', '', undef, $phase, $saved);
#}
#
#sub restore_per_target_hooks {
# my ($target, $target_arg, $phase, $saved) = @_;
# _action_on_hooks('restore', $target, $target_arg, $phase, $saved);
#}
#
#sub reinit_target {
# my ($target, $target_arg) = @_;
#
# Log::ger::add_target($target, $target_arg, {}, 0);
#
# if ($target eq 'package') {
# my $init_args = $Log::ger::Package_Targets{$target_arg};
# Log::ger::init_target(package => $target_arg, $init_args);
# } elsif ($target eq 'object') {
# my ($obj_addr) = $target_arg =~ $Log::ger::re_addr
# or die "Invalid object '$target_arg': not a reference";
# my $v = $Log::ger::Object_Targets{$obj_addr}
# or die "Unknown object target '$target_arg'";
# Log::ger::init_target(object => $v->[0], $v->[1]);
# } elsif ($target eq 'hash') {
# my ($hash_addr) = $target_arg =~ $Log::ger::re_addr
# or die "Invalid hashref '$target_arg': not a reference";
# my $v = $Log::ger::Hash_Targets{$hash_addr}
# or die "Unknown hash target '$target_arg'";
# Log::ger::init_target(hash => $v->[0], $v->[1]);
# } else {
# die "Unknown target '$target'";
# }
#}
#
#sub reinit_all_targets {
# for my $pkg (keys %Log::ger::Package_Targets) {
# Log::ger::init_target(
# package => $pkg, $Log::ger::Package_Targets{$pkg});
# }
# for my $k (keys %Log::ger::Object_Targets) {
# my ($obj, $init_args) = @{ $Log::ger::Object_Targets{$k} };
# Log::ger::init_target(object => $obj, $init_args);
# }
# for my $k (keys %Log::ger::Hash_Targets) {
# my ($hash, $init_args) = @{ $Log::ger::Hash_Targets{$k} };
# Log::ger::init_target(hash => $hash, $init_args);
# }
#}
#
#sub set_plugin {
# my %args = @_;
#
# my $hooks;
# if ($args{hooks}) {
# $hooks = $args{hooks};
# } else {
# no strict 'refs';
# my $prefix = $args{prefix} || 'Log::ger::Plugin::';
# my $mod = $args{name};
# $mod = $prefix . $mod unless index($mod, $prefix) == 0;
# (my $mod_pm = "$mod.pm") =~ s!::!/!g;
# require $mod_pm;
# $hooks = &{"$mod\::get_hooks"}(%{ $args{conf} || {} });
# }
#
# {
# last unless $args{replace_package_regex};
# my $all_hooks;
# if (!$args{target}) {
# $all_hooks = \%Log::ger::Global_Hooks;
# } elsif ($args{target} eq 'package') {
# $all_hooks = $Log::ger::Per_Package_Hooks{ $args{target_arg} };
# } elsif ($args{target} eq 'object') {
# my ($addr) = $args{target_arg} =~ $Log::ger::re_addr;
# $all_hooks = $Log::ger::Per_Object_Hooks{$addr};
# } elsif ($args{target} eq 'hash') {
# my ($addr) = $args{target_arg} =~ $Log::ger::re_addr;
# $all_hooks = $Log::ger::Per_Hash_Hooks{$addr};
# }
# last unless $all_hooks;
# for my $phase (keys %$all_hooks) {
# my $hooks = $all_hooks->{$phase};
# for my $i (reverse 0..$#{$hooks}) {
# splice @$hooks, $i, 1
# if $hooks->[$i][0] =~ $args{replace_package_regex};
# }
# }
# }
#
# for my $phase (keys %$hooks) {
# my $hook = $hooks->{$phase};
# if (defined $args{target}) {
# add_per_target_hook(
# $args{target}, $args{target_arg}, $phase, $hook);
# } else {
# add_hook($phase, $hook);
# }
# }
#
# my $reinit = $args{reinit};
# $reinit = 1 unless defined $reinit;
# if ($reinit) {
# if (defined $args{target}) {
# reinit_target($args{target}, $args{target_arg});
# } else {
# reinit_all_targets();
# }
# }
#}
#
#1;
#
#__END__
#
### Mo.pm ###
#package Mo;
#$Mo::VERSION = '0.40';
#$VERSION='0.40';
#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 ###
#
#use strict;
#use warnings;
#package Mo::Golf;
#
#our $VERSION='0.40';
#
#use PPI;
#
#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/;
# return 1 if $prev->isa( tok 'Word' ) and $next->isa( tok 'Operator' ) and $next->content =~ /^\W/;
# return 1 if $prev->isa( tok 'Symbol' ) and $next->isa( tok 'Operator' ) and $next->content =~ /^\W/;
#
# return 1 if $prev->isa( tok 'Operator' ) and $next->isa( tok 'Quote::Single' ) and $next->content =~ /^\W/;
# return 1 if $prev->isa( tok 'Operator' ) and $next->isa( tok 'Quote::Double' ) and $next->content =~ /^\W/;
# return 1 if $prev->isa( tok 'Operator' ) and $next->isa( tok 'Symbol' ) and $next->content =~ /^\W/;
# return 1 if $prev->isa( tok 'Operator' ) and $next->isa( tok 'Structure' ) and $next->content =~ /^\W/;
#
# return 1 if $prev->isa( tok 'Word' ) and $next->isa( tok 'Symbol' );
# return 1 if $prev->isa( tok 'Word' ) and $next->isa( tok 'Structure' );
# return 1 if $prev->isa( tok 'Word' ) and $next->isa( tok 'Quote::Double' );
# return 1 if $prev->isa( tok 'Symbol' ) and $next->isa( tok 'Structure' );
# return 1 if $prev->isa( tok 'ArrayIndex' ) and $next->isa( tok 'Operator' );
# return 1 if $prev->isa( tok 'Word' ) and $next->isa( tok 'Cast' );
# 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' );
# return 1 if $prev->isa( tok 'Operator' ) and $prev->content =~ /\W$/;
# 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;
# },
# );
#}
#
### Mo/Inline.pm ###
#
#package Mo::Inline;
#use Mo;
#
#our $VERSION='0.40';
#
#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;
#
### Mo/Moose.pm ###
#package Mo::Moose;
#$Mo::Moose::VERSION = '0.40';$M="Mo::";
#$VERSION='0.40';
#*{$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;
#$Attr::Trait::VERSION = '0.40';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;
#$Mo::Mouse::VERSION = '0.40';$M="Mo::";
#$VERSION='0.40';
#*{$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;
#$Attr::Trait::VERSION = '0.40';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;
#$Mo::build::VERSION = '0.40';my$M="Mo::";
#$VERSION='0.40';
#*{$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;
#$Mo::builder::VERSION = '0.40';my$M="Mo::";
#$VERSION='0.40';
#*{$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;
#$Mo::chain::VERSION = '0.40';my$M="Mo::";
#$VERSION='0.40';
#*{$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;
#$Mo::coerce::VERSION = '0.40';my$M="Mo::";
#$VERSION='0.40';
#*{$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;
#$Mo::default::VERSION = '0.40';my$M="Mo::";
#$VERSION='0.40';
#*{$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;
#$Mo::exporter::VERSION = '0.40';my$M="Mo::";
#$VERSION='0.40';
#*{$M.'exporter::e'}=sub{my($P)=@_;if(@{$M.EXPORT}){*{$P.$_}=\&{$M.$_}for@{$M.EXPORT}}};
### Mo/import.pm ###
#package Mo::import;
#$Mo::import::VERSION = '0.40';my$M="Mo::";
#$VERSION='0.40';
#my$i=\&import;*{$M.import}=sub{(@_==2 and not$_[1])?pop@_:@_==1?push@_,grep!/import/,@f:();goto&$i};
### Mo/importer.pm ###
#package Mo::importer;
#$Mo::importer::VERSION = '0.40';my$M="Mo::";
#$VERSION='0.40';
#*{$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;
#$Mo::is::VERSION = '0.40';$M="Mo::";
#$VERSION='0.40';
#*{$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;
#$Mo::nonlazy::VERSION = '0.40';my$M="Mo::";
#$VERSION='0.40';
#*{$M.'nonlazy::e'}=sub{${shift().':N'}=1};
### Mo/option.pm ###
#package Mo::option;
#$Mo::option::VERSION = '0.40';my$M="Mo::";
#$VERSION='0.40';
#*{$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;
#$Mo::required::VERSION = '0.40';my$M="Mo::";
#$VERSION='0.40';
#*{$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;
#$Mo::xs::VERSION = '0.40';my$M="Mo::";
#$VERSION='0.40';
#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/Installed/Tiny.pm ###
#package Module::Installed::Tiny;
#
#our $DATE = '2016-08-04';
#our $VERSION = '0.003';
#
#use strict;
#use warnings;
#
#use Exporter qw(import);
#our @EXPORT_OK = qw(module_installed module_source);
#
#our $SEPARATOR;
#BEGIN {
# if ($^O =~ /^(dos|os2)/i) {
# $SEPARATOR = '\\';
# } elsif ($^O =~ /^MacOS/i) {
# $SEPARATOR = ':';
# } else {
# $SEPARATOR = '/';
# }
#}
#
#sub _module_source {
# my $name_pm = shift;
#
# for my $entry (@INC) {
# next unless defined $entry;
# my $ref = ref($entry);
# my ($is_hook, @hook_res);
# if ($ref eq 'ARRAY') {
# $is_hook++;
# @hook_res = $entry->[0]->($entry, $name_pm);
# } elsif (UNIVERSAL::can($entry, 'INC')) {
# $is_hook++;
# @hook_res = $entry->INC($name_pm);
# } elsif ($ref eq 'CODE') {
# $is_hook++;
# @hook_res = $entry->($entry, $name_pm);
# } else {
# my $path = "$entry$SEPARATOR$name_pm";
# if (-f $path) {
# open my($fh), "<", $path
# or die "Can't locate $name_pm: $path: $!";
# local $/;
# return scalar <$fh>;
# }
# }
#
# if ($is_hook) {
# next unless @hook_res;
# my $prepend_ref = shift @hook_res if ref($hook_res[0]) eq 'SCALAR';
# my $fh = shift @hook_res if ref($hook_res[0]) eq 'GLOB';
# my $code = shift @hook_res if ref($hook_res[0]) eq 'CODE';
# my $code_state = shift @hook_res if @hook_res;
# if ($fh) {
# my $src = "";
# local $_;
# while (!eof($fh)) {
# $_ = <$fh>;
# if ($code) {
# $code->($code, $code_state);
# }
# $src .= $_;
# }
# $src = $$prepend_ref . $src if $prepend_ref;
# return $src;
# } elsif ($code) {
# my $src = "";
# local $_;
# while ($code->($code, $code_state)) {
# $src .= $_;
# }
# $src = $$prepend_ref . $src if $prepend_ref;
# return $src;
# }
# }
# }
#
# die "Can't locate $name_pm in \@INC (\@INC contains: ".join(" ", @INC).")";
#}
#
#sub module_source {
# my $name = shift;
#
# my $name_pm;
# if ($name =~ /\A\w+(?:::\w+)*\z/) {
# ($name_pm = "$name.pm") =~ s!::!$SEPARATOR!g;
# } else {
# $name_pm = $name;
# }
#
# _module_source $name_pm;
#}
#
#sub module_installed {
# my $name = shift;
#
# my $name_pm;
# if ($name =~ /\A\w+(?:::\w+)*\z/) {
# ($name_pm = "$name.pm") =~ s!::!$SEPARATOR!g;
# } else {
# $name_pm = $name;
# }
#
# return 1 if exists $INC{$name_pm};
#
# if (eval { _module_source $name_pm; 1 }) {
# 1;
# } else {
# 0;
# }
#}
#
#1;
#
#__END__
#
### Perinci/Sub/Complete.pm ###
#package Perinci::Sub::Complete;
#
#our $DATE = '2017-07-10';
#our $VERSION = '0.92';
#
#use 5.010001;
#use strict;
#use warnings;
#use Log::ger;
#
#use Complete::Util qw(hashify_answer complete_array_elem complete_hash_key combine_answers modify_answer);
#use Complete::Common qw(:all);
#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_index
# 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,
# },
# },
#};
#sub complete_from_schema {
# my %args = @_;
# my $sch = $args{schema};
# my $word = $args{word} // "";
#
# my $fres;
# log_trace("[comp][periscomp] entering complete_from_schema, word=<%s>, schema=%s", $word, $sch);
#
# my ($type, $cs) = @{$sch};
#
# unless ($type =~ /\A(all|any|array|bool|buf|cistr|code|date|duration|float|hash|int|num|obj|re|str|undef)\z/) {
# no strict 'refs';
# my $pkg = "Sah::SchemaR::$type";
# (my $pkg_pm = "$pkg.pm") =~ s!::!/!g;
# eval { require $pkg_pm; 1 };
# goto RETURN_RES if $@;
# my $rsch = ${"$pkg\::rschema"};
# $type = $rsch->[0];
# $cs = {};
# for my $cs0 (@{ $rsch->[1] // [] }) {
# for (keys %$cs0) {
# $cs->{$_} = $cs0->{$_};
# }
# }
# log_trace("[comp][periscomp] retrieving schema from module %s, base type=%s", $pkg, $type);
# }
#
# my $static;
# my $words;
# eval {
# if (my $xcomp = $cs->{'x.completion'}) {
# require Module::Installed::Tiny;
# my $comp;
# if (ref($xcomp) eq 'CODE') {
# $comp = $xcomp;
# } else {
# my ($submod, $xcargs);
# if (ref($xcomp) eq 'ARRAY') {
# $submod = $xcomp->[0];
# $xcargs = $xcomp->[1];
# } else {
# $submod = $xcomp;
# $xcargs = {};
# }
# my $mod = "Perinci::Sub::XCompletion::$submod";
# if (Module::Installed::Tiny::module_installed($mod)) {
# log_trace("[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->(%$xcargs);
# }
# }
# if ($comp) {
# log_trace("[comp][periscomp] using arg completion routine from schema's 'x.completion' attribute");
# $fres = $comp->(
# %{$args{extras} // {}},
# word=>$word, arg=>$args{arg}, args=>$args{args});
# return;
# }
# }
#
# if ($cs->{is} && !ref($cs->{is})) {
# log_trace("[comp][periscomp] adding completion from schema's 'is' clause");
# push @$words, $cs->{is};
# $static++;
# return;
# }
# if ($cs->{in}) {
# log_trace("[comp][periscomp] adding completion from schema's 'in' clause");
# push @$words, grep {!ref($_)} @{ $cs->{in} };
# $static++;
# return;
# }
# if ($type eq 'any') {
# 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,
# )
# } @{ $cs->{of} }
# );
# goto RETURN_RES;
# }
# }
# if ($type eq 'bool') {
# log_trace("[comp][periscomp] adding completion from possible values of bool");
# push @$words, 0, 1;
# $static++;
# return;
# }
# if ($type eq 'int') {
# my $limit = 100;
# if ($cs->{between} &&
# $cs->{between}[0] - $cs->{between}[0] <= $limit) {
# log_trace("[comp][periscomp] adding completion from schema's 'between' clause");
# push @$words, $cs->{between}[0] .. $cs->{between}[1];
# $static++;
# } elsif ($cs->{xbetween} &&
# $cs->{xbetween}[0] - $cs->{xbetween}[0] <= $limit) {
# log_trace("[comp][periscomp] adding completion from schema's '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_trace("[comp][periscomp] adding completion from schema's 'min' & 'max' clauses");
# push @$words, $cs->{min} .. $cs->{max};
# $static++;
# } elsif (defined($cs->{min}) && defined($cs->{xmax}) &&
# $cs->{xmax}-$cs->{min} <= $limit) {
# log_trace("[comp][periscomp] adding completion from schema's 'min' & 'xmax' clauses");
# push @$words, $cs->{min} .. $cs->{xmax}-1;
# $static++;
# } elsif (defined($cs->{xmin}) && defined($cs->{max}) &&
# $cs->{max}-$cs->{xmin} <= $limit) {
# log_trace("[comp][periscomp] adding completion from schema's 'xmin' & 'max' clauses");
# push @$words, $cs->{xmin}+1 .. $cs->{max};
# $static++;
# } elsif (defined($cs->{xmin}) && defined($cs->{xmax}) &&
# $cs->{xmax}-$cs->{xmin} <= $limit) {
# log_trace("[comp][periscomp] adding completion from schema's 'xmin' & 'xmax' clauses");
# push @$words, $cs->{xmin}+1 .. $cs->{xmax}-1;
# $static++;
# } elsif (length($word) && $word !~ /\A-?\d*\z/) {
# log_trace("[comp][periscomp] word not an int");
# $words = [];
# } else {
# $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;
# }
# if ($type eq 'float') {
# if (length($word) && $word !~ /\A-?\d*(\.\d*)?\z/) {
# log_trace("[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;
# }
# };
#
# log_trace("[periscomp] complete_from_schema died: %s", $@) if $@;
#
# goto RETURN_RES unless $words;
# $fres = hashify_answer(
# complete_array_elem(array=>$words, word=>$word),
# {static=>$static && $word eq '' ? 1:0},
# );
#
# RETURN_RES:
# log_trace("[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)
#* `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
#<pm: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 => ''],
# },
# 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`, and so on as
#described in the function description will not be overwritten by this.
#
#_
# },
#
# %common_args_riap,
# },
# result_naked => 1,
# result => {
# schema => 'array',
# },
#};
#sub complete_arg_val {
# my %args = @_;
#
# log_trace("[comp][periscomp] entering complete_arg_val, arg=<%s>", $args{arg});
# my $fres;
#
# my $extras = $args{extras} // {};
#
# my $meta = $args{meta} or do {
# log_trace("[comp][periscomp] meta is not supplied, declining");
# goto RETURN_RES;
# };
# my $arg = $args{arg} or do {
# log_trace("[comp][periscomp] arg is not supplied, declining");
# goto RETURN_RES;
# };
# my $word = $args{word} // '';
#
#
# my $args_prop = $meta->{args} // {};
# my $arg_spec = $args_prop->{$arg} or do {
# log_trace("[comp][periscomp] arg '$arg' is not specified in meta, declining");
# goto RETURN_RES;
# };
#
# my $static;
# eval {
#
# my $comp;
# GET_COMP_ROUTINE:
# {
# $comp = $arg_spec->{completion};
# if ($comp) {
# log_trace("[comp][periscomp] using arg completion routine from arg spec's 'completion' property");
# last GET_COMP_ROUTINE;
# }
# my $xcomp = $arg_spec->{'x.completion'};
# if ($xcomp) {
# if (ref($xcomp) eq 'CODE') {
# $comp = $xcomp;
# } else {
# my ($submod, $xcargs);
# if (ref($xcomp) eq 'ARRAY') {
# $submod = $xcomp->[0];
# $xcargs = $xcomp->[1];
# } else {
# $submod = $xcomp;
# $xcargs = {};
# }
# my $mod = "Perinci::Sub::XCompletion::$submod";
# require Module::Installed::Tiny;
# if (Module::Installed::Tiny::module_installed($mod)) {
# log_trace("[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->(%$xcargs);
# }
# }
# if ($comp) {
# log_trace("[comp][periscomp] using arg completion routine from arg spec's 'x.completion' attribute");
# last GET_COMP_ROUTINE;
# }
# }
# my $ent = $arg_spec->{'x.schema.entity'};
# if ($ent) {
# require Module::Installed::Tiny;
# my $mod = "Perinci::Sub::ArgEntity::$ent";
# if (Module::Installed::Tiny::module_installed($mod)) {
# log_trace("[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_trace("[comp][periscomp] using arg completion routine from complete_arg_val() from %s", $mod);
# $comp = \&{"$mod\::complete_arg_val"};
# last GET_COMP_ROUTINE;
# }
# }
# }
# }
#
# if ($comp) {
# if (ref($comp) eq 'CODE') {
# log_trace("[comp][periscomp] invoking arg completion routine");
# $fres = $comp->(
# %$extras,
# word=>$word, arg=>$arg, args=>$args{args});
# return;
# } elsif (ref($comp) eq 'ARRAY') {
# log_trace("[comp][periscomp] using array specified in arg completion routine: %s", $comp);
# $fres = complete_array_elem(array=>$comp, word=>$word);
# $static++;
# return;
# }
#
# log_trace("[comp][periscomp] arg spec's 'completion' property is not a coderef or arrayref");
# if ($args{riap_client} && $args{riap_server_url}) {
# log_trace("[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},
# );
# if ($res->[0] != 200) {
# log_trace("[comp][periscomp] Riap request failed (%s), declining", $res);
# return;
# }
# $fres = $res->[2];
# return;
# }
#
# log_trace("[comp][periscomp] declining");
# return;
# }
#
# my $sch = $arg_spec->{schema};
# unless ($sch) {
# log_trace("[comp][periscomp] arg spec does not specify schema, declining");
# return;
# };
#
#
# $fres = complete_from_schema(arg=>$arg, extras=>$extras, schema=>$sch, word=>$word);
# };
# log_debug("[comp][periscomp] completion died: $@") if $@;
# unless ($fres) {
# log_trace("[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_trace("[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 => ['str*'],
# },
# },
#);
#sub complete_arg_elem {
# require Data::Sah::Normalize;
#
# my %args = @_;
#
# my $fres;
#
# log_trace("[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_trace("[comp][periscomp] meta is not supplied, declining");
# goto RETURN_RES;
# };
# my $arg = $args{arg} or do {
# log_trace("[comp][periscomp] arg is not supplied, declining");
# goto RETURN_RES;
# };
# defined(my $index = $args{index}) or do {
# log_trace("[comp][periscomp] index is not supplied, declining");
# goto RETURN_RES;
# };
# my $word = $args{word} // '';
#
#
# my $args_prop = $meta->{args} // {};
# my $arg_spec = $args_prop->{$arg} or do {
# log_trace("[comp][periscomp] arg '$arg' is not specified in meta, declining");
# goto RETURN_RES;
# };
#
# my $static;
# eval {
#
# my $elcomp;
# GET_ELCOMP_ROUTINE:
# {
# $elcomp = $arg_spec->{element_completion};
# if ($elcomp) {
# log_trace("[comp][periscomp] using arg element completion routine from 'element_completion' property");
# last GET_ELCOMP_ROUTINE;
# }
# my $xelcomp = $arg_spec->{'x.element_completion'};
# if ($xelcomp) {
# if (ref($xelcomp) eq 'CODE') {
# $elcomp = $xelcomp;
# } else {
# my ($submod, $xcargs);
# if (ref($xelcomp) eq 'ARRAY') {
# $submod = $xelcomp->[0];
# $xcargs = $xelcomp->[1];
# } else {
# $submod = $xelcomp;
# $xcargs = {};
# }
# my $mod = "Perinci::Sub::XCompletion::$submod";
# require Module::Installed::Tiny;
# if (Module::Installed::Tiny::module_installed($mod)) {
# log_trace("[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->(%$xcargs);
# }
# }
# if ($elcomp) {
# log_trace("[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::Installed::Tiny;
# my $mod = "Perinci::Sub::ArgEntity::$ent";
# if (Module::Installed::Tiny::module_installed($mod)) {
# log_trace("[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_trace("[comp][periscomp] using arg element completion routine from complete_arg_val() from %s", $mod);
# $elcomp = \&{"$mod\::complete_arg_val"};
# last GET_ELCOMP_ROUTINE;
# }
# }
# }
# }
#
# $ourextras->{index} = $index;
# if ($elcomp) {
# if (ref($elcomp) eq 'CODE') {
# log_trace("[comp][periscomp] invoking arg element completion routine");
# $fres = $elcomp->(
# %$extras,
# %$ourextras,
# word=>$word);
# return;
# } elsif (ref($elcomp) eq 'ARRAY') {
# log_trace("[comp][periscomp] using array specified in arg element completion routine: %s", $elcomp);
# $fres = complete_array_elem(array=>$elcomp, word=>$word);
# $static = $word eq '';
# }
#
# log_trace("[comp][periscomp] arg spec's 'element_completion' property is not a coderef or ".
# "arrayref");
# if ($args{riap_client} && $args{riap_server_url}) {
# log_trace("[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,
# index=>$index},
# );
# if ($res->[0] != 200) {
# log_trace("[comp][periscomp] Riap request failed (%s), declining", $res);
# return;
# }
# $fres = $res->[2];
# return;
# }
#
# log_trace("[comp][periscomp] declining");
# return;
# }
#
# my $sch = $arg_spec->{schema};
# unless ($sch) {
# log_trace("[comp][periscomp] arg spec does not specify schema, declining");
# return;
# };
#
# my $nsch = Data::Sah::Normalize::normalize_schema($sch);
#
# my ($type, $cs) = @$nsch;
# if ($type ne 'array') {
# log_trace("[comp][periscomp] can't complete element for non-array");
# return;
# }
#
# unless ($cs->{of}) {
# log_trace("[comp][periscomp] schema does not specify 'of' clause, declining");
# return;
# }
#
# my $elsch = Data::Sah::Normalize::normalize_schema($cs->{of});
#
# $fres = complete_from_schema(schema=>$elsch, word=>$word);
# };
# log_debug("[comp][periscomp] completion died: $@") if $@;
# unless ($fres) {
# log_trace("[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_trace("[comp][periscomp] leaving complete_arg_elem, result=%s", $fres);
# $fres;
#}
#
#$SPEC{complete_arg_index} = {
# v => 1.1,
# summary => 'Given argument name and function metadata, complete arg element index',
# description => <<'_',
#
#This is only relevant for arguments which have `index_completion` property set
#(currently only `hash` type arguments). When that property is not set, will
#simply return undef.
#
#Completion routine will get `%args`, with the following keys:
#
#* `word` (str, the word to be completed)
#* `arg` (str, the argument name which value is currently being completed)
#* `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
#<pm: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 => ''],
# },
# 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`, and so on as
#described in the function description will not be overwritten by this.
#
#_
# },
#
# %common_args_riap,
# },
# result_naked => 1,
# result => {
# schema => 'array',
# },
#};
#sub complete_arg_index {
# require Data::Sah::Normalize;
#
# my %args = @_;
#
# my $fres;
#
# log_trace("[comp][periscomp] entering complete_arg_index, arg=<%s>",
# $args{arg});
#
# my $extras = $args{extras} // {};
#
# my $ourextras = {arg=>$args{arg}, args=>$args{args}};
#
# my $meta = $args{meta} or do {
# log_trace("[comp][periscomp] meta is not supplied, declining");
# goto RETURN_RES;
# };
# my $arg = $args{arg} or do {
# log_trace("[comp][periscomp] arg is not supplied, declining");
# goto RETURN_RES;
# };
# my $word = $args{word} // '';
#
#
# my $args_prop = $meta->{args} // {};
# my $arg_spec = $args_prop->{$arg} or do {
# log_trace("[comp][periscomp] arg '$arg' is not specified in meta, declining");
# goto RETURN_RES;
# };
#
# my $static;
# eval {
#
# my $idxcomp;
# GET_IDXCOMP_ROUTINE:
# {
# $idxcomp = $arg_spec->{index_completion};
# if ($idxcomp) {
# log_trace("[comp][periscomp] using arg element index completion routine from 'index_completion' property");
# last GET_IDXCOMP_ROUTINE;
# }
# }
#
# if ($idxcomp) {
# if (ref($idxcomp) eq 'CODE') {
# log_trace("[comp][periscomp] invoking arg element index completion routine");
# $fres = $idxcomp->(
# %$extras,
# %$ourextras,
# word=>$word);
# return;
# } elsif (ref($idxcomp) eq 'ARRAY') {
# log_trace("[comp][periscomp] using array specified in arg element index completion routine: %s", $idxcomp);
# $fres = complete_array_elem(array=>$idxcomp, word=>$word);
# $static = $word eq '';
# }
#
# log_trace("[comp][periscomp] arg spec's 'index_completion' property is not a coderef or ".
# "arrayref");
# if ($args{riap_client} && $args{riap_server_url}) {
# log_trace("[comp][periscomp] trying to perform complete_arg_index request to Riap server");
# my $res = $args{riap_client}->request(
# complete_arg_index => $args{riap_server_url},
# {(uri=>$args{riap_uri}) x !!defined($args{riap_uri}),
# arg=>$arg, args=>$args{args}, word=>$word},
# );
# if ($res->[0] != 200) {
# log_trace("[comp][periscomp] Riap request failed (%s), declining", $res);
# return;
# }
# $fres = $res->[2];
# return;
# }
#
# log_trace("[comp][periscomp] declining");
# return;
# }
#
# my $sch = $arg_spec->{schema};
# unless ($sch) {
# log_trace("[comp][periscomp] arg spec does not specify schema, declining");
# return;
# };
#
# my $nsch = Data::Sah::Normalize::normalize_schema($sch);
#
# my ($type, $cs) = @$nsch;
# if ($type ne 'hash') {
# log_trace("[comp][periscomp] can't complete element index for non-hash");
# return;
# }
#
# my %keys;
# if ($cs->{keys}) {
# $keys{$_}++ for keys %{ $cs->{keys} };
# }
# if ($cs->{indices}) {
# $keys{$_}++ for keys %{ $cs->{indices} };
# }
# if ($cs->{req_keys}) {
# $keys{$_}++ for @{ $cs->{req_keys} };
# }
# if ($cs->{allowed_keys}) {
# $keys{$_}++ for @{ $cs->{allowed_keys} };
# }
#
# for (keys %{$args{args}{$arg} // {}}) {
# delete $keys{$_};
# }
#
# $fres = complete_hash_key(word => $word, hash => \%keys);
#
# };
# log_debug("[comp][periscomp] completion died: $@") if $@;
# unless ($fres) {
# log_trace("[comp][periscomp] no index completion from metadata possible, declining");
# goto RETURN_RES;
# }
#
# $fres = hashify_answer($fres);
# $fres->{static} //= $static && $word eq '' ? 1:0;
# RETURN_RES:
# log_trace("[comp][periscomp] leaving complete_arg_index, result=%s", $fres);
# $fres;
#}
#
#$SPEC{complete_cli_arg} = {
# v => 1.1,
# summary => 'Complete command-line argument using Rinci function metadata',
# description => <<'_',
#
#This routine uses <pm:Perinci::Sub::GetArgs::Argv> to generate <pm:Getopt::Long>
#specification from arguments list in Rinci function metadata and common options.
#Then, it will use <pm: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 <pm: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`, 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 <pm: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 <pm: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";
# my $fres;
#
# my $word = $words->[$cword];
# my $args_prop = $meta->{args} // {};
#
# log_trace('[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_trace("[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 $fres;
#
# my %rargs = (
# riap_server_url => $args{riap_server_url},
# riap_uri => $args{riap_uri},
# riap_client => $args{riap_client},
# );
#
# $extras->{parsed_opts} = $cargs{parsed_opts};
#
# if (my $sm = $specmeta->{$ospec}) {
# $cargs{type} = 'optval';
# if ($sm->{arg}) {
# log_trace("[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_trace("[comp][periscomp] invoking routine supplied from 'completion' argument");
# my $compres;
# eval { $compres = $comp->(%cargs) };
# log_debug("[comp][periscomp] completion died: $@") if $@;
# log_trace("[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},
# extras=>$extras, %rargs);
# goto RETURN_RES;
# } elsif ($ospec =~ /\%$/) {
# if ($word =~ /(.*?)=(.*)/s) {
# my $key = $1;
# my $val = $2;
# $fres = complete_arg_elem(
# meta=>$meta, arg=>$sm->{arg}, args=>$gares->[2],
# word=>$val, index=>$key,
# extras=>$extras, %rargs);
# modify_answer(answer=>$fres, prefix=>"$key=");
# goto RETURN_RES;
# } else {
# $fres = complete_arg_index(
# meta=>$meta, arg=>$sm->{arg}, args=>$gares->[2],
# word=>$word, extras=>$extras, %rargs);
# modify_answer(answer=>$fres, suffix=>"=");
# $fres->{path_sep} = "=";
# $fres->{esc_mode} = "none";
# 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_trace("[comp][periscomp] completing option value for a common option, ospec=<%s>", $ospec);
# $cargs{arg} = undef;
# my $codata = $copts_by_ospec->{$ospec};
# if ($comp) {
# log_trace("[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_trace("[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_trace("[comp][periscomp] completing with common option's schema");
# $fres = complete_from_schema(
# schema => $nsch, word=>$word);
# goto RETURN_RES;
# }
# goto RETURN_RES;
# }
# } elsif ($type eq 'arg') {
# log_trace("[comp][periscomp] completing argument #%d", $cargs{argpos});
# $cargs{type} = 'arg';
#
# my $pos = $cargs{argpos};
# my $fasa = $args{func_arg_starts_at} // 0;
#
# 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_trace("[comp][periscomp] this argument position is for non-greedy function argument <%s>", $an);
# $cargs{arg} = $an;
# if ($comp) {
# log_trace("[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;
# }
#
# 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_trace("[comp][periscomp] this position is for greedy function argument <%s>'s element[%d]", $an, $index);
# if ($comp) {
# log_trace("[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_trace("[comp][periscomp] there is no matching function argument at this position");
# if ($comp) {
# log_trace("[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_trace("[comp][periscomp] completing option value for an unknown/ambiguous option, declining ...");
# goto RETURN_RES;
# }
# RETURN_RES:
# log_trace("[comp][periscomp] leaving completion routine (that we supply to Complete::Getopt::Long)");
# $fres;
# };
#
# $fres = Complete::Getopt::Long::complete_cli_arg(
# getopt_spec => $gospec,
# words => $words,
# cword => $cword,
# completion => $compgl_comp,
# extras => $extras,
# );
#
# RETURN_RES:
# log_trace('[comp][periscomp] leaving %s(), result=%s',
# $fname, $fres);
# $fres;
#}
#
#1;
#
#__END__
#
### Perinci/Sub/GetArgs/Argv.pm ###
#package Perinci::Sub::GetArgs::Argv;
#
#our $DATE = '2017-08-27';
#our $VERSION = '0.840';
#
#use 5.010001;
#use strict;
#use warnings;
#
#use Data::Sah::Normalize qw(normalize_schema);
#use Data::Sah::Util::Type qw(is_type is_simple);
#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)',
#};
#
#sub _parse_json {
# my $str = shift;
#
# state $json = do {
# require JSON::PP;
# JSON::PP->new->allow_nonref;
# };
#
# 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;
#
# my $res;
# eval {
# if ($yaml_xs_available) {
# $res = YAML::XS::Load($str);
# } else {
# $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;
# $opt;
#}
#
#sub _is_coercible_from_simple {
# my $nsch = shift;
# my $cset = $nsch->[1] or return 0;
# my $rules = $cset->{'x.perl.coerce_rules'} // $cset->{'x.coerce_rules'}
# or return 0;
# for my $rule (@$rules) {
# next unless $rule =~ /\A([^_]+)_/;
# return 1 if is_simple($1);
# }
# 0;
#}
#
#sub _is_simple_or_coercible_from_simple {
# my $nsch = shift;
# is_simple($nsch) || _is_coercible_from_simple($nsch);
#}
#
#sub _is_simple_or_array_of_simple_or_hash_of_simple {
# my $nsch = shift;
#
# my $is_simple = 0;
# my $is_array_of_simple = 0;
# my $is_hash_of_simple = 0;
# my $eltype;
#
# my $type = $nsch->[0];
# my $cset = $nsch->[1];
#
# {
# unless (is_type($nsch)) {
# require Data::Sah::Resolve;
# my $res = Data::Sah::Resolve::resolve_schema(
# {merge_clause_sets => 0}, $nsch);
# $type = $res->[0];
# $cset = $res->[1][0] // {};
# }
#
# $is_simple = _is_simple_or_coercible_from_simple([$type, $cset]);
# last if $is_simple;
#
# if ($type eq 'array') {
# my $elnsch = $cset->{of} // $cset->{each_elem};
# last unless $elnsch;
# $elnsch = normalize_schema($elnsch);
# $eltype = $elnsch->[0];
#
# unless (is_type($elnsch)) {
# require Data::Sah::Resolve;
# my $res = Data::Sah::Resolve::resolve_schema(
# {merge_clause_sets => 0}, $elnsch);
# $elnsch = [$res->[0], $res->[1][0] // {}];
# $eltype = $res->[0];
# }
#
# $is_array_of_simple = _is_simple_or_coercible_from_simple($elnsch);
# last;
# }
#
# if ($type eq 'hash') {
# my $elnsch = $cset->{of} // $cset->{each_value} // $cset->{each_elem};
# last unless $elnsch;
# $elnsch = normalize_schema($elnsch);
# $eltype = $elnsch->[0];
#
# unless (is_type($elnsch)) {
# require Data::Sah::Resolve;
# my $res = Data::Sah::Resolve::resolve_schema(
# {merge_clause_sets => 0}, $elnsch);
# $elnsch = [$res->[0], $res->[1][0] // {}];
# $eltype = $res->[0];
# }
#
# $is_hash_of_simple = _is_simple_or_coercible_from_simple($elnsch);
# last;
# }
# }
#
# ($is_simple, $is_array_of_simple, $is_hash_of_simple, $type, $cset, $eltype);
#}
#
#sub _opt2ospec {
# my ($opt, $schema, $arg_spec) = @_;
# my ($is_simple, $is_array_of_simple, $is_hash_of_simple, $type, $cset, $eltype) =
# _is_simple_or_array_of_simple_or_hash_of_simple($schema);
#
# my (@opts, @types, @isaos, @ishos);
#
# if ($is_array_of_simple || $is_hash_of_simple) {
# my $singular_opt;
# if ($arg_spec && $arg_spec->{'x.name.is_plural'}) {
# if ($arg_spec->{'x.name.singular'}) {
# $singular_opt = _arg2opt($arg_spec->{'x.name.singular'});
# } else {
# require Lingua::EN::PluralToSingular;
# $singular_opt = Lingua::EN::PluralToSingular::to_singular($opt);
# }
# } else {
# $singular_opt = $opt;
# }
# push @opts , $singular_opt;
# push @types, $eltype;
# push @isaos, $is_array_of_simple ? 1:0;
# push @ishos, $is_hash_of_simple ? 1:0;
# }
#
# if ($is_simple || !@opts) {
# push @opts , $opt;
# push @types, $type;
# push @isaos, 0;
# push @ishos, 0;
# }
#
# my @res;
#
# for my $i (0..$#opts) {
# my $opt = $opts[$i];
# my $type = $types[$i];
# my $isaos = $isaos[$i];
# my $ishos = $ishos[$i];
#
# if ($type eq 'bool') {
# if (length($opt) == 1 || $cset->{is}) {
# push @res, ($opt, {opts=>[$opt]}), undef;
# } else {
# 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]};
# }
# }
# } elsif ($type eq 'buf') {
# push @res, (
# "$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' ? 's' : $type eq 'float' ? 's' : 's') .
# ($isaos ? '@' : $ishos ? '%' : '');
# push @res, ("$opt=$t", {opts=>[$opt], desttype=>"", type=>$t}, undef);
# }
# }
#
# @res;
#}
#
#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};
# next if grep { $_ eq 'hidden' || $_ eq 'hidden-cli' }
# @{ $arg_spec->{tags} // [] };
# my $sch = $arg_spec->{schema} // ['any', {}];
# my ($is_simple, $is_array_of_simple, $is_hash_of_simple, $type, $cset, $eltype) =
# _is_simple_or_array_of_simple_or_hash_of_simple($sch);
#
# if ($type eq 'array' && $cset->{of}) {
# $cset->{of} = normalize_schema($cset->{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 $stash = {};
#
#
# my $handler = sub {
# my ($val, $val_set);
#
# my $num_called = ++$stash->{called}{$arg};
#
# my $rargs = do {
# if (ref($rargs) eq 'ARRAY') {
# $rargs->[$num_called-1] //= {};
# $rargs->[$num_called-1];
# } else {
# $rargs;
# }
# };
#
# if ($is_simple) {
# $val_set = 1; $val = $_[1];
# $rargs->{$arg} = $val;
# } elsif ($is_array_of_simple) {
# $rargs->{$arg} //= [];
# $val_set = 1; $val = $_[1];
# push @{ $rargs->{$arg} }, $val;
# } elsif ($is_hash_of_simple) {
# $rargs->{$arg} //= {};
# $val_set = 1; $val = $_[2];
# $rargs->{$arg}{$_[1]} = $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,
# );
# }
# };
#
# 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} && !$is_simple) {
# 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} && !$is_simple) {
# 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;
# }
# }
#
# 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') {
# $alospec = $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"),
# ];
# }
# }
# $go_spec->{$alospec} = sub {
#
# 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;
# }
# }
#
# if ($arg_spec->{meta}) {
# $rargs->{$arg} = {};
# my $res = _args2opts(
# %args,
# argprefix => "$argprefix$arg\::",
# meta => $arg_spec->{meta},
# rargs => $rargs->{$arg},
# );
# return $res if $res;
# }
#
# 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;
# }
# }
#
# }
#
# 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 <pm: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;
# 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 <pm: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.
#
#_
# },
# ggls_res => {
# summary => 'Full result from gen_getopt_long_spec_from_meta()',
# schema => 'array*',
# description => <<'_',
#
#If you already call `gen_getopt_long_spec_from_meta()`, you can pass the _full_ enveloped result
#here, to avoid calculating twice.
#
#_
# tags => ['category:optimization'],
# },
# },
# 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};
#
# my $rargs = $fargs{args} // {};
#
# my $genres = $fargs{ggls_res} // 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];
#
# {
# local $SIG{__WARN__} = sub{} if !$strict;
# my $old_go_conf = Getopt::Long::Configure(
# $strict ? "no_pass_through" : "pass_through",
# "no_ignore_case", "permute", "no_getopt_compat", "gnu_compat", "bundling");
# my $res = Getopt::Long::GetOptionsFromArray($argv, %$go_spec);
# Getopt::Long::Configure($old_go_conf);
# unless ($res) {
# return [500, "GetOptions failed"] if $strict;
# }
# }
#
#
# 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 ($is_simple, $is_array_of_simple, $is_hash_of_simple, $type, $cset, $eltype) =
# _is_simple_or_array_of_simple_or_hash_of_simple($arg_spec->{schema});
#
# if ($arg_spec->{greedy} && ref($val) eq 'ARRAY' &&
# !$is_array_of_simple && !$is_hash_of_simple) {
# 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) {
# 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;
# if ($arg_spec->{cmdline_on_getopt}) {
# if ($arg_spec->{greedy}) {
# $arg_spec->{cmdline_on_getopt}->(
# arg=>$name, fqarg=>$name, value=>$_, args=>$rargs,
# opt=>undef,
# ) for @$val;
# } else {
# $arg_spec->{cmdline_on_getopt}->(
# arg=>$name, fqarg=>$name, value=>$val, args=>$rargs,
# opt=>undef,
# );
# }
# }
# }
# }
# }
#
#
# my %missing_args;
# for my $arg (keys %$args_prop) {
# my $arg_spec = $args_prop->{$arg};
# if (!exists($rargs->{$arg})) {
# next unless $arg_spec->{req};
# if ($on_missing) {
# next if $on_missing->(arg=>$arg, args=>$rargs, spec=>$arg_spec);
# }
# next if exists $rargs->{$arg};
# $missing_args{$arg} = 1;
# }
# }
#
# {
# 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};
# }
# }
#
# [200, "OK", $rargs, {
# "func.missing_args" => [sort keys %missing_args],
# "func.gen_getopt_long_spec_result" => $genres,
# }];
#}
#
#1;
#
#__END__
#
### Perinci/Sub/GetArgs/Array.pm ###
#package Perinci::Sub::GetArgs::Array;
#
#our $DATE = '2016-12-10';
#our $VERSION = '0.16';
#
#use 5.010001;
#use strict;
#use warnings;
#
#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) {
# 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;
# } elsif ($type eq 'hash') {
# $rargs->{$a} = {};
# for my $j (0..$#elems) {
# my $elem = $elems[$j];
# unless ($elem =~ /(.*?)=(.*)/) {
# return [400, "Invalid key=value pair in element #$j"];
# }
# $rargs->{$a}{$1} = $2;
# }
# } else {
# $rargs->{$a} = join " ", @elems;
# }
# } else {
# $rargs->{$a} = splice(@$ary, $i, 1);
# }
# }
# }
# }
#
# return [400, "There are extra, unassigned elements in array: [".
# join(", ", @$ary)."]"] if @$ary && !$allow_extra_elems;
#
# [200, "OK", $rargs];
#}
#
#1;
#
#__END__
#
### Perinci/Sub/Normalize.pm ###
#package Perinci::Sub::Normalize;
#
#our $DATE = '2016-12-11';
#our $VERSION = '0.19';
#
#use 5.010001;
#use strict;
#use warnings;
#
#require Exporter;
#our @ISA = qw(Exporter);
#our @EXPORT_OK = qw(
# normalize_function_metadata
# );
#
#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" : "");
#
# if ($prop =~ /\A_/ || defined($attr) && $attr =~ /\A_|\._/) {
# unless ($opt_rip) {
# $nmeta->{$nk} = $meta->{$k};
# }
# next KEY;
# }
#
# my $prop_proplist = $proplist->{$prop};
#
# if (!$opt_aup && !$prop_proplist) {
# $modprefix //= $prefix;
# my $mod = "Perinci/Sub/Property$modprefix/$prop.pm";
# eval { require $mod };
# 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) {
# 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;
#
# require Sah::Schema::rinci::function_meta;
# my $sch = $Sah::Schema::rinci::function_meta::schema;
# my $sch_proplist = $sch->[1]{_prop}
# or die "BUG: Rinci schema structure changed (1a)";
#
# _normalize($meta, 1.1, $opts, $sch_proplist, {}, '');
#}
#
#1;
#
#__END__
#
### Perinci/Sub/Util.pm ###
#package Perinci::Sub::Util;
#
#our $DATE = '2017-01-31';
#our $VERSION = '0.46';
#
#use 5.010001;
#use strict;
#use warnings;
#
#require Exporter;
#our @ISA = qw(Exporter);
#our @EXPORT_OK = qw(
# err
# caller
# warn_err
# die_err
# gen_modified_sub
# gen_curried_sub
# );
#
#our %SPEC;
#
#$SPEC{':package'} = {
# v => 1.1,
# summary => 'Helper when writing functions',
#};
#
#our $STACK_TRACE;
#our @_c;
#our $_i;
#sub err {
# require Scalar::Util;
#
# my @caller = CORE::caller(1);
# if (!@caller) {
# @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;
#
# if (!$meta->{logs}) {
#
# my $stack_trace;
# {
# no warnings;
# last unless $STACK_TRACE // $INC{"Carp/Always.pm"};
# 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,
# };
# }
#
# [$status, $msg, undef, $meta];
#}
#
#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]");
#}
#
#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) {
# $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*',
# },
# 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*'],
# },
# }],
# },
#};
#sub gen_modified_sub {
# require Function::Fallback::CoreOrPP;
#
# my %args = @_;
#
# 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;
#
# 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);
# }
#
# 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}];
#}
#
#$SPEC{gen_curried_sub} = {
# v => 1.1,
# summary => 'Generate curried subroutine (and its metadata)',
# description => <<'_',
#
#This is a more convenient helper than `gen_modified_sub` if you want to create a
#new subroutine that has some of its arguments preset (so they no longer need to
#be present in the new metadata).
#
#For more general needs of modifying a subroutine (e.g. add some arguments,
#modify some arguments, etc) use `gen_modified_sub`.
#
#_
# 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.
#
#_
# req => 1,
# pos => 0,
# },
# set_args => {
# summary => 'Arguments to set',
# schema => 'hash*',
# },
# 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.
#
#_
# req => 1,
# pos => 2,
# },
# },
# args_as => 'array',
# result_naked => 1,
#};
#sub gen_curried_sub {
# my ($base_name, $set_args, $output_name) = @_;
#
# my $caller = CORE::caller();
#
# my ($base_pkg, $base_leaf);
# if ($base_name =~ /(.+)::(.+)/) {
# ($base_pkg, $base_leaf) = ($1, $2);
# } else {
# $base_pkg = $caller;
# $base_leaf = $base_name;
# }
#
# my ($output_pkg, $output_leaf);
# if ($output_name =~ /(.+)::(.+)/) {
# ($output_pkg, $output_leaf) = ($1, $2);
# } else {
# $output_pkg = $caller;
# $output_leaf = $output_name;
# }
#
# my $base_sub = \&{"$base_pkg\::$base_leaf"};
#
# my $res = gen_modified_sub(
# base_name => "$base_pkg\::$base_leaf",
# output_name => "$output_pkg\::$output_leaf",
# output_code => sub {
# no strict 'refs';
# $base_sub->(@_, %$set_args);
# },
# remove_args => [keys %$set_args],
# install => 1,
# );
#
# die "Can't generate curried sub: $res->[0] - $res->[1]"
# unless $res->[0] == 200;
#
# 1;
#}
#
#1;
#
#__END__
#
### Perinci/Sub/Util/Args.pm ###
#package Perinci::Sub::Util::Args;
#
#our $DATE = '2017-01-31';
#our $VERSION = '0.46';
#
#use 5.010001;
#use strict 'subs', 'vars';
#use warnings;
#
#use Exporter qw(import);
#our @EXPORT_OK = qw(
# args_by_tag
# argnames_by_tag
# func_args_by_tag
# func_argnames_by_tag
# call_with_its_args
#);
#
#sub args_by_tag {
# my ($meta, $args, $tag) = @_;
#
# my @res;
# my $args_prop = $meta->{args} or return ();
# my $neg = $tag =~ s/\A!//;
# for my $argname (keys %$args_prop) {
# my $argspec = $args_prop->{$argname};
# if ($neg) {
# next unless !$argspec->{tags} ||
# !(grep {$_ eq $tag} @{$argspec->{tags}});
# } else {
# next unless $argspec->{tags} &&
# grep {$_ eq $tag} @{$argspec->{tags}};
# }
# push @res, $argname, $args->{$argname}
# if exists $args->{$argname};
# }
# @res;
#}
#
#sub argnames_by_tag {
# my ($meta, $tag) = @_;
#
# my @res;
# my $args_prop = $meta->{args} or return ();
# my $neg = 1 if $tag =~ s/\A!//;
# for my $argname (keys %$args_prop) {
# my $argspec = $args_prop->{$argname};
# if ($neg) {
# next unless !$argspec->{tags} ||
# !(grep {$_ eq $tag} @{$argspec->{tags}});
# } else {
# next unless $argspec->{tags} &&
# grep {$_ eq $tag} @{$argspec->{tags}};
# }
# push @res, $argname;
# }
# sort @res;
#}
#
#sub _find_meta {
# my $caller = shift;
# my $func_name = shift;
#
# if ($func_name =~ /(.+)::(.+)/) {
# return ${"$1::SPEC"}{$2};
# } else {
# return ${"$caller->[0]::SPEC"}{$func_name};
# }
#}
#
#sub func_args_by_tag {
# my ($func_name, $args, $tag) = @_;
# my $meta = _find_meta([caller(1)], $func_name)
# or die "Can't find Rinci function metadata for $func_name";
# args_by_tag($meta, $args, $tag);
#}
#
#sub func_argnames_by_tag {
# my ($func_name, $tag) = @_;
# my $meta = _find_meta([caller(1)], $func_name)
# or die "Can't find Rinci function metadata for $func_name";
# argnames_by_tag($meta, $tag);
#}
#
#sub call_with_its_args {
# my ($func_name, $args) = @_;
#
# my ($meta, $func);
# if ($func_name =~ /(.+)::(.+)/) {
# defined &{$func_name}
# or die "Function $func_name not defined";
# $func = \&{$func_name};
# $meta = ${"$1::SPEC"}{$2};
# } else {
# my @caller = caller(1);
# my $fullname = "$caller[0]::$func_name";
# defined &{$fullname}
# or die "Function $fullname not defined";
# $func = \&{$fullname};
# $meta = ${"$caller[0]::SPEC"}{$func_name};
# }
# $meta or die "Can't find Rinci function metadata for $func_name";
#
# my @args;
# if ($meta->{args}) {
# for my $argname (keys %{ $meta->{args} }) {
# push @args, $argname, $args->{$argname}
# if exists $args->{$argname};
# }
# }
# $func->(@args);
#}
#
#1;
#
#__END__
#
### Perinci/Sub/Util/ResObj.pm ###
#package Perinci::Sub::Util::ResObj;
#
#our $DATE = '2017-01-31';
#our $VERSION = '0.46';
#
#use Carp;
#use overload
# q("") => sub {
# my $res = shift; "ERROR $err->[0]: $err->[1]\n" . Carp::longmess();
# };
#
#1;
#
#__END__
#
### Perinci/Sub/Util/Sort.pm ###
#package Perinci::Sub::Util::Sort;
#
#our $DATE = '2017-01-31';
#our $VERSION = '0.46';
#
#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;
#
#__END__
#
### Regexp/Stringify.pm ###
#package Regexp::Stringify;
#
#our $DATE = '2016-10-29';
#our $VERSION = '0.06';
#
#use 5.010001;
#use strict;
#use warnings;
#
#use re qw(regexp_pattern);
#
#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->parse($plver) >= version->parse('5.14.0');
# 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;
#
#__END__
#
### Sah/Schema/rinci/function_meta.pm ###
#package Sah::Schema::rinci::function_meta;
#
#our $DATE = '2016-12-26';
#our $VERSION = '1.1.82.2';
#
#use 5.010001;
#use strict;
#use warnings;
#
#use Data::Sah::Normalize ();
#use Sah::Schema::rinci::meta ();
#
#our $schema = [hash => {
# summary => 'Rinci function metadata',
#
# _ver => 1.1,
# _prop => {
# %Sah::Schema::rinci::meta::_dh_props,
#
# entity_v => {},
# entity_date => {},
# links => {},
#
# is_func => {},
# is_meth => {},
# is_class_meth => {},
# args => {
# _value_prop => {
# %Sah::Schema::rinci::meta::_dh_props,
#
# 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 => {},
# index_completion => {},
# element_completion => {},
# cmdline_src => {},
# meta => 'fix',
# element_meta => 'fix',
# deps => {
# _keys => {
# arg => {},
# all => {},
# any => {},
# none => {},
# },
# },
# },
# },
# args_as => {},
# args_rels => {},
# result => {
# _prop => {
# %Sah::Schema::rinci::meta::_dh_props,
#
# schema => {},
# statuses => {
# _value_prop => {
# summary => {},
# description => {},
# schema => {},
# },
# },
# partial => {},
# stream => {},
# },
# },
# result_naked => {},
# examples => {
# _elem_prop => {
# %Sah::Schema::rinci::meta::_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 => {},
# },
# },
# },
#}, {}];
#
#$schema->[1]{_prop}{args}{_value_prop}{meta} = $schema->[1];
#$schema->[1]{_prop}{args}{_value_prop}{element_meta} = $schema->[1];
#
#
#$schema = Data::Sah::Normalize::normalize_schema($schema);
#
#1;
#
#__END__
#
### Sah/Schema/rinci/meta.pm ###
#package Sah::Schema::rinci::meta;
#
#our $DATE = '2016-12-26';
#our $VERSION = '1.1.82.2';
#
#use 5.010001;
#use strict;
#use warnings;
#
#our %_dh_props = (
# v => {},
# defhash_v => {},
# name => {},
# caption => {},
# summary => {},
# description => {},
# tags => {},
# default_lang => {},
# x => {},
#);
#
#our $schema = [hash => {
# summary => 'Rinci metadata',
# _ver => 1.1,
# _prop => {
# %_dh_props,
#
# entity_v => {},
# entity_date => {},
# links => {
# _elem_prop => {
# %_dh_props,
#
# url => {},
# },
# },
# },
#}, {}];
#
#1;
#
#__END__
#
### Sah/Schema/rinci/result_meta.pm ###
#package Sah::Schema::rinci::result_meta;
#
#our $DATE = '2016-12-26';
#our $VERSION = '1.1.82.2';
#
#use 5.010001;
#use strict;
#use warnings;
#
#use Sah::Schema::rinci::meta;
#
#our $schema = [hash => {
# summary => 'Rinci envelope result metadata',
#
# _ver => 1.1,
# _prop => {
# %Sah::Schema::rinci::meta::_dh_props,
#
# perm_err => {},
# func => {},
# cmdline => {},
# logs => {},
# prev => {},
# results => {},
# part_start => {},
# part_len => {},
# len => {},
# stream => {},
# },
#}, {}];
#
#1;
#
#__END__
#
### Sah/SchemaR/rinci/function_meta.pm ###
#package Sah::SchemaR::rinci::function_meta;
#
#our $DATE = '2016-12-26';
#our $VERSION = '1.1.82.2';
#
#our $rschema = do {
# my $a = [
# "hash",
# [
# {
# _prop => {
# args => {
# _value_prop => {
# caption => {},
# cmdline_aliases => {
# _value_prop => { code => {}, description => {}, is_flag => {}, schema => {}, summary => {} },
# },
# cmdline_on_getopt => {},
# cmdline_prompt => {},
# cmdline_src => {},
# completion => {},
# default => {},
# default_lang => {},
# defhash_v => {},
# deps => { _keys => { all => {}, any => {}, arg => {}, none => {} } },
# description => {},
# element_completion => {},
# element_meta => { _prop => 'fix', _ver => 1.1, summary => "Rinci function metadata" },
# filters => {},
# greedy => {},
# index_completion => {},
# is_password => {},
# links => {},
# meta => 'fix',
# name => {},
# partial => {},
# pos => {},
# req => {},
# schema => {},
# stream => {},
# summary => {},
# tags => {},
# v => {},
# x => {},
# },
# },
# args_as => {},
# args_rels => {},
# caption => 'fix',
# default_lang => 'fix',
# defhash_v => 'fix',
# deps => {
# _keys => {
# all => {},
# any => {},
# code => {},
# env => {},
# func => {},
# none => {},
# pkg => {},
# prog => {},
# tmp_dir => {},
# trash_dir => {},
# },
# },
# description => 'fix',
# entity_date => {},
# entity_v => {},
# examples => {
# _elem_prop => {
# args => {},
# argv => {},
# caption => 'fix',
# default_lang => 'fix',
# defhash_v => 'fix',
# description => 'fix',
# name => 'fix',
# result => {},
# src => {},
# src_plang => {},
# status => {},
# summary => 'fix',
# tags => 'fix',
# test => {},
# v => 'fix',
# x => 'fix',
# },
# },
# features => {
# _keys => {
# check_arg => {},
# dry_run => {},
# idempotent => {},
# immutable => {},
# pure => {},
# reverse => {},
# tx => {},
# },
# },
# is_class_meth => {},
# is_func => {},
# is_meth => {},
# links => {},
# name => 'fix',
# result => {
# _prop => {
# caption => 'fix',
# default_lang => 'fix',
# defhash_v => 'fix',
# description => 'fix',
# name => 'fix',
# partial => {},
# schema => {},
# statuses => {
# _value_prop => { description => {}, schema => {}, summary => {} },
# },
# stream => {},
# summary => 'fix',
# tags => 'fix',
# v => 'fix',
# x => 'fix',
# },
# },
# result_naked => {},
# summary => 'fix',
# tags => 'fix',
# v => 'fix',
# x => 'fix',
# },
# _ver => 1.1,
# summary => "Rinci function metadata",
# },
# ],
# ["hash"],
# ];
# $a->[1][0]{_prop}{args}{_value_prop}{element_meta}{_prop} = $a->[1][0]{_prop};
# $a->[1][0]{_prop}{args}{_value_prop}{meta} = $a->[1][0]{_prop}{args}{_value_prop}{element_meta};
# $a->[1][0]{_prop}{caption} = $a->[1][0]{_prop}{args}{_value_prop}{caption};
# $a->[1][0]{_prop}{default_lang} = $a->[1][0]{_prop}{args}{_value_prop}{default_lang};
# $a->[1][0]{_prop}{defhash_v} = $a->[1][0]{_prop}{args}{_value_prop}{defhash_v};
# $a->[1][0]{_prop}{description} = $a->[1][0]{_prop}{args}{_value_prop}{description};
# $a->[1][0]{_prop}{examples}{_elem_prop}{caption} = $a->[1][0]{_prop}{args}{_value_prop}{caption};
# $a->[1][0]{_prop}{examples}{_elem_prop}{default_lang} = $a->[1][0]{_prop}{args}{_value_prop}{default_lang};
# $a->[1][0]{_prop}{examples}{_elem_prop}{defhash_v} = $a->[1][0]{_prop}{args}{_value_prop}{defhash_v};
# $a->[1][0]{_prop}{examples}{_elem_prop}{description} = $a->[1][0]{_prop}{args}{_value_prop}{description};
# $a->[1][0]{_prop}{examples}{_elem_prop}{name} = $a->[1][0]{_prop}{args}{_value_prop}{name};
# $a->[1][0]{_prop}{examples}{_elem_prop}{summary} = $a->[1][0]{_prop}{args}{_value_prop}{summary};
# $a->[1][0]{_prop}{examples}{_elem_prop}{tags} = $a->[1][0]{_prop}{args}{_value_prop}{tags};
# $a->[1][0]{_prop}{examples}{_elem_prop}{v} = $a->[1][0]{_prop}{args}{_value_prop}{v};
# $a->[1][0]{_prop}{examples}{_elem_prop}{x} = $a->[1][0]{_prop}{args}{_value_prop}{x};
# $a->[1][0]{_prop}{name} = $a->[1][0]{_prop}{args}{_value_prop}{name};
# $a->[1][0]{_prop}{result}{_prop}{caption} = $a->[1][0]{_prop}{args}{_value_prop}{caption};
# $a->[1][0]{_prop}{result}{_prop}{default_lang} = $a->[1][0]{_prop}{args}{_value_prop}{default_lang};
# $a->[1][0]{_prop}{result}{_prop}{defhash_v} = $a->[1][0]{_prop}{args}{_value_prop}{defhash_v};
# $a->[1][0]{_prop}{result}{_prop}{description} = $a->[1][0]{_prop}{args}{_value_prop}{description};
# $a->[1][0]{_prop}{result}{_prop}{name} = $a->[1][0]{_prop}{args}{_value_prop}{name};
# $a->[1][0]{_prop}{result}{_prop}{summary} = $a->[1][0]{_prop}{args}{_value_prop}{summary};
# $a->[1][0]{_prop}{result}{_prop}{tags} = $a->[1][0]{_prop}{args}{_value_prop}{tags};
# $a->[1][0]{_prop}{result}{_prop}{v} = $a->[1][0]{_prop}{args}{_value_prop}{v};
# $a->[1][0]{_prop}{result}{_prop}{x} = $a->[1][0]{_prop}{args}{_value_prop}{x};
# $a->[1][0]{_prop}{summary} = $a->[1][0]{_prop}{args}{_value_prop}{summary};
# $a->[1][0]{_prop}{tags} = $a->[1][0]{_prop}{args}{_value_prop}{tags};
# $a->[1][0]{_prop}{v} = $a->[1][0]{_prop}{args}{_value_prop}{v};
# $a->[1][0]{_prop}{x} = $a->[1][0]{_prop}{args}{_value_prop}{x};
# $a;
#};
#
#1;
#
#__END__
#
### Sah/SchemaR/rinci/meta.pm ###
#package Sah::SchemaR::rinci::meta;
#
#our $DATE = '2016-12-26';
#our $VERSION = '1.1.82.2';
#
#our $rschema = do {
# my $a = [
# "hash",
# [
# {
# _prop => {
# caption => {},
# default_lang => {},
# defhash_v => {},
# description => {},
# entity_date => {},
# entity_v => {},
# links => {
# _elem_prop => {
# caption => 'fix',
# default_lang => 'fix',
# defhash_v => 'fix',
# description => 'fix',
# name => {},
# summary => {},
# tags => {},
# url => {},
# v => {},
# x => {},
# },
# },
# name => 'fix',
# summary => 'fix',
# tags => 'fix',
# v => 'fix',
# x => 'fix',
# },
# _ver => 1.1,
# summary => "Rinci metadata",
# },
# ],
# ["hash"],
# ];
# $a->[1][0]{_prop}{links}{_elem_prop}{caption} = $a->[1][0]{_prop}{caption};
# $a->[1][0]{_prop}{links}{_elem_prop}{default_lang} = $a->[1][0]{_prop}{default_lang};
# $a->[1][0]{_prop}{links}{_elem_prop}{defhash_v} = $a->[1][0]{_prop}{defhash_v};
# $a->[1][0]{_prop}{links}{_elem_prop}{description} = $a->[1][0]{_prop}{description};
# $a->[1][0]{_prop}{name} = $a->[1][0]{_prop}{links}{_elem_prop}{name};
# $a->[1][0]{_prop}{summary} = $a->[1][0]{_prop}{links}{_elem_prop}{summary};
# $a->[1][0]{_prop}{tags} = $a->[1][0]{_prop}{links}{_elem_prop}{tags};
# $a->[1][0]{_prop}{v} = $a->[1][0]{_prop}{links}{_elem_prop}{v};
# $a->[1][0]{_prop}{x} = $a->[1][0]{_prop}{links}{_elem_prop}{x};
# $a;
#};
#
#1;
#
#__END__
#
### Sah/SchemaR/rinci/result_meta.pm ###
#package Sah::SchemaR::rinci::result_meta;
#
#our $DATE = '2016-12-26';
#our $VERSION = '1.1.82.2';
#
#our $rschema = [
# "hash",
# [
# {
# _prop => {
# caption => {},
# cmdline => {},
# default_lang => {},
# defhash_v => {},
# description => {},
# func => {},
# len => {},
# logs => {},
# name => {},
# part_len => {},
# part_start => {},
# perm_err => {},
# prev => {},
# results => {},
# stream => {},
# summary => {},
# tags => {},
# v => {},
# x => {},
# },
# _ver => 1.1,
# summary => "Rinci envelope result metadata",
# },
# ],
# ["hash"],
#];
#
#1;
#
#__END__
#
### Sah/Schemas/Rinci.pm ###
#package Sah::Schemas::Rinci;
#
#our $DATE = '2016-12-26';
#our $VERSION = '1.1.82.2';
#
#1;
#
#__END__
#
### String/LineNumber.pm ###
#package String::LineNumber;
#
#our $DATE = '2014-12-10';
#our $VERSION = '0.01';
#
#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;
#
#__END__
#
### String/PerlQuote.pm ###
#package String::PerlQuote;
#
#our $DATE = '2016-10-07';
#our $VERSION = '0.02';
#
#use 5.010001;
#use strict;
#use warnings;
#
#use Exporter;
#our @ISA = qw(Exporter);
#our @EXPORT_OK = qw(
# single_quote
# double_quote
# );
#
#my %esc = (
# "\a" => "\\a",
# "\b" => "\\b",
# "\t" => "\\t",
# "\n" => "\\n",
# "\f" => "\\f",
# "\r" => "\\r",
# "\e" => "\\e",
#);
#
#sub double_quote {
# local($_) = $_[0];
# s/([\\\"\@\$])/\\$1/g;
# return qq("$_") unless /[^\040-\176]/;
#
# s/([\a\b\t\n\f\r\e])/$esc{$1}/g;
#
# 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("$_");
#}
#
#sub single_quote {
# local($_) = $_[0];
# s/([\\'])/\\$1/g;
# return qq('$_');
#}
#1;
#
#__END__
#
### String/Wildcard/Bash.pm ###
#package String::Wildcard::Bash;
#
#use 5.010001;
#use strict;
#use warnings;
#
#our $VERSION = '0.03';
#
#use Exporter;
#our @ISA = qw(Exporter);
#our @EXPORT_OK = qw(
# $RE_WILDCARD_BASH
# contains_wildcard
# convert_wildcard_to_sql
# );
#
#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;
#
#__END__
#
### YAML/Old.pm ###
#package YAML::Old;
#our $VERSION = '1.23';
#
#use YAML::Old::Mo;
#
#use Exporter;
#push @YAML::Old::ISA, 'Exporter';
#our @EXPORT = qw{ Dump Load };
#our @EXPORT_OK = qw{ freeze thaw DumpFile LoadFile Bless Blessed };
#our (
# $UseCode, $DumpCode, $LoadCode,
# $SpecVersion,
# $UseHeader, $UseVersion, $UseBlock, $UseFold, $UseAliases,
# $Indent, $SortKeys, $Preserve,
# $AnchorPrefix, $CompressSeries, $InlineSeries, $Purity,
# $Stringify, $Numify
#);
#
#
#use YAML::Old::Node;
#use Scalar::Util qw/ openhandle /;
#
#use constant VALUE => "\x07YAML\x07VALUE\x07";
#
#has dumper_class => default => sub {'YAML::Old::Dumper'};
#has loader_class => default => sub {'YAML::Old::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::Old->new;
# $yaml->dumper_class($YAML::DumperClass)
# if $YAML::DumperClass;
# return $yaml->dumper_object->dump(@_);
#}
#
#sub Load {
# my $yaml = YAML::Old->new;
# $yaml->loader_class($YAML::LoaderClass)
# if $YAML::LoaderClass;
# return $yaml->loader_object->load(@_);
#}
#
#{
# no warnings 'once';
# *freeze = \ &Dump;
# *thaw = \ &Load;
#}
#
#sub DumpFile {
# my $OUT;
# my $filename = shift;
# if (openhandle $filename) {
# $OUT = $filename;
# }
# else {
# my $mode = '>';
# if ($filename =~ /^\s*(>{1,2})\s*(.*)$/) {
# ($mode, $filename) = ($1, $2);
# }
# open $OUT, $mode, $filename
# or YAML::Old::Mo::Object->die('YAML_DUMP_ERR_FILE_OUTPUT', $filename, "$!");
# }
# binmode $OUT, ':utf8';
# local $/ = "\n";
# print $OUT Dump(@_);
# unless (ref $filename eq 'GLOB') {
# close $OUT
# or do {
# my $errsav = $!;
# YAML::Old::Mo::Object->die('YAML_DUMP_ERR_FILE_OUTPUT_CLOSE', $filename, $errsav);
# }
# }
#}
#
#sub LoadFile {
# my $IN;
# my $filename = shift;
# if (openhandle $filename) {
# $IN = $filename;
# }
# else {
# open $IN, '<', $filename
# or YAML::Old::Mo::Object->die('YAML_LOAD_ERR_FILE_INPUT', $filename, "$!");
# }
# binmode $IN, ':utf8';
# 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::Old::Dumper::Base;
# YAML::Old::Dumper::Base::bless($global, @_)
#}
#sub Blessed {
# require YAML::Old::Dumper::Base;
# YAML::Old::Dumper::Base::blessed($global, @_)
#}
#sub global_object { $global }
#
#1;
### YAML/Old/Dumper.pm ###
#package YAML::Old::Dumper;
#
#use YAML::Old::Mo;
#extends 'YAML::Old::Dumper::Base';
#
#use YAML::Old::Dumper::Base;
#use YAML::Old::Node;
#use YAML::Old::Types;
#use Scalar::Util qw();
#use B ();
#use Carp ();
#
#use constant KEY => 3;
#use constant BLESSED => 4;
#use constant FROMARRAY => 5;
#use constant VALUE => "\x07YAML\x07VALUE\x07";
#
#my $ESCAPE_CHAR = '[\\x00-\\x08\\x0b-\\x0d\\x0e-\\x1f]';
#my $LIT_CHAR = '|';
#
#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;
#}
#
#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;
# $self->headless(1);
# return;
# }
# $self->{stream} .= '---';
# if ($self->use_version) {
# }
#}
#
#sub _prewalk {
# my $self = shift;
# my $stringify = $self->stringify;
# my ($class, $type, $node_id) = $self->node_info(\$_[0], $stringify);
#
# if ($type eq 'GLOB') {
# $self->transferred->{$node_id} =
# YAML::Old::Type::glob->yaml_dump($_[0]);
# $self->_prewalk($self->transferred->{$node_id});
# return;
# }
#
# if (ref($_[0]) eq 'Regexp') {
# return;
# }
#
# if (not ref $_[0]) {
# $self->{id_refcnt}{$node_id}++ if $self->purity;
# return;
# }
#
# my $value = $_[0];
# ($class, $type, $node_id) = $self->node_info($value, $stringify);
#
# return if (ref($value) and not $type);
#
# 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;
# }
#
# if ($type eq 'CODE') {
# $self->transferred->{$node_id} = 'placeholder';
# YAML::Old::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;
# }
#
# if (defined $class) {
# if ($value->can('yaml_dump')) {
# $value = $value->yaml_dump;
# }
# elsif ($type eq 'SCALAR') {
# $self->transferred->{$node_id} = 'placeholder';
# YAML::Old::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::Old::Type::blessed->yaml_dump($value);
# }
# $self->transferred->{$node_id} = $value;
# (undef, $type, $node_id) = $self->node_info($value, $stringify);
# }
#
# require YAML::Old;
# if (defined YAML::Old->global_object()->{blessed_map}{$node_id}) {
# $value = YAML::Old->global_object()->{blessed_map}{$node_id};
# $self->transferred->{$node_id} = $value;
# ($class, $type, $node_id) = $self->node_info($value, $stringify);
# $self->_prewalk($value);
# return;
# }
#
# if ($type eq 'REF' or $type eq 'SCALAR') {
# $value = YAML::Old::Type::ref->yaml_dump($value);
# $self->transferred->{$node_id} = $value;
# (undef, $type, $node_id) = $self->node_info($value, $stringify);
# }
#
# elsif ($type eq 'GLOB') {
# my $ref_ynode = $self->transferred->{$node_id} =
# YAML::Old::Type::ref->yaml_dump($value);
#
# my $glob_ynode = $ref_ynode->{&VALUE} =
# YAML::Old::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;
# }
#
# return if ++($self->{id_refcnt}{$node_id}) > 1;
#
# if ($type eq 'HASH') {
# $self->_prewalk($value->{$_})
# for keys %{$value};
# return;
# }
# elsif ($type eq 'ARRAY') {
# $self->_prewalk($_)
# for @{$value};
# return;
# }
#
# $self->warn(<<"...");
#YAML::Old::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;
#}
#
#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")
# 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");
#}
#
#sub _emit_mapping {
# my $self = shift;
# my ($value, $tag, $node_id, $context) = @_;
# $self->{stream} .= " !$tag" if $tag;
#
# my $empty_hash = not(eval {keys %$value});
# $self->warn('YAML_EMIT_WARN_KEYS', $@) if $@;
# return ($self->{stream} .= " {}\n") if $empty_hash;
#
# 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;
# }
# 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;
# }
# 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}--;
#}
#
#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));
#
# 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}--;
#}
#
#sub _emit_key {
# my $self = shift;
# my ($value, $context) = @_;
# $self->{stream} .= ' ' x $self->offset->[$self->level]
# unless $context == FROMARRAY;
# $self->_emit_str($value, KEY);
#}
#
#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 '', @_;
#}
#
#sub _emit_str {
# my $self = shift;
# my $type = $_[1] || 0;
#
# $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::Old] \$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;
# 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]);
#}
#
#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]);
# 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);
#}
#
#sub _emit_plain {
# my $self = shift;
# $self->{stream} .= defined $_[0] ? $_[0] : '~';
#}
#
#sub _emit_double {
# my $self = shift;
# (my $escaped = $self->escape($_[0])) =~ s/"/\\"/g;
# $self->{stream} .= qq{"$escaped"};
#}
#
#sub _emit_single {
# my $self = shift;
# my $item = shift;
# $item =~ s{'}{''}g;
# $self->{stream} .= "'$item'";
#}
#
#
#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;
#}
#
#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
# );
#
#sub escape {
# my $self = shift;
# my ($text) = @_;
# $text =~ s/\\/\\\\/g;
# $text =~ s/([\x00-\x1f])/$escapes[ord($1)]/ge;
# return $text;
#}
#
#1;
### YAML/Old/Dumper/Base.pm ###
#package YAML::Old::Dumper::Base;
#
#use YAML::Old::Mo;
#
#use YAML::Old::Node;
#
#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};
#
#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 {{}};
#
#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::Old::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::Old::Mo::Object->node_info($ref);
# if (not defined $blessing) {
# $ynode = YAML::Old::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/Old/Error.pm ###
#package YAML::Old::Error;
#
#use YAML::Old::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::Old ' . $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+//;s/\\n/\n/;$_} 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::Old::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_FILE_OUTPUT_CLOSE
# Error closing %s:\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 '%s' 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::Old::Warning;
#
#our @ISA = 'YAML::Old::Error';
#
#1;
### YAML/Old/Loader.pm ###
#package YAML::Old::Loader;
#
#use YAML::Old::Mo;
#extends 'YAML::Old::Loader::Base';
#
#use YAML::Old::Loader::Base;
#use YAML::Old::Types;
#use YAML::Old::Node;
#
#use constant LEAF => 1;
#use constant COLLECTION => 2;
#use constant VALUE => "\x07YAML\x07VALUE\x07";
#use constant COMMENT => "\x07YAML\x07COMMENT\x07";
#
#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();
#}
#
#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);
# $self->_parse_throwaway_comments();
# $self->document(0);
# $self->documents([]);
# if (not $self->eos) {
# if ($self->lines->[0] !~ /^---(\s|$)/) {
# unshift @{$self->lines}, '---';
# $self->{line}--;
# }
# }
#
# 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];
#}
#
#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') {
# 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;
#}
#
#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);
#}
#
#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 || ''));
#
#
# 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::Old::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);
# }
# }
# elsif ($YAML::TagClass->{$explicit} ||
# $explicit =~ m{^perl/(\@|\$)?([a-zA-Z](\w|::)+)$}
# ) {
# $class = $YAML::TagClass->{$explicit} || $2;
# if ($class->can('yaml_load')) {
# require YAML::Old::Node;
# return $class->yaml_load(YAML::Old::Node->new($node, $explicit));
# }
# else {
# if (ref $node) {
# return CORE::bless $node, $class;
# }
# else {
# return CORE::bless \$node, $class;
# }
# }
# }
# elsif (ref $node) {
# require YAML::Old::Node;
# return YAML::Old::Node->new($node, $explicit);
# }
# else {
# return $node;
# }
#}
#
#sub _parse_mapping {
# my $self = shift;
# my ($anchor) = @_;
# my $mapping = $self->preserve ? YAML::Old::Node->new({}) : {};
# $self->anchor2node->{$anchor} = $mapping;
# my $key;
# while (not $self->done and $self->indent == $self->offset->[$self->level]) {
# if ($self->{content} =~ s/^\?\s*//) {
# $self->preface($self->content);
# $self->_parse_next_line(COLLECTION);
# $key = $self->_parse_node();
# $key = "$key";
# }
# elsif ($self->{content} =~ s/^\=\s*//) {
# $key = VALUE;
# }
# elsif ($self->{content} =~ s/^\=\s*//) {
# $key = COMMENT;
# }
# 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', $key);
# }
# else {
# $mapping->{$key} = $value;
# }
# }
# return $mapping;
#}
#
#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');
# }
#
# my $preface = $self->preface;
# if ( $preface =~ /^ (\s*) ( \w .*? \: (?:\ |$).*) $/x or
# $preface =~ /^ (\s*) ((') (?:''|[^'])*? ' \s* \: (?:\ |$).*) $/x or
# $preface =~ /^ (\s*) ((") (?:\\\\|[^"])*? " \s* \: (?:\ |$).*) $/x
# ) {
# $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;
#}
#
#sub _parse_inline {
# my $self = shift;
# my ($top, $top_implicit, $top_explicit) = (@_, '', '', '');
# $self->{inline} =~ s/^\s*(.*)\s*$/$1/;
# 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 ($self->numify and defined $node and not ref $node and length $node
# and $node =~ m/\A-?(?:0|[1-9][0-9]*)?(?:\.[0-9]*)?(?:[eE][+-]?[0-9]+)?\z/) {
# $node += 0;
# }
# }
# 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;
#}
#
#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*\}\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', $key);
# }
# else {
# $node->{$key} = $value;
# }
# next if $self->inline =~ /^\s*\}/;
# $self->die('YAML_PARSE_ERR_INLINE_MAP')
# unless $self->{inline} =~ s/^\,\s*//;
# }
# return $node;
#}
#
#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*\]\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;
#}
#
#sub _parse_inline_double_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_DOUBLE');
# }
# return $node;
#}
#
#
#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;
#}
#
#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);
#}
#
#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;
#}
#
#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;
#}
#
#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});
#}
#
#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});
# if ($self->eos) {
# $self->offset->[$level + 1] = $offset + 1;
# return;
# }
# $self->{line}++;
#
# 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 {
# 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];
# }
# 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;
#}
#
#
#my %unescapes = (
# 0 => "\x00",
# a => "\x07",
# t => "\x09",
# n => "\x0a",
# 'v' => "\x0b",
# f => "\x0c",
# r => "\x0d",
# e => "\x1b",
# '\\' => '\\',
# );
#
#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/Old/Loader/Base.pm ###
#package YAML::Old::Loader::Base;
#
#use YAML::Old::Mo;
#
#has load_code => default => sub {0};
#has preserve => 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 {''};
#has numify => default => sub {0};
#
#sub set_global_options {
# my $self = shift;
# $self->load_code($YAML::LoadCode || $YAML::UseCode)
# if defined $YAML::LoadCode or defined $YAML::UseCode;
# $self->preserve($YAML::Preserve) if defined $YAML::Preserve;
# $self->numify($YAML::Numify) if defined $YAML::Numify;
#}
#
#sub load {
# die 'load() not implemented in this class.';
#}
#
#1;
### YAML/Old/Marshall.pm ###
#use strict; use warnings;
#package YAML::Old::Marshall;
#
#use YAML::Old::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::Old::Node->new(@_);
#}
#
#sub yaml_ynode {
# shift;
# YAML::Old::Node::ynode(@_);
#}
#
#1;
### YAML/Old/Mo.pm ###
#package YAML::Old::Mo;
#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};*{$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->(@_)}}};*{$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->(@_)}}};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);
#};
#
#*{$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::Old::Error;
#
# my $code = shift || 'unknown error';
# my $error = YAML::Old::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/Old/Node.pm ###
#use strict; use warnings;
#package YAML::Old::Node;
#
#use YAML::Old::Tag;
#require YAML::Old::Mo;
#
#use Exporter;
#our @ISA = qw(Exporter YAML::Old::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::Old::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::Old::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::Old::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::Old::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::Old::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";
#}
#
#*STORESIZE = *POP = *PUSH = *SHIFT = *UNSHIFT = *SPLICE = *DELETE = *EXISTS =
#*STORESIZE = *POP = *PUSH = *SHIFT = *UNSHIFT = *SPLICE = *DELETE = *EXISTS =
#*undone;
#
#package yaml_mapping;
#
#@yaml_mapping::ISA = qw(YAML::Old::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/Old/Tag.pm ###
#use strict; use warnings;
#package YAML::Old::Tag;
#
#use overload '""' => sub { ${$_[0]} };
#
#sub new {
# my ($class, $self) = @_;
# bless \$self, $class
#}
#
#sub short {
# ${$_[0]}
#}
#
#sub canonical {
# ${$_[0]}
#}
#
#1;
### YAML/Old/Types.pm ###
#package YAML::Old::Types;
#
#use YAML::Old::Mo;
#use YAML::Old::Node;
#
#package YAML::Old::Type::blessed;
#
#use YAML::Old::Mo;
#
#sub yaml_dump {
# my $self = shift;
# my ($value) = @_;
# my ($class, $type) = YAML::Old::Mo::Object->node_info($value);
# no strict 'refs';
# my $kind = lc($type) . ':';
# my $tag = ${$class . '::ClassTag'} ||
# "!perl/$kind$class";
# if ($type eq 'REF') {
# YAML::Old::Node->new(
# {(&YAML::Old::VALUE, ${$_[0]})}, $tag
# );
# }
# elsif ($type eq 'SCALAR') {
# $_[1] = $$value;
# YAML::Old::Node->new($_[1], $tag);
# }
# elsif ($type eq 'GLOB') {
# return YAML::Old::Type::glob->yaml_dump($value, $tag);
# } else {
# YAML::Old::Node->new($value, $tag);
# }
#}
#
#package YAML::Old::Type::undef;
#
#sub yaml_dump {
# my $self = shift;
#}
#
#sub yaml_load {
# my $self = shift;
#}
#
#package YAML::Old::Type::glob;
#
#sub yaml_dump {
# my $self = shift;
# my $tag = pop @_ if 2==@_;
#
# $tag = '!perl/glob:' unless defined $tag;
# my $ynode = YAML::Old::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::Old::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::Old::Type::code;
#
#my $dummy_warned = 0;
#my $default = '{ "DUMMY" }';
#
#sub yaml_dump {
# my $self = shift;
# my $code;
# my ($dumpflag, $value) = @_;
# my ($class, $type) = YAML::Old::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 { require B::Deparse };
# return if $@;
# my $deparse = B::Deparse->new();
# eval {
# local $^W = 0;
# $code = $deparse->coderef2text($value);
# };
# if ($@) {
# warn YAML::Old::YAML_DUMP_WARN_DEPARSE_FAILED() if $^W;
# $code = $default;
# }
# bless $value, $class if $class;
# chomp $code;
# $code .= "\n";
# }
# $_[2] = $code;
# YAML::Old::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::Old::Type::ref;
#
#sub yaml_dump {
# my $self = shift;
# YAML::Old::Node->new({(&YAML::Old::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::Old::VALUE};
# return \$node->{&YAML::Old::VALUE};
#}
#
#package YAML::Old::Type::regexp;
#
#sub yaml_dump {
# die "YAML::Old::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;