1package Test2::API::Instance; 2use strict; 3use warnings; 4 5our $VERSION = '1.302199'; 6 7our @CARP_NOT = qw/Test2::API Test2::API::Instance Test2::IPC::Driver Test2::Formatter/; 8use Carp qw/confess carp/; 9use Scalar::Util qw/reftype/; 10 11use Test2::Util qw/get_tid USE_THREADS CAN_FORK pkg_to_file try CAN_SIGSYS/; 12 13use Test2::EventFacet::Trace(); 14use Test2::API::Stack(); 15 16use Test2::Util::HashBase qw{ 17 _pid _tid 18 no_wait 19 finalized loaded 20 ipc stack formatter 21 contexts 22 23 add_uuid_via 24 25 -preload 26 27 ipc_disabled 28 ipc_polling 29 ipc_drivers 30 ipc_timeout 31 formatters 32 33 exit_callbacks 34 post_load_callbacks 35 context_acquire_callbacks 36 context_init_callbacks 37 context_release_callbacks 38 pre_subtest_callbacks 39 40 trace_stamps 41}; 42 43sub DEFAULT_IPC_TIMEOUT() { 30 } 44 45sub test2_enable_trace_stamps { $_[0]->{+TRACE_STAMPS} = 1 } 46sub test2_disable_trace_stamps { $_[0]->{+TRACE_STAMPS} = 0 } 47sub test2_trace_stamps_enabled { $_[0]->{+TRACE_STAMPS} } 48 49sub pid { $_[0]->{+_PID} } 50sub tid { $_[0]->{+_TID} } 51 52# Wrap around the getters that should call _finalize. 53BEGIN { 54 for my $finalizer (IPC, FORMATTER) { 55 my $orig = __PACKAGE__->can($finalizer); 56 my $new = sub { 57 my $self = shift; 58 $self->_finalize unless $self->{+FINALIZED}; 59 $self->$orig; 60 }; 61 62 no strict 'refs'; 63 no warnings 'redefine'; 64 *{$finalizer} = $new; 65 } 66} 67 68sub has_ipc { !!$_[0]->{+IPC} } 69 70sub import { 71 my $class = shift; 72 return unless @_; 73 my ($ref) = @_; 74 $$ref = $class->new; 75} 76 77sub init { $_[0]->reset } 78 79sub start_preload { 80 my $self = shift; 81 82 confess "preload cannot be started, Test2::API has already been initialized" 83 if $self->{+FINALIZED} || $self->{+LOADED}; 84 85 return $self->{+PRELOAD} = 1; 86} 87 88sub stop_preload { 89 my $self = shift; 90 91 return 0 unless $self->{+PRELOAD}; 92 $self->{+PRELOAD} = 0; 93 94 $self->post_preload_reset(); 95 96 return 1; 97} 98 99sub post_preload_reset { 100 my $self = shift; 101 102 delete $self->{+_PID}; 103 delete $self->{+_TID}; 104 105 $self->{+ADD_UUID_VIA} = undef unless exists $self->{+ADD_UUID_VIA}; 106 107 $self->{+CONTEXTS} = {}; 108 109 $self->{+FORMATTERS} = []; 110 111 $self->{+FINALIZED} = undef; 112 $self->{+IPC} = undef; 113 $self->{+IPC_DISABLED} = $ENV{T2_NO_IPC} ? 1 : 0; 114 115 $self->{+IPC_TIMEOUT} = DEFAULT_IPC_TIMEOUT() unless defined $self->{+IPC_TIMEOUT}; 116 117 $self->{+LOADED} = 0; 118 119 $self->{+STACK} ||= Test2::API::Stack->new; 120} 121 122sub reset { 123 my $self = shift; 124 125 delete $self->{+_PID}; 126 delete $self->{+_TID}; 127 128 $self->{+TRACE_STAMPS} = $ENV{T2_TRACE_STAMPS} || 0; 129 130 $self->{+ADD_UUID_VIA} = undef; 131 132 $self->{+CONTEXTS} = {}; 133 134 $self->{+IPC_DRIVERS} = []; 135 $self->{+IPC_POLLING} = undef; 136 137 $self->{+FORMATTERS} = []; 138 $self->{+FORMATTER} = undef; 139 140 $self->{+FINALIZED} = undef; 141 $self->{+IPC} = undef; 142 $self->{+IPC_DISABLED} = $ENV{T2_NO_IPC} ? 1 : 0; 143 144 $self->{+IPC_TIMEOUT} = DEFAULT_IPC_TIMEOUT() unless defined $self->{+IPC_TIMEOUT}; 145 146 $self->{+NO_WAIT} = 0; 147 $self->{+LOADED} = 0; 148 149 $self->{+EXIT_CALLBACKS} = []; 150 $self->{+POST_LOAD_CALLBACKS} = []; 151 $self->{+CONTEXT_ACQUIRE_CALLBACKS} = []; 152 $self->{+CONTEXT_INIT_CALLBACKS} = []; 153 $self->{+CONTEXT_RELEASE_CALLBACKS} = []; 154 $self->{+PRE_SUBTEST_CALLBACKS} = []; 155 156 $self->{+STACK} = Test2::API::Stack->new; 157} 158 159sub _finalize { 160 my $self = shift; 161 my ($caller) = @_; 162 $caller ||= [caller(1)]; 163 164 confess "Attempt to initialize Test2::API during preload" 165 if $self->{+PRELOAD}; 166 167 $self->{+FINALIZED} = $caller; 168 169 $self->{+_PID} = $$ unless defined $self->{+_PID}; 170 $self->{+_TID} = get_tid() unless defined $self->{+_TID}; 171 172 unless ($self->{+FORMATTER}) { 173 my ($formatter, $source); 174 if ($ENV{T2_FORMATTER}) { 175 $source = "set by the 'T2_FORMATTER' environment variable"; 176 177 if ($ENV{T2_FORMATTER} =~ m/^(\+)?(.*)$/) { 178 $formatter = $1 ? $2 : "Test2::Formatter::$2" 179 } 180 else { 181 $formatter = ''; 182 } 183 } 184 elsif (@{$self->{+FORMATTERS}}) { 185 ($formatter) = @{$self->{+FORMATTERS}}; 186 $source = "Most recently added"; 187 } 188 else { 189 $formatter = 'Test2::Formatter::TAP'; 190 $source = 'default formatter'; 191 } 192 193 unless (ref($formatter) || $formatter->can('write')) { 194 my $file = pkg_to_file($formatter); 195 my ($ok, $err) = try { require $file }; 196 unless ($ok) { 197 my $line = "* COULD NOT LOAD FORMATTER '$formatter' ($source) *"; 198 my $border = '*' x length($line); 199 die "\n\n $border\n $line\n $border\n\n$err"; 200 } 201 } 202 203 $self->{+FORMATTER} = $formatter; 204 } 205 206 # Turn on IPC if threads are on, drivers are registered, or the Test2::IPC 207 # module is loaded. 208 return if $self->{+IPC_DISABLED}; 209 return unless USE_THREADS || $INC{'Test2/IPC.pm'} || @{$self->{+IPC_DRIVERS}}; 210 211 # Turn on polling by default, people expect it. 212 $self->enable_ipc_polling; 213 214 unless (@{$self->{+IPC_DRIVERS}}) { 215 my ($ok, $error) = try { require Test2::IPC::Driver::Files }; 216 die $error unless $ok; 217 push @{$self->{+IPC_DRIVERS}} => 'Test2::IPC::Driver::Files'; 218 } 219 220 for my $driver (@{$self->{+IPC_DRIVERS}}) { 221 next unless $driver->can('is_viable') && $driver->is_viable; 222 $self->{+IPC} = $driver->new or next; 223 return; 224 } 225 226 die "IPC has been requested, but no viable drivers were found. Aborting...\n"; 227} 228 229sub formatter_set { $_[0]->{+FORMATTER} ? 1 : 0 } 230 231sub add_formatter { 232 my $self = shift; 233 my ($formatter) = @_; 234 unshift @{$self->{+FORMATTERS}} => $formatter; 235 236 return unless $self->{+FINALIZED}; 237 238 # Why is the @CARP_NOT entry not enough? 239 local %Carp::Internal = %Carp::Internal; 240 $Carp::Internal{'Test2::Formatter'} = 1; 241 242 carp "Formatter $formatter loaded too late to be used as the global formatter"; 243} 244 245sub add_context_acquire_callback { 246 my $self = shift; 247 my ($code) = @_; 248 249 my $rtype = reftype($code) || ""; 250 251 confess "Context-acquire callbacks must be coderefs" 252 unless $code && $rtype eq 'CODE'; 253 254 push @{$self->{+CONTEXT_ACQUIRE_CALLBACKS}} => $code; 255} 256 257sub add_context_init_callback { 258 my $self = shift; 259 my ($code) = @_; 260 261 my $rtype = reftype($code) || ""; 262 263 confess "Context-init callbacks must be coderefs" 264 unless $code && $rtype eq 'CODE'; 265 266 push @{$self->{+CONTEXT_INIT_CALLBACKS}} => $code; 267} 268 269sub add_context_release_callback { 270 my $self = shift; 271 my ($code) = @_; 272 273 my $rtype = reftype($code) || ""; 274 275 confess "Context-release callbacks must be coderefs" 276 unless $code && $rtype eq 'CODE'; 277 278 push @{$self->{+CONTEXT_RELEASE_CALLBACKS}} => $code; 279} 280 281sub add_post_load_callback { 282 my $self = shift; 283 my ($code) = @_; 284 285 my $rtype = reftype($code) || ""; 286 287 confess "Post-load callbacks must be coderefs" 288 unless $code && $rtype eq 'CODE'; 289 290 push @{$self->{+POST_LOAD_CALLBACKS}} => $code; 291 $code->() if $self->{+LOADED}; 292} 293 294sub add_pre_subtest_callback { 295 my $self = shift; 296 my ($code) = @_; 297 298 my $rtype = reftype($code) || ""; 299 300 confess "Pre-subtest callbacks must be coderefs" 301 unless $code && $rtype eq 'CODE'; 302 303 push @{$self->{+PRE_SUBTEST_CALLBACKS}} => $code; 304} 305 306sub load { 307 my $self = shift; 308 unless ($self->{+LOADED}) { 309 confess "Attempt to initialize Test2::API during preload" 310 if $self->{+PRELOAD}; 311 312 $self->{+_PID} = $$ unless defined $self->{+_PID}; 313 $self->{+_TID} = get_tid() unless defined $self->{+_TID}; 314 315 # This is for https://github.com/Test-More/test-more/issues/16 316 # and https://rt.perl.org/Public/Bug/Display.html?id=127774 317 # END blocks run in reverse order. This insures the END block is loaded 318 # as late as possible. It will not solve all cases, but it helps. 319 eval "END { Test2::API::test2_set_is_end() }; 1" or die $@; 320 321 $self->{+LOADED} = 1; 322 $_->() for @{$self->{+POST_LOAD_CALLBACKS}}; 323 } 324 return $self->{+LOADED}; 325} 326 327sub add_exit_callback { 328 my $self = shift; 329 my ($code) = @_; 330 my $rtype = reftype($code) || ""; 331 332 confess "End callbacks must be coderefs" 333 unless $code && $rtype eq 'CODE'; 334 335 push @{$self->{+EXIT_CALLBACKS}} => $code; 336} 337 338sub ipc_disable { 339 my $self = shift; 340 341 confess "Attempt to disable IPC after it has been initialized" 342 if $self->{+IPC}; 343 344 $self->{+IPC_DISABLED} = 1; 345} 346 347sub add_ipc_driver { 348 my $self = shift; 349 my ($driver) = @_; 350 unshift @{$self->{+IPC_DRIVERS}} => $driver; 351 352 return unless $self->{+FINALIZED}; 353 354 # Why is the @CARP_NOT entry not enough? 355 local %Carp::Internal = %Carp::Internal; 356 $Carp::Internal{'Test2::IPC::Driver'} = 1; 357 358 carp "IPC driver $driver loaded too late to be used as the global ipc driver"; 359} 360 361sub enable_ipc_polling { 362 my $self = shift; 363 364 $self->{+_PID} = $$ unless defined $self->{+_PID}; 365 $self->{+_TID} = get_tid() unless defined $self->{+_TID}; 366 367 $self->add_context_init_callback( 368 # This is called every time a context is created, it needs to be fast. 369 # $_[0] is a context object 370 sub { 371 return unless $self->{+IPC_POLLING}; 372 return unless $self->{+IPC}; 373 return unless $self->{+IPC}->pending(); 374 return $_[0]->{hub}->cull; 375 } 376 ) unless defined $self->ipc_polling; 377 378 $self->set_ipc_polling(1); 379} 380 381sub get_ipc_pending { 382 my $self = shift; 383 return -1 unless $self->{+IPC}; 384 $self->{+IPC}->pending(); 385} 386 387sub _check_pid { 388 my $self = shift; 389 my ($pid) = @_; 390 return kill(0, $pid); 391} 392 393sub set_ipc_pending { 394 my $self = shift; 395 return unless $self->{+IPC}; 396 my ($val) = @_; 397 398 confess "value is required for set_ipc_pending" 399 unless $val; 400 401 $self->{+IPC}->set_pending($val); 402} 403 404sub disable_ipc_polling { 405 my $self = shift; 406 return unless defined $self->{+IPC_POLLING}; 407 $self->{+IPC_POLLING} = 0; 408} 409 410sub _ipc_wait { 411 my ($timeout) = @_; 412 my $fail = 0; 413 414 $timeout = DEFAULT_IPC_TIMEOUT() unless defined $timeout; 415 416 my $ok = eval { 417 if (CAN_FORK) { 418 local $SIG{ALRM} = sub { die "Timeout waiting on child processes" }; 419 alarm $timeout; 420 421 while (1) { 422 my $pid = CORE::wait(); 423 my $err = $?; 424 last if $pid == -1; 425 next unless $err; 426 $fail++; 427 428 my $sig = $err & 127; 429 my $exit = $err >> 8; 430 warn "Process $pid did not exit cleanly (wstat: $err, exit: $exit, sig: $sig)\n"; 431 } 432 433 alarm 0; 434 } 435 436 if (USE_THREADS) { 437 my $start = time; 438 439 while (1) { 440 last unless threads->list(); 441 die "Timeout waiting on child thread" if time - $start >= $timeout; 442 sleep 1; 443 for my $t (threads->list) { 444 # threads older than 1.34 do not have this :-( 445 next if $t->can('is_joinable') && !$t->is_joinable; 446 $t->join; 447 # In older threads we cannot check if a thread had an error unless 448 # we control it and its return. 449 my $err = $t->can('error') ? $t->error : undef; 450 next unless $err; 451 my $tid = $t->tid(); 452 $fail++; 453 chomp($err); 454 warn "Thread $tid did not end cleanly: $err\n"; 455 } 456 } 457 } 458 459 1; 460 }; 461 my $error = $@; 462 463 return 0 if $ok && !$fail; 464 warn $error unless $ok; 465 return 255; 466} 467 468sub set_exit { 469 my $self = shift; 470 471 return if $self->{+PRELOAD}; 472 473 my $exit = $?; 474 my $new_exit = $exit; 475 476 if ($INC{'Test/Builder.pm'} && $Test::Builder::VERSION ne $Test2::API::VERSION) { 477 print STDERR <<" EOT"; 478 479******************************************************************************** 480* * 481* Test::Builder -- Test2::API version mismatch detected * 482* * 483******************************************************************************** 484 Test2::API Version: $Test2::API::VERSION 485Test::Builder Version: $Test::Builder::VERSION 486 487This is not a supported configuration, you will have problems. 488 489 EOT 490 } 491 492 for my $ctx (values %{$self->{+CONTEXTS}}) { 493 next unless $ctx; 494 495 next if $ctx->_aborted && ${$ctx->_aborted}; 496 497 # Only worry about contexts in this PID 498 my $trace = $ctx->trace || next; 499 next unless $trace->pid && $trace->pid == $$; 500 501 # Do not worry about contexts that have no hub 502 my $hub = $ctx->hub || next; 503 504 # Do not worry if the state came to a sudden end. 505 next if $hub->bailed_out; 506 next if defined $hub->skip_reason; 507 508 # now we worry 509 $trace->alert("context object was never released! This means a testing tool is behaving very badly"); 510 511 $exit = 255; 512 $new_exit = 255; 513 } 514 515 if (!defined($self->{+_PID}) or !defined($self->{+_TID}) or $self->{+_PID} != $$ or $self->{+_TID} != get_tid()) { 516 $? = $exit; 517 return; 518 } 519 520 my @hubs = $self->{+STACK} ? $self->{+STACK}->all : (); 521 522 if (@hubs and $self->{+IPC} and !$self->{+NO_WAIT}) { 523 local $?; 524 my %seen; 525 for my $hub (reverse @hubs) { 526 my $ipc = $hub->ipc or next; 527 next if $seen{$ipc}++; 528 $ipc->waiting(); 529 } 530 531 my $ipc_exit = _ipc_wait($self->{+IPC_TIMEOUT}); 532 $new_exit ||= $ipc_exit; 533 } 534 535 # None of this is necessary if we never got a root hub 536 if(my $root = shift @hubs) { 537 my $trace = Test2::EventFacet::Trace->new( 538 frame => [__PACKAGE__, __FILE__, 0, __PACKAGE__ . '::END'], 539 detail => __PACKAGE__ . ' END Block finalization', 540 ); 541 my $ctx = Test2::API::Context->new( 542 trace => $trace, 543 hub => $root, 544 ); 545 546 if (@hubs) { 547 $ctx->diag("Test ended with extra hubs on the stack!"); 548 $new_exit = 255; 549 } 550 551 unless ($root->no_ending) { 552 local $?; 553 $root->finalize($trace) unless $root->ended; 554 $_->($ctx, $exit, \$new_exit) for @{$self->{+EXIT_CALLBACKS}}; 555 $new_exit ||= $root->failed; 556 $new_exit ||= 255 unless $root->is_passing; 557 } 558 } 559 560 $new_exit = 255 if $new_exit > 255; 561 562 if ($new_exit && eval { require Test2::API::Breakage; 1 }) { 563 my @warn = Test2::API::Breakage->report(); 564 565 if (@warn) { 566 print STDERR "\nYou have loaded versions of test modules known to have problems with Test2.\nThis could explain some test failures.\n"; 567 print STDERR "$_\n" for @warn; 568 print STDERR "\n"; 569 } 570 } 571 572 $? = $new_exit; 573} 574 5751; 576 577__END__ 578 579=pod 580 581=encoding UTF-8 582 583=head1 NAME 584 585Test2::API::Instance - Object used by Test2::API under the hood 586 587=head1 DESCRIPTION 588 589This object encapsulates the global shared state tracked by 590L<Test2>. A single global instance of this package is stored (and 591obscured) by the L<Test2::API> package. 592 593There is no reason to directly use this package. This package is documented for 594completeness. This package can change, or go away completely at any time. 595Directly using, or monkeypatching this package is not supported in any way 596shape or form. 597 598=head1 SYNOPSIS 599 600 use Test2::API::Instance; 601 602 my $obj = Test2::API::Instance->new; 603 604=over 4 605 606=item $pid = $obj->pid 607 608PID of this instance. 609 610=item $obj->tid 611 612Thread ID of this instance. 613 614=item $obj->reset() 615 616Reset the object to defaults. 617 618=item $obj->load() 619 620Set the internal state to loaded, and run and stored post-load callbacks. 621 622=item $bool = $obj->loaded 623 624Check if the state is set to loaded. 625 626=item $arrayref = $obj->post_load_callbacks 627 628Get the post-load callbacks. 629 630=item $obj->add_post_load_callback(sub { ... }) 631 632Add a post-load callback. If C<load()> has already been called then the callback will 633be immediately executed. If C<load()> has not been called then the callback will be 634stored and executed later when C<load()> is called. 635 636=item $hashref = $obj->contexts() 637 638Get a hashref of all active contexts keyed by hub id. 639 640=item $arrayref = $obj->context_acquire_callbacks 641 642Get all context acquire callbacks. 643 644=item $arrayref = $obj->context_init_callbacks 645 646Get all context init callbacks. 647 648=item $arrayref = $obj->context_release_callbacks 649 650Get all context release callbacks. 651 652=item $arrayref = $obj->pre_subtest_callbacks 653 654Get all pre-subtest callbacks. 655 656=item $obj->add_context_init_callback(sub { ... }) 657 658Add a context init callback. Subs are called every time a context is created. Subs 659get the newly created context as their only argument. 660 661=item $obj->add_context_release_callback(sub { ... }) 662 663Add a context release callback. Subs are called every time a context is released. Subs 664get the released context as their only argument. These callbacks should not 665call release on the context. 666 667=item $obj->add_pre_subtest_callback(sub { ... }) 668 669Add a pre-subtest callback. Subs are called every time a subtest is 670going to be run. Subs get the subtest name, coderef, and any 671arguments. 672 673=item $obj->set_exit() 674 675This is intended to be called in an C<END { ... }> block. This will look at 676test state and set $?. This will also call any end callbacks, and wait on child 677processes/threads. 678 679=item $obj->set_ipc_pending($val) 680 681Tell other processes and threads there is a pending event. C<$val> should be a 682unique value no other thread/process will generate. 683 684B<Note:> This will also make the current process see a pending event. 685 686=item $pending = $obj->get_ipc_pending() 687 688This returns -1 if it is not possible to know. 689 690This returns 0 if there are no pending events. 691 692This returns 1 if there are pending events. 693 694=item $timeout = $obj->ipc_timeout; 695 696=item $obj->set_ipc_timeout($timeout); 697 698How long to wait for child processes and threads before aborting. 699 700=item $drivers = $obj->ipc_drivers 701 702Get the list of IPC drivers. 703 704=item $obj->add_ipc_driver($DRIVER_CLASS) 705 706Add an IPC driver to the list. The most recently added IPC driver will become 707the global one during initialization. If a driver is added after initialization 708has occurred a warning will be generated: 709 710 "IPC driver $driver loaded too late to be used as the global ipc driver" 711 712=item $bool = $obj->ipc_polling 713 714Check if polling is enabled. 715 716=item $obj->enable_ipc_polling 717 718Turn on polling. This will cull events from other processes and threads every 719time a context is created. 720 721=item $obj->disable_ipc_polling 722 723Turn off IPC polling. 724 725=item $bool = $obj->no_wait 726 727=item $bool = $obj->set_no_wait($bool) 728 729Get/Set no_wait. This option is used to turn off process/thread waiting at exit. 730 731=item $arrayref = $obj->exit_callbacks 732 733Get the exit callbacks. 734 735=item $obj->add_exit_callback(sub { ... }) 736 737Add an exit callback. This callback will be called by C<set_exit()>. 738 739=item $bool = $obj->finalized 740 741Check if the object is finalized. Finalization happens when either C<ipc()>, 742C<stack()>, or C<format()> are called on the object. Once finalization happens 743these fields are considered unchangeable (not enforced here, enforced by 744L<Test2>). 745 746=item $ipc = $obj->ipc 747 748Get the one true IPC instance. 749 750=item $obj->ipc_disable 751 752Turn IPC off 753 754=item $bool = $obj->ipc_disabled 755 756Check if IPC is disabled 757 758=item $stack = $obj->stack 759 760Get the one true hub stack. 761 762=item $formatter = $obj->formatter 763 764Get the global formatter. By default this is the C<'Test2::Formatter::TAP'> 765package. This could be any package that implements the C<write()> method. This 766can also be an instantiated object. 767 768=item $bool = $obj->formatter_set() 769 770Check if a formatter has been set. 771 772=item $obj->add_formatter($class) 773 774=item $obj->add_formatter($obj) 775 776Add a formatter. The most recently added formatter will become the global one 777during initialization. If a formatter is added after initialization has occurred 778a warning will be generated: 779 780 "Formatter $formatter loaded too late to be used as the global formatter" 781 782=item $obj->set_add_uuid_via(sub { ... }) 783 784=item $sub = $obj->add_uuid_via() 785 786This allows you to provide a UUID generator. If provided UUIDs will be attached 787to all events, hubs, and contexts. This is useful for storing, tracking, and 788linking these objects. 789 790The sub you provide should always return a unique identifier. Most things will 791expect a proper UUID string, however nothing in Test2::API enforces this. 792 793The sub will receive exactly 1 argument, the type of thing being tagged 794'context', 'hub', or 'event'. In the future additional things may be tagged, in 795which case new strings will be passed in. These are purely informative, you can 796(and usually should) ignore them. 797 798=back 799 800=head1 SOURCE 801 802The source code repository for Test2 can be found at 803L<https://github.com/Test-More/test-more/>. 804 805=head1 MAINTAINERS 806 807=over 4 808 809=item Chad Granum E<lt>exodist@cpan.orgE<gt> 810 811=back 812 813=head1 AUTHORS 814 815=over 4 816 817=item Chad Granum E<lt>exodist@cpan.orgE<gt> 818 819=back 820 821=head1 COPYRIGHT 822 823Copyright 2020 Chad Granum E<lt>exodist@cpan.orgE<gt>. 824 825This program is free software; you can redistribute it and/or 826modify it under the same terms as Perl itself. 827 828See L<https://dev.perl.org/licenses/> 829 830=cut 831