What is the correct Perl syntax for "use if, feature"?

Perl questions on StackOverflow

Published by FreonPSandoz on Monday 20 January 2025 20:06

The pragma use feature 'unicode_strings' is now strongly recommended.

How does one follow that recommendation in a library module that may be used by Perl versions older than v5.12? I tried several variations of

use if $PERL_VERSION >= v5.12, "feature 'unicode_strings'";

and I always get an error like

Can't locate feature 'unicode_strings'.pm in @INC.

The 'feature' pragma is listed in perlmodlib as a standard pragma, so I assume that it works with use if and that I simply don't have the correct syntax.

Symbolic references and Type::Tiny

Perl questions on StackOverflow

Published by simone on Monday 20 January 2025 19:22

(ADDITIONAL EDITS START HERE)

ntext: I'm trying to build a module that "guesses" data types by example.

It should work like this (adding Type::Tiny types is a role on top of plain Type::Guess):

use Type::Guess;
use Types::Standard qw( Int Num Str );
use strict;

$\ = "\n"; $, = "\t";

my @data = (
       [qw/a b cd efg hijk/],
       [qw/1 23 456 12000 12.0/],
       [qw/1.12345 23 456 12000 12.0/],
       [qw/-100% -13% 12.1%/],
       [23, +16, -100],
       [ "2022-12-30", "1923-12-30" ]
      );

for my $l (@data) {
    print Type::Guess->with_roles("+Tiny")->new($l->@*)->type->name
}

and if one needs custom types:

my $Date = Type::Tiny->new(
   name       => "Date",
   constraint => sub { /^\d{4,4}-\d{2,2}-\d{2,2}$/ },
   message    => sub { "$_ ain't a date" },
);


for my $l (@data) {
    print Type::Guess->with_roles("+Tiny")->new($l->@*, { types => [$Date, Int, Num, Str] })->type->name
}

since at the time of the first draft of this question I thought it'd be cool (I don't think so anymore, but hey) to do this:

for my $l (@data) {
    print Type::Guess->with_roles("+Tiny")->new($l->@*, { types => [qw(Date, Int, Num, Str)] })->type->name
}

(ADDITIONAL EDITS END HERE)

I am trying to get a Type::Tiny object via symbolic reference. It seems to work ok when I do it on built-in types, like this:

use Type::Tiny;
use Types::Standard qw( Int Num Str );
use strict;

$\ = "\n"; $, = "\t";

no strict 'refs';
# ------------------------------------------
# This works ok
# ------------------------------------------

print ref *{"main::Int"}{CODE}->();       # Type::Tiny
print *{"main::Int"}{CODE}->()->name;     # Int

however, when I try to create my own type and access it like this:

use Type::Tiny;
use Types::Standard qw( Int Num Str );
use strict;

$\ = "\n"; $, = "\t";

no strict 'refs';

# ------------------------------------------
# ...and now the part that doesn't work
# ------------------------------------------

my $Date = Type::Tiny->new(
   name       => "Date",
   constraint => sub { /^\d{4,4}-\d{2,2}-\d{2,2}$/ },
   message    => sub { "$_ ain't a date" },
);

print ref $Date;                          # Type::Tiny, so things look ok
print $Date->name;                        # Date, so things look ok

# ------------------------------------------
# this doesn't work
# ------------------------------------------

print *{"main::Date"}{SCALAR};
my $date_type_ref = *{"main::Date"}{SCALAR};
print ref $date_type_ref;                 # SCALAR
print $$date_type_ref;                    # nothing

# ------------------------------------------
# this doesn't work
# ------------------------------------------
my $date_type_ref = *{"main::Date"}{CODE};
eval { print $date_type_ref->() } || print $@;

# --------------------------------------------------------
# poking around in the dark but these doesn't work either
# --------------------------------------------------------
for my $type (qw/SCALAR HASH ARRAY CODE/) {
    my $date_type_ref = *{"main::Date"}{$type};
    print ref $date_type_ref;

    eval { print $date_type_ref->name }; print $@;

    eval {
         my $date_type = $$date_type_ref;
         print $date_type->name;
    };
    print $@

}

nothing seems to work.

What should I change? What is a Tiny::Type object under the hood, and how do I get there?

CPAN fails when installing Crypt::SSLeay

Perl questions on StackOverflow

Published by ManitoDeManitos23del23 on Monday 20 January 2025 18:36

When i run :

cpan install Crypt::SSLeay

I get the next output :

make: *** [Makefile:887: test_dynamic] Error 2
  OALDERS/LWP-Protocol-https-6.14.tar.gz
2 dependencies missing (IO::Socket::SSL,IO::Socket::SSL::Utils); additionally test harness failed
  /usr/bin/make test -- NOT OK
//hint// to see the cpan-testers results for installing this module, try:
  reports OALDERS/LWP-Protocol-https-6.14.tar.gz
  NANIS/Crypt-SSLeay-0.72.tar.gz
  Has already been unwrapped into directory /home/archy/.cpan/build/Crypt-SSLeay-0.72-4
  NANIS/Crypt-SSLeay-0.72.tar.gz
  Has already been prepared
Running make for N/NA/NANIS/Crypt-SSLeay-0.72.tar.gz
Warning: Prerequisite 'LWP::Protocol::https => 6.02' for 'NANIS/Crypt-SSLeay-0.72.tar.gz' failed when processing 'OALDERS/LWP-Protocol-https-6.14.tar.gz' with 'make_test => NO 2 dependencies missing (IO::Socket::SSL,IO::Socket::SSL::Utils); additionally test harness failed'. Continuing, but chances to succeed are limited.
cp lib/Crypt/SSLeay/MainContext.pm blib/lib/Crypt/SSLeay/MainContext.pm
cp lib/Crypt/SSLeay/X509.pm blib/lib/Crypt/SSLeay/X509.pm
cp lib/Crypt/SSLeay/Err.pm blib/lib/Crypt/SSLeay/Err.pm
cp lib/Crypt/SSLeay/Conn.pm blib/lib/Crypt/SSLeay/Conn.pm
cp lib/Crypt/SSLeay/Version.pm blib/lib/Crypt/SSLeay/Version.pm
cp lib/Net/SSL.pm blib/lib/Net/SSL.pm
cp SSLeay.pm blib/lib/Crypt/SSLeay.pm
cp lib/Crypt/SSLeay/CTX.pm blib/lib/Crypt/SSLeay/CTX.pm
Running Mkbootstrap for SSLeay ()
chmod 644 "SSLeay.bs"
"/usr/bin/perl" -MExtUtils::Command::MM -e 'cp_nonempty' -- SSLeay.bs blib/arch/auto/Crypt/SSLeay/SSLeay.bs 644
"/usr/bin/perl" "/usr/share/perl5/core_perl/ExtUtils/xsubpp"  -typemap '/usr/share/perl5/core_perl/ExtUtils/typemap' -typemap '/home/archy/.cpan/build/Crypt-SSLeay-0.72-4/typemap'  SSLeay.xs > SSLeay.xsc
mv SSLeay.xsc SSLeay.c
cc -c   -D_REENTRANT -D_GNU_SOURCE -fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/include/db5.3 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -fexceptions -Wp,-D_FORTIFY_SOURCE=3 -Wformat -Werror=format-security -fstack-clash-protection -fcf-protection -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -g -ffile-prefix-map=/build/perl/src=/usr/src/debug/perl -flto=auto   -DVERSION=\"0.72\" -DXS_VERSION=\"0.72\" -fPIC "-I/usr/lib/perl5/5.40/core_perl/CORE"   SSLeay.c
SSLeay.xs: In function ‘XS_Crypt__SSLeay__CTX_new’:
SSLeay.xs:152:31: error: implicit declaration of function ‘SSLv3_client_method’; did you mean ‘SSLv23_client_method’? [-Wimplicit-function-declaration]
  152 |             ctx = SSL_CTX_new(SSLv3_client_method());
      |                               ^~~~~~~~~~~~~~~~~~~
      |                               SSLv23_client_method
SSLeay.xs:152:31: error: passing argument 1 of ‘SSL_CTX_new’ makes pointer from integer without a cast [-Wint-conversion]
  152 |             ctx = SSL_CTX_new(SSLv3_client_method());
      |                               ^~~~~~~~~~~~~~~~~~~~~
      |                               |
      |                               int
In file included from SSLeay.xs:35:
/usr/include/openssl/ssl.h:1606:47: note: expected ‘const SSL_METHOD *’ {aka ‘const struct ssl_method_st *’} but argument is of type ‘int’
 1606 | __owur SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth);
      |                             ~~~~~~~~~~~~~~~~~~^~~~
SSLeay.xs:157:31: error: implicit declaration of function ‘SSLv2_client_method’; did you mean ‘SSLv23_client_method’? [-Wimplicit-function-declaration]
  157 |             ctx = SSL_CTX_new(SSLv2_client_method());
      |                               ^~~~~~~~~~~~~~~~~~~
      |                               SSLv23_client_method
SSLeay.xs:157:31: error: passing argument 1 of ‘SSL_CTX_new’ makes pointer from integer without a cast [-Wint-conversion]
  157 |             ctx = SSL_CTX_new(SSLv2_client_method());
      |                               ^~~~~~~~~~~~~~~~~~~~~
      |                               |
      |                               int
/usr/include/openssl/ssl.h:1606:47: note: expected ‘const SSL_METHOD *’ {aka ‘const struct ssl_method_st *’} but argument is of type ‘int’
 1606 | __owur SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth);
      |                             ~~~~~~~~~~~~~~~~~~^~~~
make: *** [Makefile:354: SSLeay.o] Error 1
  NANIS/Crypt-SSLeay-0.72.tar.gz
  /usr/bin/make -- NOT OK

The output to the terminal is too long, so i just put the important part

I need to install this module in order to run nikto with SSL. According to nikto docs i could either install Net::SSL or Net::SSLeay.

When i try to install Net::SSL i get as well the error above, but when doing so with Net::SSLeay everything sees fine in the output.

But runnning r in the cpan shell does not show any module seemed to Net::SSLeay

What can i do ?

Perl: perl 5, version 40, subversion 0 (v5.40.0) built for x86_64-linux-thread-multi OS: Arch Linux x64

Update perldelta for ExtUtils::ParseXS

Perl commits on GitHub

Published by steve-m-hay on Monday 20 January 2025 17:24

Update perldelta for ExtUtils::ParseXS

Update Module::CoreList for ExtUtils::ParseXS

Perl commits on GitHub

Published by steve-m-hay on Monday 20 January 2025 17:23

Update Module::CoreList for ExtUtils::ParseXS

I believe it is telling me that the changes2pm.pl is missing. isn't that file suppose to be in the cpan file/module downloaded when cpan starts the install? who/where would i point this out to the developers? more importantly how do i get it to install? couple months back the DBI installed with no issues. should i try to install the last version of DBI or will that open another can of worms so to speak. i really don't like using the --force option for anything and no i don't want to use activestate. any way this is what i'm getting.

>cpan DBI
...
Checking if your kit is complete...
Looks good

    I see you're using perl 5.038000 on MSWin32-x64-multi-thread, okay.
    Remember to actually *read* the README file!
    Use  'make' to build the software (dmake or nmake on Windows).
    Then 'make test' to execute self tests.
    Then 'make install' to install the DBI and then delete this working
    directory before unpacking and building any DBD::* drivers.

    Windows users need to use the correct make command.
    That may be nmake or dmake depending on which Perl you are using.
    If using the Win32 ActiveState build then it is recommended that you
    use the ppm utility to fetch and install a prebuilt DBI instead.

Generating a gmake-style Makefile
Writing Makefile for DBI
Writing MYMETA.yml and MYMETA.json
  HMBRAND/DBI-1.646.tar.gz
  C:\progs\sp5038000001\perl\bin\perl.exe Makefile.PL -- OK
Running make for H/HM/HMBRAND/DBI-1.646.tar.gz
gmake: Circular Changes <- lib\DBI\Changes.pm dependency dropped.
"C:\progs\sp5038000001\perl\bin\perl.exe" -MExtUtils::Command -e mkpath -- blib\lib\DBI
"C:\progs\sp5038000001\perl\bin\perl.exe" -MExtUtils::Command -e rm_f -- lib\DBI\Changes.pm blib\lib\DBI\Changes.pm
perl changes2pm.pl
Can't open perl script "changes2pm.pl": No such file or directory
gmake: *** [makefile:416: lib\DBI\Changes.pm] Error 2
  HMBRAND/DBI-1.646.tar.gz
  C:\progs\SP5038~1\c\bin\gmake.exe -- NOT OK
Stopping: 'install' failed for 'DBI'.

Any help much appreciated. fyi I'm on windows 10 64 bit os. intel i5 quad. 8 gig of ram.

Since I don't have a github account nor do I want one I have done multiple searches for a work around but I do not want to use a force option and I don't trust activestate to give me a clean Perl build.

perlintern: Document NEGATE_2IV and kin

Perl commits on GitHub

Published by khwilliamson on Monday 20 January 2025 13:57

perlintern: Document NEGATE_2IV and kin

And clean up the text in their comments

Perl Weekly Issue #704 - Perl Podcast

r/perl

Published by /u/briandfoy on Monday 20 January 2025 12:31

Perl 🐪 Weekly #704 - Perl Podcast

dev.to #perl

Published by Gabor Szabo on Monday 20 January 2025 06:44

Originally published at Perl Weekly 704

Hi there,

Do you know of any active Perl Podcast?

It reminds me when Lance Wicks reached out to Joshua McAdams to revive Perlcast in 2018. I later joined hands with Lance and we even recorded the first podcast with Neil Bowers. Unfortunately it didn't work out. Fast forward, in the new year 2025, we have another very active member, Philippe Bruhat, who came up with The Underbar, Podcast for Perl. There is already Episode 0 - A New Logo for Perl is published which was recorded on January 10th, 2025. You should listen to it and share your feedbacks to the creator. Also please do spread the word about it.

This year German Perl/Raku Workshop is happening in the beautiful city Munich. Even if German is not your first language, you can still benefit from the presentations. I attended the workshop in the year 2018, my first time. I enjoyed the 3-days event thoroughly. I even gave couple of presentations in English. For me, it was the golden opportunity to meet so many Perl stalwarts. I made many friends for life. Buy your tickets now, it is starting on 12th May 2025 and ends on 14th May 2025.

There is another good news in the year 2025, The Weekly Challenge has secured sponsor for another 12 months, thanks to Lance Wicks for the second year back to back.

Stay safe and enjoy rest of the newsletter.

--
Your editor: Mohammad Sajid Anwar.

Announcements

Introducing DateTime::Format::RelativeTime

Announcement of the new Perl module DateTime::Format::RelativeTime, which is designed to mirror its equivalent Web API Intl.RelativeTimeFormat

Premium XS Integration, Pt 1

Here is the guide how to write safe, fast, convenient, and powerful XS libraries.

Announce Perl Wiki v1.22

Please explore the latest release.

Articles

Creating MIDI Music with Perl

For all music lovers, here is your opportunity to use Perl for fun. Really cool tool, you must try.

Yet Another Perl-Powered Company: Geolytica

Imagine you want to parse free-form address input and match it against a database representing the road network. At Geolytica, Perl is used to manage and enhance vast geo-location datasets and build the application logic of the geocoding engines.

Profiling Peak DRAM Use in R With Perl - Part 1

Serious profiling discussed in 2 part series post.

Profiling Peak DRAM Use in R With Perl - Part 2

Continued the discussion of profiling Peak DRAM in this second post of the series.

Discussion

What is the correct Perl syntax for "use if, feature"?

Please checkout the reply for more detailed answer.

How to change attribute to a specific non-alphabetic order using XML::Twig?

Interesting use case and the solution too.

The Weekly Challenge

The Weekly Challenge by Mohammad Sajid Anwar will help you step out of your comfort-zone. You can even win prize money of $50 by participating in the weekly challenge. We pick one champion at the end of the month from among all of the contributors during the month, thanks to the sponsor Lance Wicks.

The Weekly Challenge - 305

Welcome to a new week with a couple of fun tasks "Binary Prefix" and "Alien Dictionary". If you are new to the weekly challenge then why not join us and have fun every week. For more information, please read the FAQ.

RECAP - The Weekly Challenge - 304

Enjoy a quick recap of last week's contributions by Team PWC dealing with the "Arrange Binary" and "Maximum Average" tasks in Perl and Raku. You will find plenty of solutions to keep you busy.

Arranged Average

Cool use of copy parameters where you can modify the contents. Raku Rocks.

Not Modified

Interesting analogy of week 304 with the HTTP status code. Always fun to read the blog post.

Perl Weekly Challenge: Week 304

For a change, I didn't see any magics used this week. Pretty straight forward approach both in Perl and Raku. Keep it up great work.

Average Replacements

Pure regex solution and compact too with plenty of discussion. Highly recommended.

am I lazy?

Two simple and easy to follow solutions in Raku. You get enough discussion to get there.

Perl Weekly Challenge 304

Breaking down task into subtask is always very handy. Have the one-liner and a complete solutions in the end. Great work.

Arrange Any Aligned Average

Another demo of regex solution, very clever attempt. You must checkout the solution.

Adding ones and maxing the mean

Nice hack to make the task easier. DIY tool lets you play with it too.

The Weekly Challenge #304

Use of goto, interesting. I know it is not commonly used these days. Check it out yourself.

Binary to the Maxmim

Simple use of loop in Kotlin gave us the solution straight away. New to Kotlin? You don't want to skip it.

Rakudo

2025.02 Ditana

Weekly collections

NICEPERL's lists

Great CPAN modules released last week;
MetaCPAN weekly report.

Events

GitLab pipelines and CI for Perl developers

This Virtual event is going to take place today, January 20, 2025, in Zoom. We will take a look at the GitLab pipelines and will bring a few examples to so who to use it in various situations. Including GitLab pages for building a front-end only web site.

You joined the Perl Weekly to get weekly e-mails about the Perl programming language and related topics.

Want to see more? See the archives of all the issues.

Not yet subscribed to the newsletter? Join us free of charge!

(C) Copyright Gabor Szabo
The articles are copyright the respective authors.

The Weekly Challenge - 305

The Weekly Challenge

Published on Monday 20 January 2025 06:28

Welcome to the Week #305 of The Weekly Challenge.

RECAP - The Weekly Challenge - 304

The Weekly Challenge

Published on Monday 20 January 2025 06:10

Thank you Team PWC for your continuous support and encouragement.

Perl Dancer2 app logging with Log4perl isn't working

Perl questions on StackOverflow

Published by type_outcast on Monday 20 January 2025 05:55

I'm converting an existing Dancer2 app to use Log4perl. In my Dancer2 app's config.yml, I have the following:

logger: log4perl
engines:
  logger:
    log4perl:
      config_file: log4perl.conf

And log4perl.conf is as follows:

log4perl.rootLogger                 = INFO, LOG1
log4perl.appender.LOG1              = Log::Log4perl::Appender::File
log4perl.appender.LOG1.filename     = app_name.log
log4perl.appender.LOG1.mode         = append
log4perl.appender.LOG1.layout       = Log::Log4perl::Layout::PatternLayout
log4perl.appender.LOG1.layout.ConversionPattern = %d %p %m %n

(This is very similar to the example given in Dancer2::Logger::Log4perl's POD.)

When I run the app via plackup or use the module in test scripts, it reports loading my configuration (and will throw errors if I have anything invalid in config.yml, but I'm not sure it's using log4perl at all, or ever reading log4perl.conf (no error is reported, even if I move log4perl.conf away entirely). app_name.log is never created, and all of my app's log messages are sent to the console as if I had no logging configuration at all. There are no errors or warnings; the app just loads and ignores my logger config.

I have double checked all relevant modules are installed (though I would hope something would throw a warning otherwise), including Dancer2::Logger::Log4perl, Log::Log4perl and all of the Appender and Layout modules shown above. Running on Perl 5.40.0.

I've also started a new Dancer2 app from scratch with the same logger config, with the same result, so it's not some leftover cruft from elsewhere in my larger application.

What am I doing wrong?

Announce Perl.Wiki.html V 1.22

blogs.perl.org

Published by Ron Savage on Monday 20 January 2025 04:34

The Weekly Challenge - Guest Contributions

The Weekly Challenge

Published on Monday 20 January 2025 01:35

As you know, The Weekly Challenge, primarily focus on Perl and Raku. During the Week #018, we received solutions to The Weekly Challenge - 018 by Orestis Zekai in Python. It was pleasant surprise to receive solutions in something other than Perl and Raku. Ever since regular team members also started contributing in other languages like Ada, APL, Awk, BASIC, Bash, Bc, Befunge-93, Bourne Shell, BQN, Brainfuck, C3, C, CESIL, Chef, COBOL, Coconut, C Shell, C++, Clojure, Crystal, D, Dart, Dc, Elixir, Elm, Emacs Lisp, Erlang, Excel VBA, F#, Factor, Fennel, Fish, Forth, Fortran, Gembase, GNAT, Go, GP, Groovy, Haskell, Haxe, HTML, Hy, Idris, IO, J, Janet, Java, JavaScript, Julia, K, Korn Shell, Kotlin, Lisp, Logo, Lua, M4, Maxima, Miranda, Modula 3, MMIX, Mumps, Myrddin, Nelua, Nim, Nix, Node.js, Nuweb, Oberon, Octave, OCaml, Odin, Ook, Pascal, PHP, Python, PostgreSQL, Postscript, PowerShell, Prolog, R, Racket, Rexx, Ring, Roc, Ruby, Rust, Scala, Scheme, Sed, Smalltalk, SQL, Standard ML, SVG, Swift, Tcl, TypeScript, Uiua, V, Visual BASIC, WebAssembly, Wolfram, XSLT, YaBasic and Zig.

The Weekly Challenge - 304

The Weekly Challenge

Published on Monday 20 January 2025 01:20

Welcome to the Week #304 of The Weekly Challenge.

The Weekly Challenge - 303

The Weekly Challenge

Published on Monday 20 January 2025 01:20

Welcome to the Week #303 of The Weekly Challenge.

[MERGE] ParseXS: heavily refactor generate_output

Perl commits on GitHub

Published by iabyn on Monday 20 January 2025 00:13

[MERGE] ParseXS: heavily refactor generate_output

generate_output() is the function which emits the C which returns the
value of a variable.

This series of 53 commits simplifies and reorganises that method so that
it is much more regular, and with fewer special cases.  For example, the
code to handle 'OUTLIST var' now shares the same code path as RETVAL, so
it can now also take advantage of the various optimisations which used
to apply only to RETVAL, such as using TARG.

Many more tests have also been added.

Also, generate_output() has been renamed to as_output_code() and becomes
a method of ExtUtils::ParseXS::Node::Param: part of the gradual shift
towards having an AST and methods which act upon it.

There is still more work to be done in this area of code generation, but
this branch is long enough already, so I will return to it later.

ParseXS: fix OUTLIST/OUTPUT override issue

Perl commits on GitHub

Published by iabyn on Monday 20 January 2025 00:11

ParseXS: fix OUTLIST/OUTPUT override issue

I introduced a bug during recent code refactoring. For the specific
(and unusual) case of a void XSUB with a single parameter which was
both OUTLIST and also had an OUTPUT entry with a code override:

    foo(IN_OUTLIST int A)
        OUTPUT:
            A    setA(ST[99], A);

the OUTLIST would fail to emit the code to set the new mortal to be
stored at ST(0) to the value of A.

Arrange Any Aligned Average (PWC 304)

dev.to #perl

Published by Matthias Muth on Sunday 19 January 2025 23:53

Challenge 304 solutions in Perl by Matthias Muth

These are my Challenge 304 Task 1 and 2 solutions in Perl
for The Weekly Challenge.

Thank you, Mohammad Sajid Anwar for two more great challenges this week!

Task 1: Arrange Binary

You are given a list of binary digits (0 and 1) and a positive integer, \$n.
Write a script to return true if you can re-arrange the list by replacing at least \$n digits with 1 in the given list so that no two consecutive digits are 1 otherwise return false.

Example 1

Input: @digits = (1, 0, 0, 0, 1), $n = 1
Output: true
Re-arranged list: (1, 0, 1, 0, 1)


Example 2

Input: @digits = (1, 0, 0, 0, 1), $n = 2
Output: false

The task description contains the words 'replacing' and 'digits'.
The first thing that I think of when I hear 'replacing' in a Perl context is 'What's the regular expression that I can use?'. So here we go.

The array of digits is easily turned into a string of zeroes and ones by joining together the array elements:

    my $string = join "", $digits->@*;

Then, we match the places where we can put in ones instead of zeroes.
The condition for replacing a '0' by a '1' is that neither left of it nor right of it there is a '1' already.
We can translate this directly to a regular expression, using a negative lookbehind and a negative lookahead. Using the x modifier to make those more easily recognizable:

    $string =~ s/ (?<!1) 0 (?!1) /1/x

We cannot simply use the g modifier to replace all those zeroes in one go, because our substitutions are not taken into account for finding the next match. For sequences like '00000' we would end up with '11111', because every '0' in the original string fulfils the critera to be replaced by a '1'.
That means that we need to put the substitution into a while loop. Within the loop body, we decrement $n by one, because we were able to do a replacement.
So:

    while ( $string =~ s/ (?<!1) 0 (?!1) /1/x ) {
        --$n;
    }

In production software, or with longer strings, I would probably try to avoid restarting the search for the next match at the beginning of the string again and again. I would probably do so by setting pos $string to the place behind the recent successful replacement, before re-iterating.

For the challenge examples, this here works well enough already:

use v5.36;

sub arrange_binary( $digits, $n ) {
    my $string = join "", $digits->@*;
    while ( $string =~ s/ (?<!1) 0 (?!1) /1/x ) {
        --$n;
    }
    return $n <= 0;
}

If you have your own solution, you might try with these additional testcases:

use Test2::V0 qw( -no_srand );

is arrange_binary( [1, 0, 0, 0, 1], 1 ), T,
    'Example 1: arrange_binary( [1, 0, 0, 0, 1], 1 ) is true';
is arrange_binary( [1, 0, 0, 0, 1], 2 ), F,
    'Example 2: arrange_binary( [1, 0, 0, 0, 1], 2 ) is false';
is arrange_binary( [], 0 ), T,
    'Test 1: arrange_binary( [], 0 ) is true';
is arrange_binary( [], 1 ), F,
    'Test 2: arrange_binary( [], 1 ) is false';
is arrange_binary( [ 0 ], 1 ), T,
    'Test 3: arrange_binary( [ 0 ], 1 ) is true';
is arrange_binary( [ 1 ], 1 ), F,
    'Test 4: arrange_binary( [ 1 ], 1 ) is false';
is arrange_binary( [ 0 ], 2 ), F,
    'Test 5: arrange_binary( [ 0 ], 2 ) is false';
is arrange_binary( [0, 0], 1 ), T,
    'Test 6: arrange_binary( [0, 0], 1 ) is true';
is arrange_binary( [0, 0], 2 ), F,
    'Test 7: arrange_binary( [0, 0], 2 ) is false';
is arrange_binary( [0, 1], 1 ), F,
    'Test 8: arrange_binary( [0, 1], 1 ) is false';
is arrange_binary( [0, 0, 0], 2 ), T,
    'Test 9: arrange_binary( [0, 0, 0], 2 ) is true';
is arrange_binary( [1, 0, 0], 1 ), T,
    'Test 10: arrange_binary( [1, 0, 0], 1 ) is true';
is arrange_binary( [0, 1, 0], 1 ), F,
    'Test 11: arrange_binary( [0, 1, 0], 1 ) is false';
is arrange_binary( [0, 0, 1], 1 ), T,
    'Test 12: arrange_binary( [0, 0, 1], 1 ) is true';
is arrange_binary( [0, 0, 0, 0, 0, 0], 3 ), T,
    'Test 13: arrange_binary( [0, 0, 0, 0, 0], 3 ) is true';
is arrange_binary( [0, 0, 0, 0, 0, 0], 4 ), F,
    'Test 14: arrange_binary( [0, 0, 0, 0, 0], 4 ) is false';

done_testing;

Task 2: Maximum Average

You are given an array of integers, @ints and an integer, $n which is less than or equal to total elements in the given array.
Write a script to find the contiguous subarray whose length is the given integer, $n, and has the maximum average. It should return the average.

Example 1

Input: @ints = (1, 12, -5, -6, 50, 3), \$n = 4
Output: 12.75
Subarray: (12, -5, -6, 50)
Average: (12 - 5 - 6 + 50) / 4 = 12.75


Example 2

Input: @ints = (5), \$n = 1
Output: 5

So finding 'contiguous subarrays'.
Good that we know the length of each of those subarrays -- it's $n.
Which makes it easier, because we don't need to find all possible contiguous subarrays of the input arrays, but only those with that given length.
What we really do is a 'sliding window' search, taking the first $n elements of the array, then the $n elements starting with the second element, and so on.

In a loop, the first starting index for the sliding window is 0, of course.
The last index is the one that uses the last $n elements for the window.
If we have a window size of $n == 1, the last window starts at $ints->$#*. Generalizing from there, the last index for any $n is $ints->$#* - ( $n - 1 ).

To get the values in the window, we can simply use Perl's arrays slice construct. Starting at index $_, the window is @int[ $_ .. ( $_ + $n - 1 ) ].

I put this together into one statement, using map to iterate through the windows, sum to sum up each window, maxto find the largest window sum, and / $n to reduce that to the largest average.

In my environment, the array data are handed into the subroutine as an arrayref, so instead of @ints we have $ints pointing to the data.
I prefer using the 'Postfix Dereferencing Syntax' ($ints->@*[...]) for accessing the array data (and also $ints->$#* for the last index into that array), because I find it easier to read and more logical to write most of the times.

So here it is:

use v5.36;

use List::Util qw( sum max );

sub maximum_average( $ints, $n ) {
    return max(
        map sum( $ints->@[ $_ .. ( $_ + $n - 1 ) ] ),
            0 .. ( $ints->$#* - ( $n - 1 )  )
    ) / $n;
}

Thank you for the challenge!

Find the complete source code for both tasks, including tests, on Github.

Premium XS Integration, Pt 1

blogs.perl.org

Published by Nerdvana on Sunday 19 January 2025 23:18

Intro

There are several competing philosophies for wrapping external C libraries. One is that the XS module should hide all the details of the library and provide a clean “Perlish interface”. The opposite extreme is that the external C functions should be exposed to Perl using an extremely minimal XS layer, or the Foreign Function Interface (FFI) and all the logic for working with the library should be written in Perl.

I advocate something in the middle. I think that a good interface should expose as much of the low-level as possible (to make the most usage of that library possible by other Perl modules) while “padding the sharp edges” so that it is difficult for Perl-side usage to crash the program. Higher level features can be provided in addition to the low level API via XS, Perl modules, or both.

If you consider that the average C library is an awkward mess of state machines and lightly-enforced state requirements that will segfault if not carefully obeyed, wrapping that nicely for the Perl developer is going to require a lot of data translation and runtime sanity checks. If you skip those runtime sanity checks in your wrapper library, it drags down the efficiency of your subsequent Perl development to the level of C development, which is to say, sitting around scratching your head for hours wondering why the program keeps segfaulting. (or attaching gdb to your debug build of perl) If you write those runtime checks in Perl, like with the FFI approach, your runtime performance can suffer significantly. If you write those runtime checks in XS, you can actually do quite a lot of them before there’s any notable decrease in the performance of the script.

Meanwhile, C code runs an order of magnitude faster than Perl opcodes, so if you’re going to require the end user to use a compiled module already, I feel it makes sense to put as much of the higher-level routines into XS as you have time for. But, the higher level routines shouldn’t be at the expense of the lower-level ones, or else you limit what people can do with the library.

This guide will explain all the tricks I know to write safe, fast, convenient, and powerful XS libraries.

(If you spot anything wrong, or want to contribute suggestions, open an issue at the GitHub repo

Binding Objects

One of the first things you’ll need to do for any C library which allocates “objects” is to bind them to a matching Perl object, usually a blessed scalar ref or hash ref. (The C language doesn’t have official objects of course, but a library often allocates a struct or opaque pointer with a lifespan and a destructor function that they expect you to call when you’re done with it, which is the same theme as an object.)

If you read through the common tutorials, you’ll probably see a recipe like

SV*
new(class, some_data)
  SV *class;
  IV some_data;
  INIT:
    LibWhaever_obj *obj;
  CODE:
    obj= LibWhaever_create(some_data);
    if (!obj) croak("LibWhaever_create failed");
    RETVAL= (SV*) newRV_noinc(newSViv((IV)obj));
    sv_bless(RETVAL,
             gv_stashpv("YourProject::LibWhatever", GV_ADD));
  OUTPUT:
    RETVAL

void
DESTROY(self)
  SV *self;
  INIT:
    LibWhaever_obj *obj;
  PPCODE:
    obj= (LibWhaever_obj*) SvIV(SvRV(self));
    LibWhaever_destroy(obj);
    XSRETURN(0);

This is about the least effort/overhead you can have for binding a C data structure to a Perl blessed scalar ref, and freeing it when the Perl object goes out of scope. (you can also move some of this code to the typemap, but I’ll come back to that later)

I don’t like this pattern for several reasons:

  • If someone passes the object to Storable’s dclone, it happily makes a copy of your scalar ref and then when the first object goes out of scope it runs the destructor, and the other object is now referring to freed memory and will probably segfault during its next use.
  • When you create a new thread in a threaded Perl, it clones objects, creating the same bug.
  • The pointer is stored as an integer visible to Perl, and could get altered by sloppy/buggy Perl code, and then you get a segfault.
  • A user could subclass the XS object, and write their own DESTROY method that forgets to call $self->SUPER::DESTROY, leaking the C object.
  • Sloppy/buggy Perl code could re-bless the class, also bypassing the DESTROY call.
  • Sloppy/buggy Perl code could call DESTROY on something which isn’t the blessed scalar-ref containing a valid pointer.

While most of these scenarios shouldn’t happen, if by unfortunate circumstances they do happen, someone loses a bunch of hours debugging it, especially if they aren’t the XS author and don’t know about these pitfalls.

Magic

A much more reliable way to link the C structs to the Perl blessed refs is through Perl’s “magic” system. Magic is the name for essentially a pointer within the SV/AV/HV of your object which points to a linked list of C metadata. This metadata describes various things, like operator-overloading or ties or other low-level Perl features. One type of magic is reserved for “extensions” (that’s you!)

There is a fair amount of effort and boilerplate to set up magic on your objects, but consider these benefits:

  • You are guaranteed that only the object your C code created will carry the pointer to your C struct, and no sloppy/buggy Perl-level operations can break that.
  • If the magic-attached pointer isn’t present, you can cleanly die with an error message to the user that somehow they have called your XS method on something that isn’t your object.
  • Your C-function destructor is described by the magic metadata, and does not rely on a DESTROY Perl method. This also makes destruction faster if Perl doesn’t need to call a Perl-level DESTROY function.
  • Magic can be applied equally to any type of ref, so you can use one pattern for whatever you are blessing, or even let the user choose what kind of ref it will be.
  • You can even use Moo or Moose to create the object, then attach your magic to whatever ref the object system created.
  • You get a callback when a new Perl thread starts and attempts to clone your object. (letting you clone it, or throw an exception that it can’t be cloned which is at least nicer to the user than a segfault would be)

With that in mind, lets begin suffering through the details.

Defining Magic

Magic is described with “struct MGVTBL”:

static int
YourProject_LibWhatever_magic_free(pTHX_ SV* sv, MAGIC* mg) {
  LibWhatever_obj *obj= (LibWhatever_obj*) mg->mg_ptr;
  LibWhatever_destroy(obj);
}

#ifdef USE_ITHREADS
static int
YourProject_LibWhatever_magic_dup(pTHX_ MAGIC *mg,
  CLONE_PARAMS *param)
{
  croak("This object cannot be shared between threads");
  return 0;
};
#else
#define YourProject_LibWhatever_magic_dup 0
#endif

// magic table for YourProject::LibWhatever
static MGVTBL YourProject_LibWhatever_magic_vtbl= {
  0, /* get */
  0, /* set */
  0, /* length */
  0, /* clear */
  YourProject_LibWhatever_magic_free, /* free */
#ifdef MGf_COPY
  0, /* copy magic to new variable */
#endif
#ifdef MGf_DUP
  YourProject_LibWhatever_magic_dup /* dup for new threads */
#endif
#ifdef MGf_LOCAL
  ,0 /* local */
#endif
};

You only need one static instance for each type of magic your module creates. It’s just metadata telling Perl how to handle your particular type of extension magic. The ifdefs are from past versions of the struct that had fewer fields, though if your module is requiring Perl 5.8 you can assume ‘copy’ and ‘dup’ exist, and from 5.10 ‘local’ always exists as well.

Next, the recipe to attach it to a new Perl object:

SV * my_wrapper(LibWhatever_obj *cstruct) {
  SV *obj, *objref;
  MAGIC *magic;
  obj= newSV(0); // or newHV() or newAV()
  objref= newRV_noinc(obj);
  sv_bless(objref, gv_stashpv("YourProject::LibWhatever", GV_ADD));
  magic= sv_magicext(
    obj,               // the inner SV/AV/HV, not the ref to it
    NULL,
    PERL_MAGIC_ext,                      // "extension magic"
    &YourProject_LibWhatever_magic_vtbl, // show perl your functions
    (const char*) cstruct,               // your custom pointer
    0);
#ifdef USE_ITHREADS
  magic->mg_flags |= MGf_DUP;
#else
  (void)magic; // suppress warning
#endif
  return objref;
}

The key there is ‘sv_magicext’. Note that you’re applying it to the thing being referred to, not the scalar ref that you use for the call to sv_bless. The messy ifdef part is due to the ‘dup’ field of the magic table only being used when perl was compiled with threading support. The reference to YourProject_LibWhatever_magic_vtbl is both an instruction for Perl to know what functions to call, but also a unique value used to identify your extension magic from anyone else’s.

To read your pointer back from an SV provided to you, the recipe is:

LibWhatever_obj* YourProject_LibWhatever_from_magic(SV *objref) {
  SV *sv;
  MAGIC* magic;

  if (SvROK(objref)) {
    sv= SvRV(objref);
    if (SvMAGICAL(sv)) {
      // Iterate magic attached to this scalar to find our vtable
      for (magic= SvMAGIC(sv); magic; magic = magic->mg_moremagic)
        if (magic->mg_type == PERL_MAGIC_ext
         && magic->mg_virtual == &YourProject_LibWhatever_magic_vtbl)
          // If found, the mg_ptr points to the fields structure.
          return (LibWhatever_obj*) magic->mg_ptr;
    }
  }
  return NULL;
}

This might look a little expensive, but there is likely only one type of magic on your object, so the loop exits on the first iteration, and all you did was “SvROK”, “SvRV”, “SvMAGICAL”, and “SvMAGIC” followed by two comparisons. It’s actually quite a bit faster than verifying the inheritance of the blessed package name.

So there you go - you can now attach your C structs with magic.

Convenience via Typemap

In a typical wrapper around a C library, you’re going to be writing a lot of methods that need to call YourProject_LibWhatever_from_magic on the first argument. To make that easier, lets move this decoding step to the typemap.

Without a typemap:

IV
method1(self, param1)
  SV *self
  IV param1
  INIT:
    LibWhatever_obj *obj= YouProject_LibWhatever_from_magic(self);
  CODE:
    if (!obj) croak("Not an instance of LibWhatever");
    RETVAL= LibWhatever_method1(obj, param1);
  OUTPUT:
    RETVAL

With a typemap entry like:

TYPEMAP
LibWhatever_obj*        O_LibWhatever_obj

INPUT
O_LibWhatever_obj
  $var= YourProject_LibWhatever_from_magic($arg);
  if (!$var) croak("Not an instance of LibWhatever");

the XS method becomes

IV
method1(obj, param1)
  LibWhatever_obj *obj
  IV param1
  CODE:
    RETVAL= LibWhatever_method1(obj, param1);
  OUTPUT:
    RETVAL

If you have some functions that take an optional LibWhatever_obj pointer, try this trick:

typedef LibWhatever_obj Maybe_LibWhatever_obj;

...

void
show(obj)
  Maybe_LibWhatever_obj *obj
  PPCODE:
    if (obj) {
      printf("...", LibWhatever_get_attr1(obj));
    }
    else {
      printf("NULL");
    }

TYPEMAP
LibWhatever_obj*        O_LibWhatever_obj
Maybe_LibWhatever_obj*  O_Maybe_LibWhatever_obj

INPUT
O_LibWhatever_obj
  $var= YourProject_LibWhatever_from_magic($arg);
  if (!$var) croak("Not an instance of LibWhatever");

INPUT
O_Maybe_LibWhatever_obj
  $var= YourProject_LibWhatever_from_magic($arg);

If you want to save a bit of compiled .so file size, you can move the error message into the ‘from_magic’ function, with a flag:

#define OR_DIE 1

LibWhatever_obj*
YourProject_LibWhatever_from_magic(SV *objref, int flags) {
  SV *sv;
  MAGIC* magic;

  if (SvROK(objref)) {
    sv= SvRV(objref);
    if (SvMAGICAL(sv)) {
      // Iterate magic attached to this scalar to find our vtable
      for (magic= SvMAGIC(sv); magic; magic = magic->mg_moremagic)
        if (magic->mg_type == PERL_MAGIC_ext
         && magic->mg_virtual == &YourProject_LibWhatever_magic_vtbl)
          // If found, the mg_ptr points to the fields structure.
          return (LibWhatever_obj*) magic->mg_ptr;
    }
  }
  if (flags & OR_DIE)
    croak("Not an instance of LibWhatever");
  return NULL;
}

TYPEMAP
LibWhatever_obj*        O_LibWhatever_obj
Maybe_LibWhatever_obj*  O_Maybe_LibWhatever_obj

INPUT
O_LibWhatever_obj
  $var= YourProject_LibWhatever_from_magic($arg, OR_DIE);

INPUT
O_Maybe_LibWhatever_obj
  $var= YourProject_LibWhatever_from_magic($arg, 0);

You can play further games with this, like automatically initializing the SV to become one of your blessed objects if it wasn’t defined, in the style of Perl’s open my $fh, ..., or maybe an option to add the magic to an existing object created by a pure-perl constructor. Do whatever makes sense for your API.

More Than One Pointer

In all the examples so far, I’m storing a single pointer to a type defined in the external C library being wrapped. Chances are, though, you need to store more than just that one pointer.

Imagine a poorly-written C library where you need to call SomeLib_create to get the object, then a series of SomeLib_setup calls before any other function can be used, then if you want to call SomeLib_go you have to first call SomeLib_prepare or else it segfaults. You could track these states in Perl variables in a hash ref, but it would just be easier if they were all present in a local C struct of your creation.

So, rather than attaching a pointer to the library struct with magic, you can attach your own allocated struct, and your struct can have a pointer to all the library details. For extra convenience, your struct can also have a pointer to the Perl object which it is attached to, which lets you access that object from other methods you write which won’t have access to the Perl stack.

struct YourProject_objinfo {
  SomeLib_obj *obj;
  HV *wrapper;
  bool started_setup, finished_setup;
  bool did_prepare;
};

struct YourProject_objinfo*
YourProject_objinfo_create(HV *wrapper) {
  struct YourProject_objinfo *objinfo= NULL;
  Newxz(objinfo, 1, struct YourProject_objinfo);
  objinfo->wrapper= wrapper;
  /* other setup here ... */
  return objinfo;
}

void
YourProject_objinfo_free(struct YourProject_objinfo *objinfo) {
  if (objinfo->obj) {
    SomeLib_obj_destroy(objinfo->obj);
  }
  /* other cleanup here ... */
  Safefree(objinfo);
}

static int YourProject_objinfo_magic_free(pTHX_ SV* sv, MAGIC* mg) {
  YourProject_objinfo_free(
    (struct YourProject_objinfo *) mg->mg_ptr);
}

One other thing that has changed from the previous scenario is that you can allocate this struct and attach it to the object whenever you want, instead of waiting for the user to call the function that creates the instance of SomeLib_obj. This gives you more flexible ways to deal with creation of the magic.

Here’s a pattern I like:

#define OR_DIE 1
#define AUTOCREATE 2

struct YourProject_objinfo*
YourProject_objinfo_from_magic(SV *objref, int flags) {
  SV *sv;
  MAGIC* magic;

  if (!sv_isobject(objref))
    /* could also check 'sv_derived_from' here, but that's slow */
    croak("Not an instance of YourProject");

  sv= SvRV(objref);
  if (SvMAGICAL(sv)) {
    /* Iterate magic attached to this scalar to find our vtable */
    for (magic= SvMAGIC(sv); magic; magic = magic->mg_moremagic)
      if (magic->mg_type == PERL_MAGIC_ext
       && magic->mg_virtual == &YourProject_objinfo_magic_vtbl)
        /* If found, the mg_ptr points to the fields structure. */
        return (struct YourProject_objinfo*) magic->mg_ptr;
  }
  if (flags & AUTOCREATE) {
    struct YourProject_objinfo *ret;
    if (SvTYPE(sv) != SVt_PVHV)
      croak("Expected blessed hashref");
    ret= YourProject_objinfo_create((HV*)sv);
    magic= sv_magicext(sv, NULL, PERL_MAGIC_ext,
      &YourProject_objinfo_magic_vtbl, (const char*) ret, 0);
#ifdef USE_ITHREADS
    magic->mg_flags |= MGf_DUP;
#else
    (void)magic; // suppress warning
#endif
    return ret;
  }
  if (flags & OR_DIE)
    croak("Not an initialized instance of YourProject");
  return NULL;
}

typedef struct YourProject_objinfo Maybe_YourProject_objinfo;
typedef struct YourProject_objinfo Auto_YourProject_objinfo;

Then in the typemap:

TYPEMAP
struct YourProject_objinfo*  O_YourProject_objinfo
Maybe_YourProject_objinfo*   O_Maybe_YourProject_objinfo
Auto_YourProject_objinfo*    O_Auto_YourProject_objinfo

INPUT
O_YourProject_objinfo
  $var= YourProject_objinfo_from_magic($arg, OR_DIE);

INPUT
O_Maybe_YourProject_objinfo
  $var= YourProject_objinfo_from_magic($arg, 0);

INPUT
O_Auto_YourProject_objinfo
  $var= YourProject_objinfo_from_magic($arg, AUTOCREATE);

Then use it in your XS methods to conveniently implement your sanity checks for this annoying C library:

# This is called by the pure-perl constructor, after blessing the hashref
void
_init(objinfo, param1, param2)
  Auto_YourProject_objinfo* objinfo
  IV param1
  IV param2
  PPCODE:
    if (objinfo->obj)
      croak("Already initialized");
    objinfo->obj= SomeLib_create(param1, param2);
    if (!objinfo->obj)
      croak("SomeLib_create failed: %s", SomeLib_get_last_error());
    XSRETURN(0);

bool
_is_initialized(objinfo)
  Maybe_YourProject_objinfo* objinfo
  CODE:
    RETVAL= objinfo != NULL && objinfo->obj != NULL;
  OUTPUT:
    RETVAL

void
setup(objinfo, key, val)
  struct YourProject_objinfo* objinfo
  const char *key
  const char *val
  PPCODE:
    if (objinfo->finished_setup)
      croak("Cannot call 'setup' after 'prepare'");
    if (!SomeLib_setup(objinfo->obj, key, val))
      croak("SomeLib_setup failed: %s", SomeLib_get_last_error());
    objinfo->setup_started= true;
    XSRETURN(0);

void
prepare(objinfo)
  struct YourProject_objinfo* objinfo
  PPCODE:
    if (!objinfo->started_setup)
      croak("Must call setup at least once before 'prepare'");
    objinfo->finished_setup= true;
    if (!SomeLib_prepare(objinfo->obj))
      croak("SomeLib_prepare failed: %s", SomeLib_get_last_error());
    objinfo->did_prepare= true;
    XSRETURN(0);

void
somelib_go(objinfo)
  struct YourProject_objinfo* objinfo
  PPCODE:
    if (!objinfo->did_prepare)
      croak("Must call 'prepare' before 'go'");
    if (!SomeLib_go(objinfo->obj))
      croak("SomeLib_go failed: %s", SomeLib_get_last_error());
    XSRETURN(0);

Like how clean the XS methods got?

Conclusion

When you use the pattern above, your module becomes almost foolproof against misuse. You provide helpful errors for the Perl coder to guide them toward correct usage of the library with easy-to-understand errors (well, depending on how much effort you spend on that) and they don’t have to pull their hair out trying to log all the API calls and compare to the C library documentation to figure out which one happened in the wrong order resulting in a mysterious crash.

The code above is all assuming that the C library is providing objects whose lifespan you are in control of. Many times, the objects from a C library will have some other lifespan that the user can’t directly control with the Perl objects. I’ll cover some techniques for dealing with that in the next article.

Premium XS Integration, Pt 1

r/perl

Published by /u/nrdvana on Sunday 19 January 2025 18:26

Using Perl to Monitor Peak DRAM use in R

dev.to #perl

Published by chrisarg on Sunday 19 January 2025 18:24

A story in two parts:

  1. buff.ly/4hmFepy goes over the subtleties of monitoring DRAM use in #rstats
  2. buff.ly/4hlMstF shows the #Perl solution and how one can make it play nice from within R

Code is released under the MIT license

Using Perl to Profile Peak DRAM Use in R

r/perl

Published by /u/ReplacementSlight413 on Sunday 19 January 2025 16:42

This is a two part story:

  1. Part 1 goes over the subtleties of monitoring DRAM use by R applications (which seems impossible or very difficult to do from within R, except in a valgrind kind of way)
  2. Part 2 shows the Perl solution and how one can make it play nice from within R

Code is released under the MIT license - feel free to adapt to your use cases (and perhaps someone can provide a Windows version!)

submitted by /u/ReplacementSlight413
[link] [comments]

Perl 5.40.1 and 5.38.3 are now available!

r/perl

Published by /u/Grinnz on Sunday 19 January 2025 00:28

Profiling Peak DRAM Use in R With Perl - Part 2

Killing-It-with-PERL

Published on Sunday 19 January 2025 00:00

In the second part of this we implement the solution that was outlines at the end of Part 1:

  1. utilize a Perl application that probes the operating system in real time for the RSS (Resident Set Size), i.e. the DRAM footprint of an application
  2. fire the application from within R as a separate process, provide it with the PID (Process ID) of the R session and put it in the background
  3. do the long, memory hungry application
  4. upon the end of the calculation kill the Perl application and obtain DRAM usage for use within R

The Perl application that implements the first step is straightforward:

  1. Obtain the command line arguments : the PID of the R session, a monitoring interval and a temporary file …
  2. for the Perl application to write out its own PID
  3. Obtain the initial memory usage by call the ps command line utility, using the excellent (and safe as it bypasses the shell!)
  4. IPC::System::Simple MetaCPAN module
  5. Register an event handler that will write out the peak change (“$max_delta”) change of the RSS from the initial value, as well s the initial value
  6. Go into an infinite loop, in which
    • ps is probed for the current value of the RSS,
    • subtracts it from the initial,
    • updates the value of $max_delta if the current value over the baseline is larger than the
    • goes to sleep for a user defined period of time
    • reawakens at the top of the while loop
#!/usr/bin/perl

# Name: monitor_memory.pl
# Purpose: Registers peak DRAM usage of a process
# Usage: perl monitor_memory.pl <PID> <interval_in_seconds> <pidfile>
# Example: perl monitor_memory.pl 12345 1 /tmp/pidfile
# Date: January 19th 2025
# Author: Christos Argyropoulos
# License: MIT https://mit-license.org/

use strict;
use warnings;
use Time::HiRes qw(nanosleep); # high res waiting
use IPC::System::Simple qw(capturex); # safe capture that bypasses the shell

# Process the command line
my ( $pid, $interval_sec, $pidfile ) = @ARGV;
die "Usage: $0 <PID> <interval_in_seconds> <pidfile>\n"
  unless defined $pid && defined $interval_sec && defined $pidfile;

# Write our own PID that R will use to kill the Perl application
open( my $fh, '>', $pidfile ) or die "Can't write to $pidfile: $!";
print $fh "$$\n";
close $fh;

# Obtain initial memory usage
my $interval    = $interval_sec * 1_000_000_000;
my $initial_mem = capturex('ps', 'o', 'rss=', 'p', $pid);
chomp($initial_mem);
my $max_delta = 0;

# Register the INT and TERM signal handlers to print peak and initial DRAM usage
$SIG{INT} = $SIG{TERM} = sub {
    print "$max_delta\t$initial_mem\n";
    exit 0;
};


# Obtain the RSS, store the maximum delta up to this point, sleep and re-awaken
while (1) {
    my $current = capturex('ps', 'o', 'rss=', 'p', $pid);
    chomp($current);
    my $delta = $current - $initial_mem;
    $max_delta = $delta if $delta > $max_delta;
    nanosleep($interval);
}

Having delegated the peak DRAM monitoring to Perl, R is now free to obtain execution timings and memory allocation using Henrik Bengtsson’s excellent profmem package The package’s vignette may be found here and explains what id does and how this works (emphasis is mine):

The profmem() function uses the utils::Rprofmem() function for logging memory allocation events to a temporary file. The logged events are parsed and returned as an in-memory R object in a format that is convenient to work with. All memory allocations that are done via the native allocVector3() part of R’s native API are logged, which means that nearly all memory allocations are logged. Any objects allocated this way are automatically deallocated by R’s garbage collector at some point. Garbage collection events are not logged **by profmem(). **Allocations not logged are those done by non-R native libraries or R packages that use native code Calloc() / Free() for internal objects. Such objects are not handled by the R garbage collector.

Based on this description, monitor_memory.pl and profmem are complementary: the former will log peak running memory use, while the latter will log in all allocations, and the combination will provide the best of both worlds.

The tricky part in the implementation is how to ensure that one does end up with an orphan Perl process when the long calculation throws an error, and thus avoid having to kill the orphan somehow (Unix terminology is so violent). However, the Perl side should not have to worry about the prospect of becoming an orphan, or detecting it has become one. Killing the Perl process (orphan or not), is a task for R, but Perl has to help out, by providing R with the PID of the Perl application. Completion of the communication loop is a necessary, but not sufficient condition for culling the orphan and R has to do its part when implementing the 2nd and 4th step of the top level logic. Here is where R’s tryCatch-finally facilities come to shine:

# Benchmarking allocations, peak DRAM use and execution timing of an expression in R
bench_time_mem<-function(x) {
	gc(reset=FALSE,verbose=FALSE)  ## force a gc here
	pidfile <- tempfile() # temp file to story Perl's PID
	outfile <- tempfile() # stdout redirection for Perl
	pid <- Sys.getpid()   # get R's PID
	ret<-NULL
	system2("./monitor_memory.pl", 
		c(pid,step_of_monitor,pidfile),wait=FALSE,stdout=outfile)
	Sys.sleep(0.2)  # Wait for PID file to be written
	monitor_pid <- readLines(pidfile)[1] # Get Perl's PID
	tryCatch (
		expr = {
			mem<-profmem(time<-system.time(x,gcFirst = FALSE))
			rettime<-c(time)
			names(rettime)<-names(time)
			retval<-c(time,"R_gc_alloc" = sum(mem$bytes,na.rm=T))
		}, # execute R expression, get timing and allocations
		finally = {
			system2("kill",c("-TERM", monitor_pid)) # kill the ? orphan
			Sys.sleep(0.2) # Wait for Perl to finish logging
			memstats<-read.csv(outfile,sep="\t",
				header=FALSE) # get memory statistics
			unlink(c(pidfile,outfile)) # cleanup files
			retval<-c(retval ,
				  "delta"= memstats[1,1]*1024,
				"initial"= memstats[1,2]*1024
				)
		}
	)

	return(retval)
}

The logic of the R partner is fairly straightforward:

  1. Obtain the PID of the R process and a temporary file location for monitor_memory.pl to store its PID
  2. Launch monitor_memory.pl and put it in the background
  3. Proceed to execute the user provided expression in the tryCatch bloc and obtain allocations and execution timings with mem<-profmem(time<-system.time(x,gcFirst = FALSE))
  4. Sum the total memory allocated during the execution of the user expression
  5. Kill the Perl process in the finally block. This code will be executed even if errors are encountered in the user’s expression, and hence no orphan will be allowed to live
  6. Package the DRAM usage into the return value vector and send it to the user, along with allocations and timings.

Let’s look at a complete example written as a R script with command line parsing to see what we have achieved. For this example, we will use the two sequential and the one large allocation we considered in Part 1 :

# Script Name: profile_time_memory.R
# Purpose: illustrate how to profile time and memory usage in R
# Usage: Rscript profile_time_memory.R --sleep_time 1 --size 1E6 --monitor_step 0.001
# Date: January 19th 2025
# Author: Christos Argyropoulos
# License: MIT https://mit-license.org/

library(profmem)
library(getopt)

# Define command line options
spec <- matrix(c(
  'sleep_time', 's', 1, "numeric", "Sleep time in seconds [default 1]",
  'size', 'n', 1, "numeric", "Size of the problem N [default 1E6]",
  'monitor_step', 'm', 1, "numeric", "Monitoring step in seconds [default 0.001]",
  'help', 'h', 0, "logical", "Show this help message and exit"
), byrow = TRUE, ncol = 5)

# Parse command line options
opt <- getopt(spec)


# Assign command line arguments to variables
if(is.null(opt$sleep_time)) opt$sleep_time<-1
if(is.null(opt$size)) opt$size<-1E6
if(is.null(opt$monitor_step)) opt$monitor_step<-0.001

sleep_time <- opt$sleep_time
N <- opt$size
step_of_monitor <- opt$monitor_step

busy_wait <- function(seconds) {
  start_time <- Sys.time()
  stop_time <- Sys.time()
  while (difftime(stop_time, start_time, units = "secs") < seconds) {
    stop_time <- Sys.time()
  }
}

bench_time_mem<-function(x) {
	gc(reset=FALSE,verbose=FALSE)  ## force a gc here
	pidfile <- tempfile() # temp file to story Perl's PID
	outfile <- tempfile() # stdout redirection for Perl
	pid <- Sys.getpid()   # get R's PID
	ret<-NULL
	system2("./monitor_memory.pl", 
		c(pid,step_of_monitor,pidfile),wait=FALSE,stdout=outfile)
	Sys.sleep(0.2)  # Wait for PID file to be written
	monitor_pid <- readLines(pidfile)[1] # Get Perl's PID
	tryCatch (
		expr = {
			mem<-profmem(time<-system.time(x,gcFirst = FALSE))
			rettime<-c(time)
			names(rettime)<-names(time)
			retval<-c(time,"R_gc_alloc" = sum(mem$bytes,na.rm=T))
		}, # execute R expression, get timing and allocations
		finally = {
			system2("kill",c("-TERM", monitor_pid)) # kill the ? orphan
			Sys.sleep(0.2) # Wait for Perl to finish logging
			memstats<-read.csv(outfile,sep="\t",
				header=FALSE) # get memory statistics
			unlink(c(pidfile,outfile)) #cleanup files
			retval<-c(retval ,
				  "delta"= memstats[1,1]*1024,
				"initial"= memstats[1,2]*1024
				)
		}
	)

	return(retval)
}



val<-bench_time_mem(
	{  	
		busy_wait(sleep_time);
		cat("\nAllocating\n")
		q<-rnorm(N);
		busy_wait(sleep_time);
		rm(q);gc(reset=F)
		q2<-rnorm(N);
		busy_wait(sleep_time);
		rm(q2);gc(reset=F)
	}
)

valcp<-bench_time_mem(
	{  
		busy_wait(sleep_time);
		cat("\nAllocating\n")
		q<-rnorm(N*2);
		busy_wait(sleep_time*2);
	}
)




cat("\n Allocating a double vector of length N = ",N," in R")
cat("\n            with busy waiting period  T = ",sleep_time," seconds")
cat("\n            and monitoring memory every : ",step_of_monitor," seconds")
cat("\n Will allocate N->gc->N and then 2N at once\n")
cat(paste(rep("=",65),collapse=""))
cat("\n Measured vs alloc'd in R  (2N at once): ", valcp["delta"]/valcp["R_gc_alloc"])
cat("\n Measured vs alloc'd in R  (N-> gc ->N): ", val["delta"]/val["R_gc_alloc"])
cat("\n")
cat("\n Performance of the two allocations : ")
cat("\n N-> gc ->N : \n")
print(val)
cat("\n 2N at once : \n")
print(valcp)

Running this from the command line we obtain the following output:

Rscript --vanilla  profile_time_memory.R -s 1 -n 1000000 -m 0.00001

Allocating

Allocating

 Allocating a double vector of length N =  1e+06  in R
            with busy waiting period  T =  1  seconds
            and monitoring memory every :  1e-05  seconds
 Will allocate N->gc->N and then 2N at once
=================================================================
 Measured vs alloc'd in R  (2N at once):  0.995325
 Measured vs alloc'd in R  (N-> gc ->N):  0.4750328

 Performance of the two allocations : 
 N-> gc ->N : 
   user.self     sys.self      elapsed   user.child    sys.child   R_gc_alloc 
       3.135        0.022        3.163        0.000        0.000 16210416.000 
       delta      initial 
 7700480.000 76742656.000 

 2N at once : 
   user.self     sys.self      elapsed   user.child    sys.child   R_gc_alloc 
       3.088        0.017        3.110        0.000        0.000 16000048.000 
       delta      initial 
15925248.000 84443136.000 

As you can see the Perl monitor identified that the peak memory use of the sequential allocation-deallocation-allocation was half than of a single-step allocation of the entire workspace. The Perl application’s ability to monitor the process in very fine resolution (theoretically up to nanosec, but reallistically one microsecond is where I’d draw the limit), comes handy when one has to monitor spikes in peak memory usage. Consider the example, in which some recently allocated memory is used for a fast task and then discarded (this is simulated by providing a small value to the s argument of the script). At low resolution, our estimates of the peak memory use are biased, e.g. :

Rscript --vanilla  profile_time_memory.R -s .001 -n 1000000 -m 0.1

Allocating

Allocating

 Allocating a double vector of length N =  1e+06  in R
            with busy waiting period  T =  0.001  seconds
            and monitoring memory every :  0.1  seconds
 Will allocate N->gc->N and then 2N at once
=================================================================
 Measured vs alloc'd in R  (2N at once):  0.07372778
 Measured vs alloc'd in R  (N-> gc ->N):  0.3777522

 Performance of the two allocations : 
 N-> gc ->N : 
   user.self     sys.self      elapsed   user.child    sys.child   R_gc_alloc 
       0.154        0.012        0.165        0.000        0.000 16210416.000 
       delta      initial 
 6123520.000 76742656.000 

 2N at once : 
   user.self     sys.self      elapsed   user.child    sys.child   R_gc_alloc 
       0.108        0.011        0.119        0.000        0.000 16000048.000 
       delta      initial 
 1179648.000 84635648.000 

However changing the resolution of monitoring re-establishes accuracy:

Rscript --vanilla  profile_time_memory.R -s .001 -n 1000000 -m 0.0001 
Allocating

Allocating

 Allocating a double vector of length N =  1e+06  in R
            with busy waiting period  T =  0.001  seconds
            and monitoring memory every :  1e-04  seconds
 Will allocate N->gc->N and then 2N at once
=================================================================
 Measured vs alloc'd in R  (2N at once):  0.995325
 Measured vs alloc'd in R  (N-> gc ->N):  0.4750328

 Performance of the two allocations : 
 N-> gc ->N : 
   user.self     sys.self      elapsed   user.child    sys.child   R_gc_alloc 
       0.180        0.007        0.188        0.000        0.000 16210416.000 
       delta      initial 
 7700480.000 76746752.000 

 2N at once : 
   user.self     sys.self      elapsed   user.child    sys.child   R_gc_alloc 
       0.119        0.009        0.128        0.000        0.000 16000048.000 
       delta      initial 
15925248.000 84447232.000 

Having described the solution, let’s provide some limitations and a context of use that acknowledges these limitations and some extensions:

  • Small allocations (e.g. 100k doubles or below) will be invisible to the Perl monitor. This appears to be related to how the OS manages memory and how the kernel updates the page that is raided by ps for data
  • This code is thus best used to monitor large allocations in long calculations
  • One can extend the Perl monitor to take action with respect to R if memory usage grows at an unstainable rate, alert the user etc (
  • important in my mind for large tasks executing remotely e.g. over the weekend). This is an interesting extension for future work
  • One can easily extend the Perl to work under MacOs (trivial - as it has a ps command line utility), and Windows, e.g. run R under WSL2 or use tasklist instead of ps (another possible extension)

I hope you enjoyed this journey with R and Perl so far! Have fun until the next time.

(dxxxi) 9 great CPAN modules released last week & perl 5.40.1

r/perl

Published by /u/niceperl on Saturday 18 January 2025 20:55

(dxxxi) 9 great CPAN modules released last week & perl 5.40.1

Niceperl

Published by Unknown on Saturday 18 January 2025 21:55

Updates for great CPAN modules released last week. A module is considered great if its favorites count is greater or equal than 12.

  1. Catmandu - a data toolkit
    • Version: 1.2024 on 2025-01-16, with 23 votes
    • Previous CPAN version: 1.2022 was 3 months, 17 days before
    • Author: NICS
  2. CPAN::Audit - Audit CPAN distributions for known vulnerabilities
    • Version: 20250115.001 on 2025-01-15, with 14 votes
    • Previous CPAN version: 20250109.001 was 5 days before
    • Author: BRIANDFOY
  3. DateTime::TimeZone - Time zone object base class and factory
    • Version: 2.64 on 2025-01-17, with 20 votes
    • Previous CPAN version: 2.63 was 4 months, 10 days before
    • Author: DROLSKY
  4. DBD::CSV - DBI driver for CSV files
    • Version: 0.62 on 2025-01-13, with 25 votes
    • Previous CPAN version: 0.60 was 2 years, 7 days before
    • Author: HMBRAND
  5. DBIx::Class - Extensible and flexible object <-> relational mapper.
    • Version: 0.082844 on 2025-01-16, with 290 votes
    • Previous CPAN version: 0.082843 was 2 years, 7 months, 30 days before
    • Author: RIBASUSHI
  6. Feersum - A PSGI engine for Perl based on EV/libev
    • Version: 1.504 on 2025-01-17, with 13 votes
    • Previous CPAN version: 1.503 was 4 months before
    • Author: EGOR
  7. Graph - graph data structures and algorithms
    • Version: 0.9733 on 2025-01-12, with 27 votes
    • Previous CPAN version: 0.9704 was 9 years, 3 months, 5 days before
    • Author: ETJ
  8. perl - The Perl 5 language interpreter
    • Version: 5.040001 on 2025-01-18, with 425 votes
    • Previous CPAN version: 5.40.0 was 7 months, 9 days before
    • Author: SHAY
  9. SPVM - The SPVM Language
    • Version: 0.990039 on 2025-01-17, with 34 votes
    • Previous CPAN version: 0.990038 was 8 days before
    • Author: KIMOTO

(dxcviii) metacpan weekly report - List::MoreUtils

Niceperl

Published by Unknown on Saturday 18 January 2025 21:53

This is the weekly favourites list of CPAN distributions. Votes count: 49

Week's winners (+3): List::MoreUtils

Build date: 2025/01/18 20:44:03 GMT


Clicked for first time:


Increasing its reputation:

Profiling Peak DRAM Use in R With Perl - Part 1

Killing-It-with-PERL

Published on Saturday 18 January 2025 00:00

Another year, another opportunity for Perl to excel as a system’s language. Today I decided to take Perl for a (?)wild ride and use it to monitor peak physical DRAM use in a R script. Due to the multi-language nature of the post, there will be a lot of R code in the first part of the series; however, the code is self-explanatory, and should not be difficult to understand (the same applies to the Perl code for those coming from a R background). For those of you who would like to skip the R part (why?), jump straight to the end Part 1 to see the solution and then go to Part 2 for the details.

First, a little bit of background about R’s memory management and the tools that one can use within R to monitor how the process is managing memory. R similar to Perl (?)frees the programmer from having to manage memory manually by providing dynamically allocated containers. R features a garbage collector, which similar to Perl’s uses a reference counting mechanism to return memory back to the operating system. Managing memory in R is as critical as managing memory in Perl, and there are tools available that are built-in the language (the Names and Values in the 2nd edition of the book “Advanced R” is a valuable introduction to memory management, while the Chapter Memory in the first edition of that book is also a useful read). The basic tool used to profile R code is the builtin function Rprof that samples the call stack and writes it out to a log-file that can be subsequently parsed. In the documentation of Rprof, one finds the following disclaimer:

     Note that the (timing) interval cannot be too small.  With
     ‘"cpu"’, the time spent in each profiling step is currently added
     to the interval.  With all profiling events, the computation in
     each profiling step causes perturbation to the observed system and
     biases the results.  What is feasible is machine-dependent.  On
     Linux, R requires the interval to be at least 10ms, on all other
     platforms at least 1ms.  Shorter intervals will be rounded up with
     a warning.

The relative slow sampling frequencing implies that one must somehow slow the code down to capture peak memory usage. One solution for those of us in Linux systems is to take the hint and release the valgrid Kraken as detailed in Profiling R code for memory use; this will really slow the code down and then we can capture stuff (note that taking the hint, also applies to Perl, i.e. see Test::Valgrind in MetaCPAN). But ultimately, we would like not to slow the code that much, especially if we are also trying to obtain performance information at the same time as we profile the memory.

Assuming that one does not want to use an interactive tool to profile the code (the excellent profvis comes to mind), then one is stuck with the low-level option provided by Rprof logging and summaryRprof parsing. This leads us to the next question: what is the overhead by these tools? Overhead is paid in both hard disk space and execution time. Let’talk about space first: for a high resolution logging (e.g. sampling every 10msec), the log file will grow by ~ 10kb per second of calculation. This may not seem much, but profiling an involved calculation quickly adds up: to profile an expression that takes 10shr to execute will consume 10 x 3600 x 10 = 360000 KB ~ 360MB (incidentally ~10hr is the longest calculation I have ever done in R).To give a sense of measure, the total size of the files in my /var/log is ~1.1GB. And yes, while hard-disks are getting bigger, this is no excuse to fill them with log files! To give an idea of the time overhead, we will need to provide an alternative to hard-disk logging (hint: this will be a Perl program!), but first let’s provide a straightforward R implementation of a logging function.

bench_time_mem<-function(x) {  ## x is the R expression to profile
  gc(reset=FALSE,verbose=FALSE)  ## force a gc here
  profing_fname <- tempfile() ## create a temporary file
  Rprof(filename=profing_fname, memory.profiling=TRUE,interval=0.01)
  time<-system.time(x,gcFirst = FALSE)
  Rprof(NULL) ## stop profiling and logging
  memprof<-summaryRprof(profing_fname, memory="tseries",lines="hide",diff=TRUE)
  mem_alloc<-sum(memprof[-1,"vsize.large"]) ## get memory allocated via malloc
  time_prof<-summaryRprof(profing_fname, memory="none",lines="hide",diff=TRUE)
  times<-time_prof$by.total[2,-2]
  retval<-unlist(c(times[1,1],mem_alloc,file.info(profing_fname)$size))
  unlink(profing_fname) ## delete the logfiles
  names(retval)<-c("total_time","R_gc_alloc","logfile_size")
  retval
}

The code should be self-explanatory even for non R users : it first triggers the garbage collector, and then in sequence creates a temporary file, starts logging to that file, execute the R expression (R code within brackets, similar to how one would provide an anonymous code reference in Perl), then parses the file to get memory usage and timing), and returns the total time, the size of the memory allocated by R in the stack, when running the expression and the size of the log file.

Here is a minimally working example:

## function for busy waiting for a fixed number of seconds
busy_wait <- function(seconds) {
  start_time <- Sys.time()
  stop_time <- Sys.time()
  while (difftime(stop_time, start_time, units = "secs") < seconds) {
    stop_time <- Sys.time()
  }
}

N<-100000
work_time <- 1 # second(s)

val<-bench_time_mem(
	{  	
		busy_wait(work_time);  ## work without allocation
		cat("\nAllocating\n")
		q<-rnorm(N);            ## Gaussian random variables
		busy_wait(work_time);   ## work without allocation
		rm(q);gc(reset=F)       ## free memory/trigger the gc
		q2<-rnorm(N);           ## another allocation
		busy_wait(work_time);   ## busy working!
		rm(q2);gc(reset=F)      ## free the memory yet again

	}
)

In this example, we first provide an implementation of a function busy_wait that simulates a work load without further allocation. The actual code to be profiled, alternates periods of busy waiting with allocation and de-allocation. With the values of N and work_time in the code snippet, I obtain the following code profile summary:

> val
  total_time   R_gc_alloc logfile_size 
         3.4    1600000.0      32446.0 

Let’s talk about these figures: first note that parsing the Rprof, does not allow one direct access to the peak memory used during the calculation (only the total amount of memory allocated in the stack. While this information is crucial for performance, i.e. one pays a price for every byte moved around, it is not very informative about whether t he program will even run in the machine, as the datasets scale: R processes data in memory, and when the physical memry is exhausted, the operating system will put the R process out of its misery. In the example above, the peak memory usage while the expression executes is N*8 (since rnorm returns a double precision floating number in C parlance), but since two allocations were done, the profiler cn only report their sum. In fact, the output is virtually indistinguishable from the following code which allocates an array of 2 x N doubles in a single go.

valcp<-bench_time_mem(
	{  
		busy_wait(work_time);
		cat("\nAllocating\n")
		q<-rnorm(N*2);
		rm(q);gc(reset=F)
		busy_wait(work_time*2);
	}
)

and

valcp
  total_time   R_gc_alloc logfile_size 
         3.2    1600000.0      30773.0 

Whie both codes allocated the same total amount of memory, the first code would work if one allocated the entirety of the free memory in a given machine, while the second would croak when roughly half the free memory was requested.

The difference of ~0.2sec execution time, is the price one has to pay for triggering R’s garbage collector. The following shows that while allocating an array of 10^5 doubles and filling it with random numbers is very fast (it takes 6msec in my machine), triggering the gaarbage collector is 32x slower.

> system.time(rnorm(N))
   user  system elapsed 
  0.006   0.000   0.006


> system.time({q<-rnorm(N);rm(q);gc(reset=FALSE)})
   user  system elapsed 
  0.193   0.000   0.194 

So how can one get the peak DRAM usage without logging anything to the hard disk? The answer, which will be provided in Part 2, blends together R and Perl and is conceptually very simple, design-wise:

  • write a Perl script that probes the ps command line utility for resident set size (RSS) i.e. the footprint of the R process in DRAM.
  • put the probing of the RSS in a monitoring loop, so that awakens periodically to sample the size of the RSS in realtime and compares
  • it to that at the beginning of the monitoring phase
  • start the Perl monitoring script as sub-process of the R process, provide it with the Process ID (PID) of the R process and put it in the background
  • when the R expression concludes, kill the Perl process and report the maximum difference of the RSS from the baseline; this gives the peak (over the baseline) footprint of the program in DRAM.

(to be continued…)

Isn’t Perl Dead

…let’s just move on shall we ;-)

Essential Knowledge for Perl Consultants

So you want to be the guy, the one that swoops in to the shop that has been saddled with the legacy Perl application because you’ve been doing Perl since the last century? You know that shop, they have a Perl application and a bunch of developers that only do Python and they’ve suddenly becom allergic to learning something new (to them). From my own experience, here are some of the technologies you’ll encounter and should be familiar with to be the guy.

  • [x] mod_perl
  • [x] FastCGI
  • [x] Moose
  • [x] HTML::Template
  • [x] Mason
  • [ ] Template::Toolkit

I checked off the things I’ve encountered in my last three jobs.

Of course, the newer Perl based frameworks are good to know as well:

  • Mojolicious
  • Catalyst

Some “Nice to Knows”

  • Apache
  • docker
  • cpanm
  • carton
  • make
  • bash

…and of these, I think the most common thing you’ll encounter on sites that run Perl applications is mod_perl.

Thar’s gold in them thar hills!

Well, maybe not gold, but certainly higher rates and salaries for experienced Perl developers. You’re a unicorn! Strut your stuff. Don’t back down and go cheap. Every day someone leaves the ranks of Perl development only to become one of the herd leaving you to graze alone.

Over the last three years I’ve earned over a half-million dollars in salary and consulting fees. Some of you are probably earning more. Some less. But here’s the bottom line, your skills are becoming scarcer and scarcer. And here’s the kicker…these apps aren’t going away. Companies are loathe to touch some of their cash cows or invest in any kind of “rewrite”. And here’s why…

  • They don’t know what the application even does!
  • They don’t have any bandwidth for rewriting applications that “work”.
  • They love technical debt or never even heard of it.

And here’s what they want you do for a big pile of their cash:

  • fix a small bug that may take you a day to find, but only a minute to fix
  • upgrade their version of perl
  • upgrade the platform the app runs on because of security vulnerabilities
  • containerize their application to run in the cloud
  • add a feature that will take a you a week to find out how to implement and a day to actually implement

The Going Rate?

According to the “interweb” the average salary for an experienced Perl developer is around $50/hour or about $100K or so. I’m suspicious of those numbers to be honest. Your mileage may vary but here’s what I’ve been able to get in my last few jobs:

  • $180K/year + bonus
  • $160K/year + a hearty handshake
  • $100/hour

…and I’m not a great negotiator. I do have over 20 years of experience with Perl and over 40 years of experience in IT. I’m not shy about promoting the value of that experience either. I did turn down a job for $155K/year that would have required some technical leadership, a position I think should have been more like $185k/year to lead a team of Perl developers across multiple time zones.

Your best prospects are…your current customers!

Even if you decide to leave a job or are done with an assignement, don’t burn bridges. Be willing to help them with a transition. Be polite, ask for a recommendation if appropriate. If they’re not planning on rehiring, they may be willing to contract with you for spot assignments.

Some Miss Manners Advice

  • Be nice…always
  • Suggest improvements but don’t be upset if they like the crappy app just the way it is
  • Write good documentation! Help someone else pick up your work (it could be you a year from now).
  • Be a mentor but not a know-it-all, you don’t know-it-all, and nobody likes a know-it-all even if you do
  • Don’t be stubborn and fight with the resident guru unless his bad decision is about to take the company off the cliff (and even then don’t fight with him, take it to the boss)
  • Ask questions and take a keen interest in their domain, you never know when a similar job might present itself

Yet Another Perl-Powered Company: Geolytica

perl.com

Published on Thursday 16 January 2025 09:00

Imagine you want to parse free-form address input and match it against a database representing the road network.

Example 1

  • Input: "751 FAIR OKS AVENUE PASADNA CA"
  • Output: "751 N Fair Oaks AVE, Pasadena, CA 91103-3069 / 34.158874,-118.151053" View example

Example 2

  • Input: "5 Adne Edle Street, London"
  • Output: "5 THREADNEEDLE STREET, LONDON, United Kingdom EC3V 3NG" View example

The database contains road names, shapes, numbers, zip/postal codes, city names, regions, neighborhood/district names, and more—billions of named location entities worldwide. Add another 100 million points of interest extracted from billions of webpages, and the problem becomes quite difficult.

Two decades of Perl coding, starting in 2005, and this problem is (mostly) solved at Geolytica.


Geolytical logo

Perl at Geolytica

At Geolytica, we harness Perl to manage and enhance vast geo-location datasets and build the application logic of the geocoding engines powering geocoder.ca and geocode.xyz.

Data Cleanup and Enhancement

We continuously update and enhance our location entities database, because ground truth changes - at the speed of life. One standout example is our work with OpenStreetMap’s POI data. A year ago, we utilized an in-house AI tool, (let’s call it “PerlGPT,”) to refine this dataset, correcting inconsistencies and enhancing data quality. The results were significant enough to share with the community at Free POI Data.

Perl’s Versatility and Stability

The beauty of Perl lies in its backward compatibility. Despite our codebase spanning over two decades, upgrading Perl across versions has never broken our code. In contrast, with other languages, we’ve observed issues like API changes causing extensive refactoring or even rewrites. Perl’s design allows for seamless integration of old and new code, which is vital for our specific needs.

Practical Implementation

At Geolytica, tasks like parsing location entities from text involve complex string manipulations. As shown in the examples above, these challenges would be difficult in any programming language, but Perl makes them easier than other options.


Final Thoughts

The best programming language for any job is the one that makes hard problems easy and impossible ones possible. For Geolytica, that language is Perl.


About the Author

Ervin Ruci has been immersed in Perl since 1998, initially building student information systems at Mount Allison University, then registry systems for CIRA from 2000 to 2005. In 2005, he became a location-independent entrepreneur, founding Geolytica to tackle the location intelligence problem.

How I used a named pipe to save memory and prevent crashes (in Perl)

dev.to #perl

Published by Nicholas Hubbard on Wednesday 15 January 2025 16:13

I recently ran into an interesting bug in my Slackware package manager sbozyp. In this post I will detail the bug and my solution.

Disclaimer: The code snippets in this post do not deal with every edge case and are only meant to convey the ideas relevant to this blog post. All important edge cases are dealt with in the actual code for sbozyp.

Sbozyp is a package manager for SlackBuilds.org, a repository of build scripts for Slackware packages. There is a very important subroutine in sbozyp named build_slackware_pkg() that (basically) takes the name of a package, builds it into a Slackware package, and returns the path to the built package. To build the package we must execute the packages SlackBuild script. A SlackBuild script always has the general form: { basic setup -> perform build procedure -> conglomerate built parts into a Slackware package }. The last step is always performed by a Slackware-specific tool called makepkg. Unfortunately there is no way (that I know of) to be able to determine the name of the Slackware package before executing the SlackBuild script. For this reason sbozyp must inspect the stdout of the SlackBuild script to look for a line that makepkg always outputs that looks like Slackware package $PATH created. It is also important of course that the user can see the output of the SlackBuild script as it may contain vital information. This means that both my program and the user needs to examine the output of the SlackBuild script. (See here for more information on SlackBuild scripts)

With the problem description out of the way we can now focus on the solution.

My original solution was an obvious one but had an interesting bug. I simply would use Perl's system command to execute the SlackBuild script with a shell, where I would pipe stdout to tee, writing the stdout to a temporary file. After the SlackBuild would execute I would read the temporary file looking for the Slackware package $PATH created line. This solved the problem of allowing both the user and sbozyp to read the stdout of the SlackBuild script. For 99% of builds this worked fine ... but then there was qemu. Qemu is a massive project that requires a huge compilation. My system uses a small 4GB tmpfs mounted at /tmp, and the temporary file that was being teed to ended up getting so large from all the qemu compilation output that tee (and thus sbozyp) crashed for "device out of space".

Here is a basic (not actually realistic to sbozyp) outline of that code:

sub build_slackware_pkg {
    my ($pkg_name) = @_;
    my $slackbuild_script = find_slackbuild_script($pkg_name);
    my $tmp_file = make_temp_file(DIR=>'/tmp');
    0 == system("set -o pipefail; $slackbuild_script | tee $tmp_file") or die;
    open my $fh, '<', $tmp_file or die;
    my $slackware_pkg;
    while (my $stdout_line = <$tmp_file>) {
        $slackware_pkg = $1 if $stdout_line =~ /^Slackware package (.+) created$/;
    }
    return $slackware_pkg;
}

To solve the problem I create a named pipe, fork, and use the child process to execute the SlackBuild script, teeing stdout to the named pipe. From the parent I read the named pipe looking for the magic Slackware package $PATH created line. Here is a (also not realistic to sbozyp) outline of this code:

use POSIX qw(mkfifo WNOHANG);

sub build_slackware_pkg {
    my ($pkg_name) = @_;
    my $slackbuild_script = find_slackbuild_script($pkg_name);
    my $tmp_dir = make_temp_dir(DIR=>'/tmp');
    mkfifo("$tmp_dir/fifo", 0700);
    my $pid = fork();
    if ($pid == 0) { # child
        0 == system("set -o pipefail; $slackbuild_script | tee $fifo") or die;
        exit 0;
    } else { # parent
        open my $fifo_r_fh, '<', $fifo or die;
        my $slackware_pkg;
        while (waitpid($pid, WNOHANG) == 0 or my $stdout_line = <$fifo_r_fh>) {
            $slackware_pkg = $1 if $stdout_line and $stdout_line =~ /^Slackware package (.+) created$/;
        }
        die if $? != 0; # $? has exit status of child
        return $slackware_pkg;
    }
}

This implementation saves disk space as the data is being teed to a named pipe instead of a regular file in /tmp. As data is written to the pipe it is immediately being read, throwing away all the data that sbozyp doesn't need.

Problem solved :)

(Thanks to thrig on the #perl Libera IRC channel for helping lead me to this solution)

EDIT

I got some great feedback from u/gorkish on reddit with a much simpler way to solve the problem by running the SlackBuild script with open instead of system. Here is the code:

sub build_slackware_pkg {
    my ($pkg_name) = @_;
    my $slackbuild_script = find_slackbuild_script($pkg_name);
    open(my $cmd, '-|', $slackbuild_script) or die $!;
    my $slackware_pkg;
    while (my $line = <$cmd>) {
        $slackware_pkg = $1 if $line =~ /^Slackware package (.+) created$/;
        print $line;
    }
    close $cmd;
    die if $? != 0;
    return $slackware_pkg;
}

Creating MIDI Music with Perl

perl.com

Published on Wednesday 15 January 2025 09:00

Music is a vast subject

It is older than agriculture and civilization itself. We shall only cover the essential parts needed to make music on the computer. So let’s get right to the point!

How do you make music with code? And what is music in the first place?

Well, for our purposes, music is a combination of rhythm, melody, and harmony.

Okay, what are these musical elements from the perspective of a programming language? And how do you create these elements with code? Enter: Perl.

Set Up, Play, Write

Here is a basic algorithm that builds an ascending musical phrase two times. It uses named notes with the octave (e.g. C4):

use MIDI::Util qw(setup_score);

my $score = setup_score();

for (1 .. 2) {
  for my $note (qw(C4 D4 E4 F4)) {
    $score->n('qn', $note); # Adds a quarter note
    $score->r('qn');        # Adds a quarter note rest
  }
}

$score->write_score("$0.mid");

Rendering Audio

In order to actually hear some sound, you can either play the MIDI directly, with a command-line player like timidity and an sf2 “soundfont” file, as in this list. Also the MIDI file can be used to create an audio formatted file (e.g. WAV, MP3) that can be played. Here is the command for this, that I use on my Mac:

timidity -c ~/timidity.cfg some.mid -Ow -o - | ffmpeg -i - -acodec libmp3lame -ab 64k some.mp3

These command line switches do the following things: -Ow = Generate RIFF WAVE format output. -o - = Place output on stdout. -i - = Specify the infile as stdin. -acodec libmp3lame = Specify that we are converting to mp3 format. -ab 64k = Set the bitrate (in bits/s).

But wait! You can also generate and play MIDI in real-time with the MIDI::RtMidi::FFI::Device and MIDI::RtMidi::ScorePlayer modules. :D

Back to Creating Music!

So far, we have encountered the “Set up, Play, and Write” algorithm. Next we shall replace the “Play” bit with “Sync” and play the bass and treble parts simultaneously (and again, we use a named note plus octave number in each of the subroutines):

use MIDI::Util qw(setup_score);

my $score = setup_score();

$score->synch(
  sub { bass($score) },
  sub { treble($score) },
);

$score->write_score("$0.mid");

sub bass {
  my ($score) = @_;
  for my $note (qw(C3 F3 G3 C4)) {
    $score->n('qn', $note);
  }
}

sub treble {
  my ($score) = @_;
  for my $note (qw(C4 D4 E4 F4)) {
    $score->n('en', $note);
    $score->r('en');
  }
}

This code is not especially clever, but illustrates the basics.

If we want to repeat the phrase, just add a for loop to the synch:

$score->synch(
  sub { bass($score) },
  sub { treble($score) },
) for 1 .. 4;

Setting Channels, Patches, Volume, and Tempo

Use the MIDI::Util::set_chan_patch() function to set the channel and the patch. To set the tempo in “beats per minute”, give a bpm to the setup_score() function. To set an individual note volume, add "v$num" as an argument to the $score->n() method, where $num is an integer from 0 to 127. Here is code that sets these parameters:

use MIDI::Util qw(setup_score set_chan_patch);

my $bpm = shift || 120;

my $score = setup_score(bpm => $bpm);

$score->synch(
  sub { bass($score) },
  sub { treble($score) },
);

$score->write_score("$0.mid");

sub bass {
  my ($score) = @_;
  set_chan_patch($score, 0, 35);
  for my $note (qw(C3 F3 G3 C4)) {
    $score->n('qn', $note, 'v127');
  }
}

sub treble {
  my ($score) = @_;
  set_chan_patch($score, 1, 0);
  for my $note (qw(C4 D4 E4 F4)) {
    $score->n('en', $note, 'v110');
    $score->r('en');
  }
}

If the synched subroutines do not amount to the same number of beats, the synch will probably not work as expected, and will stop playing the shorter part and keep playing the longer part until it is finished.

Selecting Pitches

What if we want the program to choose notes at random, to add to the score? Here is a simple example:

sub treble {
  my ($score) = @_;
  set_chan_patch($score, 1, 0);

  my @pitches = (60, 62, 64, 65, 67, 69, 71, 72);

  for my $n (1 .. 4) {
    my $pitch = $pitches[int rand @pitches];
    $score->n('en', $pitch);
    $score->r('en');
  }
}

For MIDI-Perl, the named note with octave C4 and the MIDI number 60 are identical, as shown in the tables on this page.

Another, more “music-theory way” is to select notes from a named scale (and this time, over two octaves):

use Music::Scales qw(get_scale_MIDI);
# ...

sub treble {
  my ($score) = @_;
  set_chan_patch($score, 1, 0);

  my $octave = 4;

  my @pitches = (
    get_scale_MIDI('C', $octave, 'major'),
    get_scale_MIDI('C', $octave + 1, 'major'),
  );

  for my $n (1 .. 4) {
    my $pitch = $pitches[int rand @pitches];
    $score->n('en', $pitch);
    $score->r('en');
  }
}

Single Notes, Basslines, and “Melody”

We saw above, how to select pitches at random. But this is the least musical or interesting way. Pitches may be selected by interval choice, as with the excellent Music::VoiceGen module. You could also choose by mathematical computation with Music::Voss (code example), or a probability density, or an evolutionary fitness function, etc.

Basslines are single note lines in a lower register. They have their own characteristics, which I will not attempt to summarize. One thing you can do is to make sure your notes are in the octaves 1 to 3. Fortunately, there is a module for this very thing called Music::Bassline::Generator. Woo!

So what is a melody? Good question. I’ll leave out the long-winded music theory discussion, and just say, “Go forth and experiment!”

Chords and Harmony

We can construct chords at random - oof:

use Data::Dumper::Compact qw(ddc);
use MIDI::Util qw(setup_score);
use Music::Scales qw(get_scale_MIDI);

my @pitches = (
    get_scale_MIDI('C', 4, 'minor'),
    get_scale_MIDI('C', 5, 'minor'),
);

my $score = setup_score();

for my $i (1 .. 8) {
  my @chord = map { $pitches[int rand @pitches] } 1 .. 3;
  print ddc(\@chord);
  $score->n('hn', @chord);
  $score->r('hn');
}

$score->write_score("$0.mid");

We can construct chord progressions by name:

use Data::Dumper::Compact qw(ddc);
use MIDI::Util qw(setup_score midi_format);
use Music::Chord::Note;

my $score = setup_score();

my $mcn = Music::Chord::Note->new;

for my $c (qw(Cm7 F7 BbM7 EbM7 Adim7 D7 Gm)) {
  my @chord = $mcn->chord_with_octave($c, 4);

  @chord = midi_format(@chord); # convert to MIDI-Perl notation
  print ddc(\@chord);

  $score->n('wn', @chord);
}

$score->write_score("$0.mid");

Chord progressions may be constructed algorithmically. Here is an example of a randomized state machine that selects chords from the major scale using the default settings of the Music::Chord::Progression module:

use Data::Dumper::Compact qw(ddc);
use MIDI::Util qw(setup_score);
use Music::Chord::Progression;

my $score = setup_score();

my $prog = Music::Chord::Progression->new;
my $chords = $prog->generate;
print ddc($chords);

$score->n('wn', @$_) for @$chords;

$score->write_score("$0.mid");

Advanced Neo-Riemannian operations can be used with the Music::Chord::Progression::Transform module.

To get chord inversions, use the Music::Chord::Positions module. For instance, say we have a chord like C major (C4-E4-G4), and we want the first or second inversion. Sure, we could just rewrite it to be E4-G4-C5 or G4-C5-E5 - but that’s not programming! The inversion of a chosen chord can be programmatically altered if deemed necessary.

Phrasing

This bit requires creativity! But fortunately, there is also the Music::Duration::Partition module. With it, rhythms can be generated and then applied to single-note, chord, or drum parts. This time, let’s choose the pitches more musically with Music::VoiceGen:

use MIDI::Util qw(setup_score);
use Music::Duration::Partition ();
use Music::Scales qw(get_scale_MIDI);
use Music::VoiceGen ();

my $score = setup_score();

# get rhythmic phrases
my $mdp = Music::Duration::Partition->new(
    size => 4,                  # 1 measure in 4/4
    pool => [qw(hn dqn qn en)], # half, dotted-quarter, quarter, eighth notes
);
my @motifs = $mdp->motifs(4);

# assign voices to the rhythmic motifs
my @pitches = (
  get_scale_MIDI('C', 4, 'minor'),
  get_scale_MIDI('C', 5, 'minor'),
);
my $voice = Music::VoiceGen->new(
    pitches   => \@pitches,
    intervals => [qw(-3 -2 -1 1 2 3)], # allowed interval jumps
);
my @voices;
for my $motif (@motifs) {
    my @notes = map { $voice->rand } @$motif;
    push @voices, \@notes;
}

for (1 .. 4) { # repeat the group of phrases 4 times
    for my $n (0 .. $#motifs) {
        # add each motif with corresponding voices, to the score
        $mdp->add_to_score($score, $motifs[$n], $voices[$n]);
    }
}

$score->write_score("$0.mid");

Sidebar: Modulo arithmetic

If we want to stay within a range, say the chromatic scale of all notes, use the % operator:

use Data::Dumper::Compact qw(ddc);
use Music::Scales qw(get_scale_notes);

my @notes = get_scale_notes('C', 'chromatic');

my %tritones = map { $notes[$_] => $notes[ ($_ + 6) % @notes ] } 0 .. $#notes;
print ddc(\%tritones);

(The “tritone” is a musical interval, once considered to be the “Devil’s interval.” 🎶 Purple haze all in my brain 🎶)

Sidebar: Alternation math

If we want to change every other iteration, we can also use the % operator:

if ($i % 2 == 0) {
  $score->n('qn', $pitch);
  $score->r('qn');
}
else {
  $score->n('hn', $pitch);
}

Beats!

A steady pulse:

use MIDI::Drummer::Tiny;

my $d = MIDI::Drummer::Tiny->new;

$d->count_in(4);  # Closed hi-hat for 4 measures

$d->write;

A simple “backbeat” rhythm:

use MIDI::Drummer::Tiny;

my $d = MIDI::Drummer::Tiny->new(file => "$0.mid");

$d->note(
    $d->quarter,
    $d->closed_hh,
    $_ % 2 ? $d->kick : $d->snare
) for 1 .. $d->beats * $d->bars;

$d->write;

With this module, you can craft unique grooves like John Bonham’s “Fool in the Rain” (code example):

With combinatorial sequences from Music::CreatingRhythms, you can make algorithmic drums (code example):

And how about random grooves (code example)?

Please see the tutorials in the MIDI-Drummer-Tiny distribution for details on how to implement beats in your program.

Differentiation of Parts

This is an involved subject. Ideally, the different parts of a composition are distinct. If the piece starts slow (i.e. with a low note density per measure - not tempo change), then the next section should be more dense, then less again. Start quiet and soft? Follow with loud. If a part is staccato and edgy, it may be followed by a smooth legato section. Low register first, then higher register next, etc, etc. If a piece never changes, it is monotonous!

However that being said, consider “Thursday Afternoon” by Brian Eno. Brilliant.

Conclusion

You too can make music with Perl! This can be comprised of single-note lines (melody and bass, for instance), chord progressions, and of course drums. * Creativity not included. Haha!

References

The example code for this article

MIDI::Util

Music::Scales

Music::VoiceGen

Music::Voss

Music::Bassline::Generator

Data::Dumper::Compact

Music::Chord::Note

Music::Chord::Progression

Music::Chord::Progression::Transform

MIDI::Drummer::Tiny

Music::CreatingRhythms

MIDI::RtMidi::FFI::Device

MIDI::RtMidi::ScorePlayer

My personal music is available to stream on all platforms.

Introducing DateTime::Format::RelativeTime

perl.com

Published on Tuesday 14 January 2025 14:45

I have the pleasure to announce the release of the new Perl module DateTime::Format::RelativeTime, which is designed to mirror its equivalent Web API Intl.RelativeTimeFormat

It requires only Perl v5.10.1 to run, and uses an exception class to return error or to die (if the option fatal is provided and set to a true value).

You can use it the same way as the Web API:

use DateTime::Format::RelativeTime;
my $fmt = DateTime::Format::RelativeTime->new(
    # You can use en-GB (Unicode / web-style) or en_GB (system-style), it does not matter.
    'en_GB', {
        localeMatcher => 'best fit',
        # see getNumberingSystems() in Locale::Intl for the supported number systems
        numberingSystem => 'latn',
        # Possible values are: long, short or narrow
        style => 'short',
        # Possible values are: always or auto
        numeric => 'always',
    },
) || die( DateTime::Format::RelativeTime->error );

# Format relative time using negative value (-1).
$fmt->format( -1, 'day' ); # "1 day ago"

# Format relative time using positive value (1).
$fmt->format( 1, 'day' ); # "in 1 day"

This will work with 222 possible locales as supported by the Unicode CLDR (Common Locale Data Repository). The CLDR data (currently the Unicode version 46.1) is made accessible via another module I created a few months ago: Locale::Unicode::Data

However, beyond the standard options, and parameters you can pass to the methods format and formatToParts (or format_to_parts if you prefer), you can also provide 1 or 2 DateTime objects, and DateTime::Format::RelativeTime will figure out for you the greatest difference between the 2 objects.

If you provide only 1 DateTime object, DateTime::Format::RelativeTime will instantiate a second one with DateTime->now and using the first DateTime object time_zone value.

For example:

my $dt = DateTime->new(
    year => 2024,
    month => 8,
    day => 15,
);
$fmt->format( $dt );
# Assuming today is 2024-12-31, this would return: "1 qtr. ago"

or, with 2 DateTime objects:

my $dt = DateTime->new(
    year => 2024,
    month => 8,
    day => 15,
);
my $dt2 = DateTime->new(
    year => 2022,
    month => 2,
    day => 22,
);
$fmt->format( $dt => $dt2 ); # "2 yr. ago"

When using the method formatToParts (or format_to_parts) you will receive an array reference of hash references, making it easy to customise and handle as you wish. For example:

use DateTime::Format::RelativeTime;
use Data::Pretty qw( dump );
my $fmt = DateTime::Format::RelativeTime->new( 'en', { numeric => 'auto' });
my $parts = $fmt->formatToParts( 10, 'seconds' );
say dump( $parts );

would yield:

[
    { type => "literal", value => "in " },
    { type => "integer", unit => "second", value => 10 },
    { type => "literal", value => " seconds" },
]

You can use a negative number to indicate the past, and you can also use decimals, such as:

my $parts = $fmt->formatToParts( -12.5, 'hours' );
say dump( $parts );

would yield:

[
    { type => "integer", unit => "hour", value => 12 },
    { type => "decimal", unit => "hour", value => "." },
    { type => "fraction", unit => "hour", value => 5 },
    { type => "literal", value => " hours ago" },
]

The possible units are: year, quarter, month, week, day, hour, minute, and second, and those can be provided in singular or plural form.

Of course, you can choose a different numbering system than the default latn, i.e. numbers from 0 to 9, as long as the numbering system you want to use is of numeric type. There are 77 of those out of 96 in the CLDR data. See the method number_system in Locale::Unicode::Data for more information.

So, for example:

use DateTime::Format::RelativeTime;
use Data::Pretty qw( dump );
my $fmt = DateTime::Format::RelativeTime->new( 'ar', { numeric => 'auto' });
my $parts = $fmt->formatToParts( -3, 'minutes' );
say dump( $parts );

would yield:

[
    { type => "literal", value => "قبل " },
    { type => "integer", value => '٣', unit => "minute" },
    { type => "literal", value => " دقائق" },
]

or, here we are explicitly setting the numbering system to deva, which is not a system default:

use DateTime::Format::RelativeTime;
use Data::Pretty qw( dump );
my $fmt = DateTime::Format::RelativeTime->new( 'hi-IN', { numeric => 'auto', numberingSystem => 'deva' });
my $parts = $fmt->formatToParts( -3.5, 'minutes' );
say dump( $parts );

would yield:

[
    { type => "integer", value => '३', unit => "minute" },
    { type => "decimal", value => ".", unit => "minute" },
    { type => "fraction", value => '५', unit => "minute" },
    { type => "literal", value => " मिनट पहले" },
]

The option numeric can be set to auto or always. If it is on auto, the API will check if it can find a time relative term, such as today or yesterday instead of returning in 0 day or 1 day ago. If it is set to always, then the API will always return a format involving a number like the ones I just mentioned.

Just like its Web API counterpart, you can use the method resolvedOptions after having instantiated an object to check how DateTime::Format::RelativeTime has resolved the options you provided, or possibly come up with default ones:

use DateTime::Format::RelativeTime;
use Data::Pretty qw( dump );
# locale is "Marathi"
my $fmt = DateTime::Format::RelativeTime->new( 'mr', { numeric => 'auto' });
my $options = $fmt->resolvedOptions;
say dump( $options );

would yield:

{
    locale => "mr",
    numberingSystem => "deva"
    numeric => "auto",
    style => "long",
}

deva is the numbering system in the CLDR for “Devanagari Digits” used by the following 12 locales: bgc (Haryanvi), bho (Bhojpuri), brx (Bodo), doi (Dogri), hi (Hindi), kok (Konkani), mai (Maithili), mr (Marathi), ne (Nepali), raj (Rajasthani), sa (Sanskrit) and xnr (Kangri).

I hope you will enjoy this module, and that it will be useful to you. I have spent quite a bit of time putting it together, and it has been rigorously tested. If you see any bugs, or opportunities for improvement, kindly submit an issue on Gitlab

PERL Scripting Training Course Online

Perl on Medium

Published by Multisoft Systems on Monday 13 January 2025 07:12

Master the art of automation with PERL Scripting Training Online Course by Multisoft Systems.

Perl 🐪 Weekly #703 - Teach me some Perl!

dev.to #perl

Published by Gabor Szabo on Monday 13 January 2025 06:33

Originally published at Perl Weekly 703

Hi there!

After the Advent calendars and the vacation days it seems people are still tired and there is not much content to share. So let me repeat and rephrase my call for speaker for the online live events.

At these online meetings I'd like to see guests who would teach me, and the audience, interesting stuff. Eg. 'How to write Object oriented code in Perl?', 'How to write a web application using Mojolicious?', 'How to process huge amounts of data with Perl?', just to give you a few ideas.

There could be presentations on how a particular module works, and how to contribute to that module.

These could be also about Python, Rust, or some other interesting language, but I guess the readers of this newsletter will more likely know and want to share Perl.

These could be well-prepared presentations, or they can be more ad-hoc, pair-programming sessions. Just as you'd explain things to a new co-worker.

After each presentation we stay around and have a discussion. It is way better than just watching the video, but of course you have to join us at the live event to enjoy that. I hope to see you at one of the events either as listener or as guest speaker!

Anyway, if you are interested, check out the planned live events and send me an email with a topic you'd like to talk about.

Enjoy your week!

--
Your editor: Gabor Szabo.

Articles

Adding structured data with Perl

Structured data on your web pages are said to help the search engines (aka. Google) to index your site, rank it higher and then display informative snippets to the people searching.

Discussion

Alternating glob failure

Rose::DB ORM and Perl

Perl

This week in PSC (175) | 2025-01-09

... and by brian d foy.

The Weekly Challenge

The Weekly Challenge by Mohammad Sajid Anwar will help you step out of your comfort-zone. You can even win prize money of $50 by participating in the weekly challenge. We pick one champion at the end of the month from among all of the contributors during the month, thanks to the sponsor Lance Wicks.

The Weekly Challenge - 304

Welcome to a new week with a couple of fun tasks "Arrange Binary" and "Maximum Average". If you are new to the weekly challenge then why not join us and have fun every week. For more information, please read the FAQ.

RECAP - The Weekly Challenge - 303

Enjoy a quick recap of last week's contributions by Team PWC dealing with the "3-digits Even" and "Delete and Earn" tasks in Perl and Raku. You will find plenty of solutions to keep you busy.

TWC303

Combination of sort, uniq, map, join and grep. This is not for weak hearts. Great work.

Delete and Even

Find the difference between combinations and permutations. Highly recommended.

See Other

Nice catch of edge case and solution for the same. Keep it up great work.

Earn Evenly

Nice introduction to List::Gather, thanks. Cool use case, must checkout.

Perl Weekly Challenge 303

Nice promotion of CPAN modules and end up with a compact solutions. Well done.

Even and earn

Breakdown of a task into smaller subtask is very handy and easy to follow. Nice to see the use of new Perl camel.

The Weekly Challenge #303

Recursive call in play this week. Compact and powerful solutions, keep sharing knowledge with us.

Can Even Digits Earn?

Use of Bitmask is a clever move, brilliant. Great work, keep it up.

Earn with 3 digits

This is for Python fans. Anybody can follow the code, it is so simple. Thanks for sharing.

Weekly collections

NICEPERL's lists

Great CPAN modules released last week.

Events

Boston.pm monthly meeting

Virtual event

GitLab pipelines and CI for Perl developers

January 20, 2025, Virtual event in Zoom

Boston.pm monthly meeting

Virtual event

The Perl and Raku Conference 2025

Greenville, South Carolina, USA

You joined the Perl Weekly to get weekly e-mails about the Perl programming language and related topics.

Want to see more? See the archives of all the issues.

Not yet subscribed to the newsletter? Join us free of charge!

(C) Copyright Gabor Szabo
The articles are copyright the respective authors.

Adding structured data with Perl

Perl Hacks

Published by Dave Cross on Sunday 12 January 2025 16:25

If you have a website, then it’s very likely that you would like as many people as possible to see it. One of the best tools for achieving that is to ensure that your site is returned close to the top of as many search results pages as possible.

In order to do that, you really have two targets:

  1. Ensure the search engines know what your website is about
  2. Ensure the search engines think your website is an important source of information on the topics it covers

The second item on the list is mostly about getting other websites on the same topic to link to you – and it is outside the scope of this post. In this post, I want to talk about a good way to ensure search engines know what your site is about.

Of course, the search engines have invested a lot of money in working that out for themselves. They scan the text on your site and processes it to extract the meaning. But there are various ways you can make it easier for them. And they like sites that make their lives easier.

One of the most powerful ways to achieve this is to add structured data to your site. That means adding extra mark-up to your web pages which explains what the page is about. On the Schema.org website, you can find dozens of “things” the you can describe in structured data – for example, here is the definition of the Person entity. Each entity has a number of (largely optional) properties which can be included in structured data about an object of that type. Each property can be a string or another structured data entity. Additionally, entities are arranged in a hierarchy, so one entity can be based on another, more generic, entity. A Person, for example, inherits all of the properties of a Thing (which is the most generic type of entity). This is a lot like inheritance in Object-Oriented Programming.

Perhaps most usefully, the definition of each entity type ends with some examples of how structured data about an entity of that type could be added to an HTML document. The examples cover three formats:

  1. Microdata. This involved adding a lot of new attributes to various elements in the HTML (you might also add more <span> and <div> elements in order to have a place to put these attributes. These attributes have names like “itemscope”, “itemtype” and “itemprop”.
  2. RDFa. This looks a lot like microdata, but the attributes have different names – “vocab”, “typeof” and “property”.
  3. JSON-LD. This is different from the other two formats. It is not added to the existing mark-up, but it is a separate element which contains JSON defining the entities on the page.

Because it is completely separate to the existing mark-up, I find JSON-LD to be easier to work with. And for that reason, I wrote MooX::Role::JSON_LD which makes it easy to generate JSON-LD for classes that are based on Moo or Moose. Let’s look at a simple example of using it to add Person JSON-LD to a web page of a person. We’ll assume we already have a Person class that we use to provide the data on a web page about a person. It has attributes first_name, last_name and birth_date.

We start with some configuration. We load the role and define two subroutines which tell us which entity type we’re working with and which attributes we want to include in the JSON-LD. The code might look like this:

with 'MooX::Role::JSON_LD';

sub json_ld_type { 'Person' };

sub json_ld_fields { [ qw[ first_name last_name birth_date ] ] };

We can now use our Person class like this:

use Person;

my $bowie = Person->new({
  first_name => 'David',
  last_name  => 'Bowie',
  birth_date => '1947-01-08',
});

say $bowie->json_ld;

This produces the following output:

{
   "@context" : "http://schema.org/",
   "@type" : "Person",
   "first_name" : "David",
   "last_name" : "Bowie",
   "birth_date" : "1947-01-08"
}

This looks pretty good. But, sadly, it’s not valid JSON-LD. In the Schema.org Person entity, the relevant properties are called “givenName”, “familyName” and “birthDate”. Obviously, if we were designing our class from scratch, we could create attributes with those names. But often we’re adding features to existing systems and we don’t have that luxury. So the role allows us to change the names of attributes before they appear in the JSON-LD. We need to look more closely at the json_ld_fields() subroutine. It defines the names of the attributes that will appear in the JSON-LD. It returns an array reference and each element of the array contains a string which is the name of an attribute. But one of these elements can also contain a hash reference. In that case, the key of the hash is the name of the property we want to appear in the JSON-LD and the value is the name of the matching attribute in our class. So we can redefine our subroutine to look like this:

sub json_ld_fields {
    [
      { givenName  => 'first_name' },
      { familyName => 'last_name' },
      { birthDate  => 'birth_date' },
    ]
}

And now we get the following JSON-LD:

{
  "@context" : "http://schema.org/",
  "@type" : "Person",
  "givenName" : "David",
  "familyName" : "Bowie",
  "birthDate" : "1947-01-08"
}

Which is now valid.

There’s one other trick we can use. We’ve seen the Schema.org Person entity has a “firstName” and “lastName” properties which map directly onto our “first_name” and “last_name” attributes. But the Person entity inherits from the Thing entity and that has a property called “name” which might be more useful for us. So perhaps we want to combine the “first_name” and “last_name” attributes into the single JSON-LD property. We can do that by changing our json_ld_fields() subroutine again:

sub json_ld_fields {
    [
      { birthDate => 'birth_date'},
      { name => sub { $_[0]->first_name . ' ' . $_[0]->last_name} },
    ]
  }

In this version, we’ve added the “name” as the key of a hashref and the value is an anonymous subroutine that is passed the object and returns the name by concatenating the first and last names separated by a space. We now get this JSON-LD:

{
  "@context" : "http://schema.org/",
  "@type" : "Person",
  "birthDate" : "1947-01-08"
  "name" : "David Bowie",
}

Using this approach, allows us to build arbitrary JSON-LD properties from a combination of attributes from our object’s attributes.

Let’s look at a real-world example (and the reason why I was reminded of this module’s existence earlier this week.

I have a website called ReadABooker. It’s about the books that compete for the Booker Prize. Each year, a shortlist of six novels is announced and, later in the year, a winner is chosen. The winning author gets £50,000 and all of the shortlisted novels get massively increased sales. It’s a big deal in British literary circles. I created the website a few years ago. It lists all of the events (the competition goes back to 1969) and for each year, it lists all of the shortlisted novels. You can also see all of the authors who have been shortlisted and which of their shortlisted novels have won the prize. Each novel has a “Buy on Amazon” button and that link includes my associate ID – so, yes, it’s basically an attempt to make money out of people who want to buy Booker shortlisted novels.

But it’s not working. It’s not working because not enough people know about the site. So last week I decided to do a bit of SEO work on the site. And the obvious improvement was to add JSON-LD for the book and author pages.

The site itself is fully static. It gets updated twice a year – once when the shortlist is announced and then again when the winner is announced (the second update is literally setting a flag on a database row). The data about the novels is stored in an SQLite database. And there are DBIx::Class classes that allow me to access that data. So the obvious place to add the JSON-LD code is in Booker::Schema::Result::Book and Booker::Schema::Result::Person (a person can exist in the database if they have been an author, a judge or both).

The changes for the Person class were trivial. I don’t actually hold much information about the people in the database.

with 'MooX::Role::JSON_LD';

sub json_ld_type { 'Person' }

sub json_ld_fields {
  [
    qw/name/,
  ];
}

The changes in the Book class have one interesting piece of code:

with 'MooX::Role::JSON_LD';

sub json_ld_type { 'Book' }

sub json_ld_fields {
  [
    { name => 'title' },
    { author => sub {
      $_[0]->author->json_ld_data }
    },
    { isbn => 'asin' },
  ];
}

The link between a book and its author is obviously important. But in the database, that link is simply represented by a foreign key in the book table. Having something like “author : 23” in the JSON-LD would be really unhelpful, so we take advantage of the link between the book and the author that DBIx::Class has given us and call the json_ld_data() method on the book’s author object. This method (which is added to any class that uses the role) returns the raw data structure which is later passed to a JSON encoder to produce the JSON-LD. So by calling that method inside the anonymous subroutine that creates the “author” attribute we can reuse that data in our book data.

The Person class creates JSON-LD like this:

{
   "@context" : "http://schema.org/",
   "@type" : "Person",
   "name" : "Theresa Mary Anne Smith"
}

And the Book class creates JSON-LD like this:

{
   "@context" : "http://schema.org/",
   "@type" : "Book",
   "author" : {
      "@context" : "http://schema.org/",
      "@type" : "Person",
      "name" : "Theresa Mary Anne Smith"
   },
   "isbn" : "B086PB2X8F",
   "name" : "Office Novice"
}

There were two more changes needed. We needed to get the JSON-LD actually onto the HTML pages. The site is created using the Template Toolkit and the specific templates are author.html.tt and title.html.tt. Adding the JSON-LD to these pages was as simple as adding one line to each template:

[% author.json_ld_wrapped -%]

And

[% book.json_ld_wrapped -%]

We haven’t mentioned the json_ld_wrapped() method yet. Let me explain the hierarchy of the three main methods that the role adds to a class.

  • json_ld_data() returns the raw Perl data structure that contains the data that will be displayed in the JSON-LD
  • json_ld() takes the value returned from json_ld_data() and encodes it into a JSON document
  • json_ld_wrapped() takes the JSON returned from json_ld() and wraps it in the <script type="application/ld+json">..</script> tag that is used to embed JSON-LD in HTML. This is the method that you usually want to call from whatever is generating your HTML

And that’s how I added JSON-LD to my website pretty easily. I now need to wait and see just how effective these changes will be. Hopefully thousands of people will be buying books through my site in the coming weeks and I can sit back and stop having to write code for a living.

It’s the dream!

How about you? Which of your websites would benefit from the addition of a few carefully-crafted pieces of JSON-LD?

The post Adding structured data with Perl appeared first on Perl Hacks.

(dxxx) 20 great CPAN modules released last week

Niceperl

Published by Unknown on Saturday 11 January 2025 21:48

Updates for great CPAN modules released last week. A module is considered great if its favorites count is greater or equal than 12.

  1. App::DBBrowser - Browse SQLite/MySQL/PostgreSQL databases and their tables interactively.
    • Version: 2.421 on 2025-01-09, with 14 votes
    • Previous CPAN version: 2.420 was 13 days before
    • Author: KUERBIS
  2. App::Sqitch - Sensible database change management
    • Version: v1.5.0 on 2025-01-08, with 43 votes
    • Previous CPAN version: v1.4.1 was 11 months, 4 days before
    • Author: DWHEELER
  3. CGI - Handle Common Gateway Interface requests and responses
    • Version: 4.67 on 2025-01-08, with 44 votes
    • Previous CPAN version: 4.66 was 6 months, 19 days before
    • Author: LEEJO
  4. Config::General - Generic Config Module
    • Version: 2.67 on 2025-01-08, with 31 votes
    • Previous CPAN version: 2.65 was 2 years, 8 months, 28 days before
    • Author: TLINDEN
  5. CPAN::Audit - Audit CPAN distributions for known vulnerabilities
    • Version: 20250109.001 on 2025-01-10, with 14 votes
    • Previous CPAN version: 20250103.001 was 6 days before
    • Author: BRIANDFOY
  6. Crypt::Passphrase - A module for managing passwords in a cryptographically agile manner
    • Version: 0.020 on 2025-01-10, with 17 votes
    • Previous CPAN version: 0.019 was 11 months, 13 days before
    • Author: LEONT
  7. DateTime::Format::Natural - Parse informal natural language date/time strings
    • Version: 1.19 on 2025-01-05, with 18 votes
    • Previous CPAN version: 1.18 was 1 year, 3 months before
    • Author: SCHUBIGER
  8. DBD::mysql - A MySQL driver for the Perl5 Database Interface (DBI)
    • Version: 5.011 on 2025-01-06, with 58 votes
    • Previous CPAN version: 5.010 was 1 month, 25 days before
    • Author: DVEEDEN
  9. DBI - Database independent interface for Perl
    • Version: 1.646 on 2025-01-11, with 273 votes
    • Previous CPAN version: 1.645 was 4 months, 8 days before
    • Author: HMBRAND
  10. experimental - Experimental features made easy
    • Version: 0.034 on 2025-01-09, with 31 votes
    • Previous CPAN version: 0.033 was 17 days before
    • Author: LEONT
  11. Module::Pluggable - automatically give your module the ability to have plugins
    • Version: 6.3 on 2025-01-10, with 25 votes
    • Previous CPAN version: 6.2 was 2 months, 16 days before
    • Author: SIMONW
  12. Object::Pad - a simple syntax for lexical field-based objects
    • Version: 0.819 on 2025-01-10, with 45 votes
    • Previous CPAN version: 0.818 was 18 days before
    • Author: PEVANS
  13. Perl::Tidy - indent and reformat perl scripts
    • Version: 20250105 on 2025-01-05, with 142 votes
    • Previous CPAN version: 20240903 was 4 months, 2 days before
    • Author: SHANCOCK
  14. Rose::DB::Object - Extensible, high performance object-relational mapper (ORM).
    • Version: 0.822 on 2025-01-06, with 21 votes
    • Previous CPAN version: 0.821 was 2 months, 17 days before
    • Author: JSIRACUSA
  15. SPVM - The SPVM Language
    • Version: 0.990038 on 2025-01-09, with 34 votes
    • Previous CPAN version: 0.990035 was 5 days before
    • Author: KIMOTO
  16. Test::Warnings - Test for warnings and the lack of them
    • Version: 0.037 on 2025-01-05, with 18 votes
    • Previous CPAN version: 0.036 was 2 days before
    • Author: ETHER
  17. Text::CSV - comma-separated values manipulator (using XS or PurePerl)
    • Version: 2.05 on 2025-01-11, with 81 votes
    • Previous CPAN version: 2.04 was 1 year, 1 month, 9 days before
    • Author: ISHIGAKI
  18. Text::CSV_XS - Comma-Separated Values manipulation routines
    • Version: 1.59 on 2025-01-05, with 102 votes
    • Previous CPAN version: 1.58 was 6 days before
    • Author: HMBRAND
  19. Text::MultiMarkdown - Convert MultiMarkdown syntax to (X)HTML
    • Version: 1.004 on 2025-01-06, with 13 votes
    • Previous CPAN version: 1.003 was 2 months, 13 days before
    • Author: BRIANDFOY
  20. Time::Piece - Object Oriented time objects
    • Version: 1.35 on 2025-01-06, with 60 votes
    • Previous CPAN version: 1.3401 was 4 years, 9 months before
    • Author: PEVANS

This week in PSC (175) | 2025-01-09

blogs.perl.org

Published by Perl Steering Council on Saturday 11 January 2025 07:35

Three of us again. Aristotle had limited time, Philippe and Graham stayed longer.

  • Steve Hay released the RCs for for 5.38.3 and 5.40.1. Thank you!
  • Philippe rebased his Perl 42 branch on top of blead after the release of v5.41.7. Things are on track to build a 41.8 testing tarball alongside the 5.41.8 release and we will keep this dual track going for now. We agreed that if we decide to go through with the 42 plan, we must have at least three 41.x-only releases, to keep with the feature freeze policy.
  • We also considered the behavior of use VERSION when given a non-existent version from the gap between the last v5.41.x and 42. We think it should be an error, to continue helping with typos (in line with the current helpful error message when requesting e.g. 5.10 instead of 5.010).
  • We talked about forbidding non-overloaded references stringification. Everyone seems in agreement that the feature is good to have, but the way to enable it is less clear for now: it could be a stricture, warning, feature flag, or pragma.
  • We briefly touched on feedback on our preliminary plan for TLS in core, suggesting that an even simpler approach may be possible. We will pick this back up in a future call.

[P5P posting of this summary]

List of new CPAN distributions in 2024

Perlancar

Published by perlancar on Monday 06 January 2025 01:30

dist author abstract date
AI-Chat BOD Interact with AI Chat APIs 2024-03-02T22:12:10
AI-Image BOD Generate images using OpenAI's DALL-E 2024-03-06T23:01:10
AI-Ollama-Client CORION Client for AI::Ollama 2024-04-05T09:15:33
Ac_me-Local CONTRA The great new Ac_me::Local! 2024-12-06T13:35:37
Acme-App-Broken CONTRA The great new Acme::App::Broken! 2024-09-05T12:41:54
Acme-Both-MakefilePL-And-BuildPL CONTRA The great new Acme::Both::MakefilePL::And::BuildPL! 2024-09-23T17:37:52
Acme-CPANModules-ArrayData PERLANCAR List of modules related to ArrayData 2024-02-05T00:05:46
Acme-CPANModules-BPOM-FoodRegistration PERLANCAR List of modules and utilities related to Food Registration at BPOM 2024-04-27T00:06:16
Acme-CPANModules-FormattingDate PERLANCAR List of various methods to format dates 2024-02-18T14:01:27
Acme-CPANModules-GroupingElementsOfArray PERLANCAR List of modules to group elements of array into several buckets 2024-01-14T00:11:01
Acme-CPANModules-HashData PERLANCAR List of modules related to HashData 2024-02-06T00:05:32
Acme-CPANModules-Import-CPANRatings-User-davidgaramond PERLANCAR List of modules mentioned by CPANRatings user davidgaramond 2024-02-28T00:05:24
Acme-CPANModules-InfoFromCPANTesters PERLANCAR List of distributions that gather information from CPANTesters 2024-02-18T14:03:11
Acme-CPANModules-InterestingTies PERLANCAR List of interesting uses of the tie() interface 2024-02-29T00:05:11
Acme-CPANModules-JSONVariants PERLANCAR List of JSON variants/extensions 2024-04-29T00:05:46
Acme-CPANModules-LoadingModules PERLANCAR List of modules to load other Perl modules 2024-03-01T00:06:07
Acme-CPANModules-LoremIpsum PERLANCAR List of modules related to "Lorem Ipsum", or lipsum, placeholder Latin text 2024-03-02T00:05:10
Acme-CPANModules-MatchingString PERLANCAR List of modules related to matching string 2024-01-10T01:49:01
Acme-CPANModules-ModifiedHashes PERLANCAR List of modules that provide hashes with modified behaviors 2024-07-13T02:14:33
Acme-CPANModules-MultipleDispatch PERLANCAR List of modules to do smart matching 2024-08-18T00:05:41
Acme-CPANModules-OpeningFileInApp PERLANCAR List of modules to open a file with appropriate application 2024-03-04T00:05:56
Acme-CPANModules-QuickGraph PERLANCAR List of modules/tools to quickly create graph/chart 2024-01-21T00:05:07
Acme-CPANModules-RandomText PERLANCAR List of modules for generating random (placeholder) text 2024-03-05T00:05:27
Acme-CPANModules-RemovingElementsFromArray PERLANCAR List of modules to help remove elements from array 2024-01-07T00:05:24
Acme-CPANModules-Soundex PERLANCAR List of modules that implement the soundex algorithm 2024-11-24T00:05:57
Acme-CPANModules-UnixCommandImplementations PERLANCAR List of various CLIs that try to reimplement traditional Unix commands 2024-09-08T00:05:29
Acme-CPANModules-UnixCommandVariants PERLANCAR List of various CLIs that are some variants of traditional Unix commands 2024-08-26T09:48:48
Acme-CPANModules-UnixCommandWrappers PERLANCAR List of various CLIs that wrap existing Unix commands 2024-09-01T00:05:58
Acme-CaSe CONTRA The great new Acme::CaSe! 2024-11-19T08:13:26
Acme-Case CONTRA The great new Acme::Case! 2024-11-19T08:13:37
Acme-Free-API-ChuckNorris OODLER Perl API client for the Chuck Norris Quote API service, https://api.chucknorris.io. 2024-08-29T18:39:41
Acme-Free-API-Geodata-GeoIP CAVAC Lookup GeoIP data for an IP address 2024-09-01T10:12:01
Acme-Free-API-Stonks OODLER Perl API client for the, top 50 stocks discussed on le'Reddit subeddit – r/Wallstreetbets, https://tradestie.com/apps/reddit/api/. 2024-08-30T16:21:46
Acme-Free-API-Ye OODLER Perl API client for the Kanye Rest Quote API service, https://kanye.rest/. 2024-08-28T16:39:49
Acme-Free-Advice SANKO Wise words. Dumb code. 2024-09-03T17:56:37
Acme-Free-Advice-Slip SANKO Seek Advice from the Advice Slip API 2024-09-03T16:56:16
Acme-Free-Advice-Unsolicited SANKO Solicit Unsolicited Advice from the Unsolicited Advice API 2024-09-03T16:59:12
Acme-Free-Dog-API OODLER Perl API client for the Dog API service, https://dog.ceo/dog-api. 2024-09-04T05:43:45
Acme-Free-Public-APIs OODLER Perl API client for … 2024-09-07T01:03:15
Acme-Ghost ABALAMA An yet another view to daemon processes 2024-01-06T19:41:31
Acme-Insult SANKO Code That Wasn't Raised Right 2024-09-03T16:02:55
Acme-Insult-Evil SANKO Programmatically Generate Evil Insults 2024-09-03T15:20:59
Acme-Insult-Glax SANKO Programmatically Generate Insults 2024-09-03T15:19:30
Acme-Insult-Pirate SANKO Programmatically Generate Pirate Themed Insults 2024-09-03T15:24:06
Acme-TaintTest SIDNEY module for checking taint peculiarities on some CPAN testers 2024-03-25T09:22:24
Acme-Version-Same CONTRA Module for testing CPAN Pause indexing 2024-12-19T08:38:15
Acme STIGTSP foo() returns "Foo" 2024-12-05T16:35:21
Acrux ABALAMA Southern crucis constellation for your applications 2024-01-28T14:27:27
Acrux-DBI ABALAMA Database independent interface for Acrux applications 2024-02-05T18:44:46
Akamai-PropertyFetcher SHINGO Akamaiプロパティã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ–ãƒãƒ¼ã‚¸ãƒ§ãƒ³æƒ…報をå–å¾—ã™ã‚‹ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ« 2024-11-04T08:09:49
Algorithm-Gutter JMATES cellular automata to simulate rain in a gutter 2024-11-25T15:59:02
Alien-Cowl ZMUGHAL Find or build Cowl 2024-02-15T03:24:53
Alien-DuckDB PERIGRIN Find or build DuckDB 2024-11-26T03:41:37
Alien-NLOpt DJERIUS Build and Install the NLOpt library 2024-04-28T00:59:11
Alien-NLopt DJERIUS Build and Install the NLopt library 2024-05-01T05:00:12
Alien-Pipx CHRISARG Provides the pipx Python Package Manager 2024-03-09T13:19:11
Alien-Qhull DJERIUS Build and Install the Qhull library 2024-02-09T17:38:52
Alien-RtAudio JBARRETT Install RtAudio 2024-06-23T15:44:22
Alien-SeqAlignment-MMseqs2 CHRISARG find, build and install the mmseqs2 tools 2024-03-24T03:33:13
Alien-SeqAlignment-bowtie2 CHRISARG find, build and install the bowtie2 tools 2024-03-19T12:31:34
Alien-SeqAlignment-cutadapt CHRISARG Provide the cutadapt utility for eliminating polyA tails through pipx 2024-03-09T04:49:02
Alien-SeqAlignment-hmmer3 CHRISARG find, build and install the hmmer3 tools 2024-03-22T03:29:12
Alien-SeqAlignment-last CHRISARG find, build and install the last tools 2024-03-16T21:16:36
Alien-SeqAlignment-minimap2 CHRISARG A Perl wrapper for the minimap2 binary executables 2024-03-23T00:58:56
Alien-SunVox JBARRETT Install The SunVox Library – Alexander Zolotov's SunVox modular synthesizer and sequencer 2024-06-20T09:22:51
Alien-cargo PLICEASE Find or download the cargo command (build system and package manager for Rust) 2024-11-24T00:06:19
Alien-cargo-capi PLICEASE Find or build the cargo capi command 2024-11-24T23:56:49
Alien-cargo-clone PLICEASE Find or build the cargo clone command 2024-11-24T02:33:51
Alien-cue PLICEASE Find or download the cue configuration language tool 2024-05-07T11:34:32
Alien-fpm NHUBBARD Alien package for the fpm package builder 2024-10-20T14:38:39
Alien-libextism EXTISM find or build and install libextism with development dependencies 2024-06-06T03:28:08
Alien-libsecp256k1 BRTASTIC Interface to libsecp256k1 2024-09-12T15:25:26
Alien-libversion GDT Alien wrapper for libversion 2024-05-01T20:53:07
Alien-onnxruntime EGOR Discover or download and install onnxruntime (ONNX Runtime is a cross-platform inference and training machine-learning accelerator.) 2024-04-17T22:03:45
Alien-pipx CHRISARG Provides the pipx Python Package Manager 2024-03-08T20:39:35
Alien-poetry OLIVER Download and install poetry 2024-05-11T11:33:08
Alien-raylib5 PERIGRIN Alien distribution for raylib video game engine, version 5 and above 2024-11-23T06:04:11
Alt-Crypt-OpenSSL-PKCS12-Broadbean DAKKAR Perl extension to OpenSSL's PKCS12 API. 2024-09-30T09:02:44
Alt-Digest-MD5-OpenSSL SKIM Perl interface to the MD5 Algorithm 2024-01-25T10:58:17
Amazon-SQS-Client BIGFOOT Perl classes for interacting with Amazon SQS 2024-11-27T23:07:47
Amazon-Sites DAVECROSS A class to represent Amazon sites 2024-03-20T16:18:39
Amon2-Plugin-Web-Flash YOSHIMASA Ruby on Rails flash for Amon2 2024-05-26T03:25:23
AnyEvent-I3X-Workspace-OnDemand WATERKIP An I3 workspace loader 2024-04-12T18:33:21
AnyEvent-Sway JOHNMERTZ communicate with the Sway window manager 2024-02-09T00:42:07
Aozora2Epub YOSHIMASA Convert Aozora Bunko XHTML to EPUB 2024-06-14T10:10:23
Apache-Session-MariaDB BPS An implementation of Apache::Session using MariaDB 2024-01-19T14:46:59
App-ArticleWrap SCHROEDER word wrap news articles or mail files 2024-06-28T11:16:03
App-BPOMUtils-NutritionLabelRef PERLANCAR Get one or more values from BPOM nutrition label reference (ALG, acuan label gizi) 2024-06-05T00:06:03
App-BPOMUtils-RPO-Ingredients PERLANCAR Group ingredients suitable for food label 2024-03-10T00:05:30
App-BookmarkFeed SCHROEDER Create a RSS feed from Markdown files 2024-08-05T16:33:07
App-CSVUtils-csv_mix_formulas PERLANCAR Mix several formulas/recipes (lists of ingredients and their weights/volumes) into one, and output the combined formula 2024-03-03T00:06:02
App-Changelog OLOOEEZ Simple command-line CHANGELOG.md generator written in Perl 2024-12-01T14:35:19
App-Codit HANJE IDE for and in Perl 2024-05-20T08:51:39
App-CommonPrefixUtils PERLANCAR Utilities related to common prefix 2024-06-01T00:05:57
App-CommonSuffixUtils PERLANCAR Utilities related to common suffix 2024-06-02T00:06:21
App-ComparerUtils PERLANCAR CLIs related to Comparer 2024-03-06T00:05:48
App-CryptPasswordUtilUtils PERLANCAR Utilities related to Crypt::Password::Util 2024-01-06T07:55:01
App-DWG-Sort SKIM Tool to sort DWG files by version. 2024-03-06T10:03:07
App-DesktopNotifyUtils PERLANCAR Utilities related to Desktop::Notify 2024-09-16T00:05:20
App-GeometryUtils PERLANCAR Utilities related to geometry 2024-07-07T00:05:12
App-GnuCash-MembershipUtils PDURDEN A group of perl modules and scripts to help in using GnuCash for membership. 2024-02-27T02:41:31
App-Greple-stripe UTASHIRO Greple zebra stripe module 2024-10-07T08:06:15
App-Greple-under UTASHIRO greple under-line module 2024-10-14T09:17:05
App-HeightUtils PERLANCAR Utilities related to body height 2024-09-15T00:06:02
App-ISBN-Check SKIM Tool for ISBN checking. 2024-02-25T18:59:34
App-KemenkesUtils-RDA PERLANCAR Get one or more values from Indonesian Ministry of Health's RDA (AKG, angka kecukupan gizi, from Kemenkes) 2024-06-12T00:06:32
App-LastStats DAVECROSS A module to fetch and display Last.fm statistics 2024-07-28T17:34:18
App-LevenshteinUtils PERLANCAR CLI utilities related to Levenshtein algorithm 2024-01-30T00:06:14
App-LinkSite DAVECROSS 2024-10-29T11:43:59
App-MARC-Record-Stats SKIM Tool to work with MARC::Record::Stats on MARC dataset. 2024-02-21T11:20:06
App-MediaPi MATHIAS Media Player for Raspberry Pi or other devices with very small screen. 2024-09-04T21:26:50
App-MergeCal DAVECROSS 2024-02-02T17:37:26
App-NKC2MARC SKIM Tool to fetch record from National library of the Czech Republic to MARC file. 2024-06-26T07:14:52
App-NutrientUtils PERLANCAR Utilities related to nutrients 2024-05-26T00:06:02
App-PasswordManager OLOOEEZ Simple password manager for adding, listing, editing, deleting, and copying passwords to the clipboard 2024-11-26T12:46:39
App-PerlGzipScript SKAJI Gzip perl scripts to reduce their file size 2024-07-20T12:49:29
App-Prove-Plugin-TestArgs SVW A prove plugin to configure test aliases and arguments 2024-02-07T12:49:02
App-SortExampleUtils PERLANCAR CLIs related to SortExample 2024-03-07T00:05:25
App-SortKeyUtils PERLANCAR CLIs related to SortKey 2024-03-08T00:05:47
App-SortSpecUtils PERLANCAR CLIs related to SortSpec 2024-03-09T00:05:07
App-SorterUtils PERLANCAR CLIs related to Sorter 2024-03-11T00:05:26
App-SpreadsheetOpenUtils PERLANCAR Utilities related to Spreadsheet::Open 2024-03-12T00:05:23
App-Standup-Diary SMONFF Manage a simple Markdown journal for your daily standups 2024-12-01T17:05:39
App-Stouch SAMYOUNG Simple template file creator 2024-11-22T02:59:41
App-Tarotplane SAMYOUNG Curses flashcard program 2024-10-31T18:18:37
App-TextSimilarityUtils PERLANCAR CLI utilities related to text similarity 2024-01-31T00:06:20
App-Tickit-Hello SKIM Tickit application with hello world. 2024-12-18T19:17:34
App-TimeTracker-Gtk3StatusIcon DOMM Show TimeTracker status as a GTK3 StatusIcon in the system tray 2024-09-11T19:36:29
App-Timestamper-Log-Process SHLOMIF various filters and queries for App::Timestamper logs. 2024-06-09T04:42:04
App-TodoList OLOOEEZ Simple command-line to-do list manager written in Perl 2024-11-25T23:32:50
App-YtDlpUtils PERLANCAR Utilities (mostly wrappers) related to yt-dlp 2024-07-10T02:59:34
App-bsky SANKO A Command-line Bluesky Client 2024-01-26T03:46:19
App-cat-v UTASHIRO cat-v command implementation 2024-03-31T10:58:40
App-cdbookmark PERLANCAR Change directory to one from the list 2024-02-03T00:05:45
App-chartimes TULAMILI 2024-03-15T01:18:20
App-colcount TULAMILI 各行について、カラムの数を数えたり、条件を満たすカラムの数を数えたりする。 2024-03-15T10:32:37
App-coldigits TULAMILI TSVファイルの各列が何桁のものが何件あったかを、行列状に示す。 2024-11-18T14:35:34
App-cpx CONTRA Install and execute CPAN package binaries 2024-09-05T17:09:44
App-ctransition TULAMILI 入力の全ての文字に対して、次の文字は何であるかの回数の集計を、行列状に表示する。 2024-03-15T12:58:49
App-datasection PLICEASE Work with __DATA__ section files from the command line 2024-12-22T14:02:22
App-findsort PERLANCAR Unix find wrapper to add sorting 2024-10-27T00:05:59
App-gapstat TULAMILI 改行区切りの数値列に、差分が1を超えるギャップ(間隙)がないかを、チェックする。 2024-11-20T15:35:38
App-genusername PERLANCAR Generate random username 2024-01-26T00:05:37
App-grep-similar-text PERLANCAR Print lines similar to the specified text 2024-02-01T00:06:12
App-grep-sounds-like PERLANCAR Print lines with words that sound like to the specified word 2024-11-20T05:47:15
App-hashdata PERLANCAR Show content of HashData modules (plus a few other things) 2024-01-25T00:06:11
App-htidx GBROWN generate static HTML directory listings. 2024-05-29T11:03:56
App-indent PERLANCAR Indent text 2024-01-25T04:48:04
App-lcpan-CmdBundle-namespace PERLANCAR lcpan subcommands related to namespaces 2024-01-09T04:56:59
App-mqtt2job CHRISC Subscribe to an MQTT topic and trigger job execution 2024-10-24T22:22:49
App-optex-glob UTASHIRO optex filter to glob filenames 2024-09-10T12:36:16
App-optex-mask UTASHIRO optex data masking module 2024-08-16T10:14:16
App-optex-scroll UTASHIRO optex scroll region module 2024-09-11T12:40:16
App-papersway SPWHITTON PaperWM-like window management for Sway/i3wm 2024-04-12T08:18:00
App-pdfresize PERLANCAR Resize each page of PDF file to a new dimension 2024-09-29T00:06:10
App-pdfsize PERLANCAR Show dimensions of PDF files 2024-09-22T00:05:31
App-perlwhich MMCCLENN locate a Perl module 2024-01-09T21:42:01
App-prefixcat PERLANCAR Like Unix `cat` but by default prefix each line with filename 2024-08-09T12:33:04
App-rdapper GBROWN a simple console-based RDAP client. 2024-05-29T23:00:49
App-repeat PERLANCAR Repeat a command a number of times 2024-12-06T06:58:51
App-runscript SVW Module that implements the runscript utility 2024-06-25T08:11:16
App-samelines TULAMILI 2024-03-14T07:49:49
App-sbozyp NHUBBARD a package manager for Slackware's SlackBuilds.org 2024-10-20T20:41:27
App-sort_by_comparer PERLANCAR Sort lines of text by a Comparer module 2024-04-16T00:06:00
App-sort_by_example PERLANCAR Sort lines of text by example 2024-04-20T00:05:10
App-sort_by_sorter PERLANCAR Sort lines of text by a Sorter module 2024-04-17T00:05:42
App-sort_by_sortkey PERLANCAR Sort lines of text by a SortKey module 2024-04-24T00:06:38
App-zen LITCHIE Zen is a markdown based literate programming tool 2024-02-05T05:48:06
Archive-Libarchive-Compress PLICEASE Recursively archive a directory (using libarchive) 2024-11-15T19:49:10
Archive-SCS NAUTOFON SCS archive controller 2024-05-21T18:27:52
Arcus-Client JAMTWOIN Perl client for arcus cache cluster 2024-09-04T02:56:17
Arithmetic-PaperAndPencil JFORGET simulating paper and pencil techniques for basic arithmetic operations 2024-04-22T19:57:44
Ascii-Text LNATION module for generating ASCII text in various fonts and styles 2024-08-29T10:49:18
Ascii-Text-Image LNATION module for generating images using ASCII text. 2024-09-04T15:30:30
Astro-MoonPhase-Simple BLIAKO Calculate the phase of the Moon on a given time without too much blah blah 2024-07-14T14:14:36
Audio-Cuefile-Libcue GREGK Perl interface to the libcue cuesheet reading library 2024-07-19T19:43:23
Audio-SunVox-FFI JBARRETT Bindings for the SunVox library – a modular synthesizer and sequencer 2024-06-22T11:40:41
Authorization-AccessControl TYRRMINAL Hybrid RBAC/ABAC access control 2024-05-16T03:53:26
Autoconf-Template BIGFOOT autoconfiscation help scripts 2024-08-06T09:26:35
Bencher-Scenario-ExceptionHandling PERLANCAR Benchmark various ways to do exception handling in Perl 2024-04-13T00:05:36
Bencher-Scenario-ListFlattenModules PERLANCAR Benchmark various List::Flatten implementaitons 2024-03-13T00:05:28
Bencher-ScenarioBundle-Accessors PERLANCAR Scenarios to benchmark class accessors 2024-05-13T00:05:21
Bencher-ScenarioBundle-Algorithm-Diff PERLANCAR Scenarios to benchmark Algorithm::Diff 2024-05-11T00:06:17
Bencher-ScenarioBundle-Graphics-ColorNames PERLANCAR Scenarios to benchmark Graphics::ColorNames and related modules 2024-05-12T00:05:13
Bencher-ScenarioBundle-Log-Any PERLANCAR Scenarios for benchmarking Log::Any 2024-05-20T00:06:19
Bencher-ScenarioBundle-Log-ger PERLANCAR Scenarios for benchmarking Log::ger 2024-05-21T00:05:46
Bencher-ScenarioBundle-Ref-Util PERLANCAR Benchmark Ref::Util 2024-12-04T03:38:56
Bencher-ScenarioBundle-SmartMatch PERLANCAR Scenarios to benchmark switch & smartmatch in Perl 2024-07-03T09:45:27
Bencher-Scenarios-Log-Any PERLANCAR Scenarios for benchmarking Log::Any 2024-01-28T00:05:19
Bencher-Scenarios-Log-Dispatch PERLANCAR Bencher scenarios related to Log::Dispatch modules 2024-02-04T00:05:28
Bencher-Scenarios-Log-Dispatch-FileRotate PERLANCAR Scenarios to benchmark Log::Dispatch::FileRotate 2024-02-11T00:05:41
Bencher-Scenarios-Text-Table-Sprintf PERLANCAR Scenarios for benchmarking Text::Table::Sprintf 2024-03-14T00:05:21
Bio-EnsEMBL ABECKER Bio::EnsEMBL – Ensembl Core API 2024-09-03T10:23:40
Bio-SeqAlignment CHRISARG Aligning (and pseudo aligning) biological sequences 2024-03-24T01:05:16
Bio-SeqAlignment-Applications-SequencingSimulators-RNASeq-Polyester CHRISARG Skeleton package that does nothing but reserve the namespace. 2024-06-09T13:20:02
Bio-SeqAlignment-Components-Libraries-edlib CHRISARG basic edlib library 2024-06-13T03:23:35
Bio-SeqAlignment-Components-SeqMapping CHRISARG Imports all modules relevant to sequence mapping 2024-06-10T04:15:38
Bio-SeqAlignment-Components-Sundry CHRISARG Miscellaneous components for building awesome sequencing apps. 2024-06-09T16:30:30
Bio-SeqAlignment-Examples-EnhancingEdlib CHRISARG Parallelizing Edlib with MCE, OpenMP using Inline and FFI::Platypus 2024-06-13T01:02:44
Bio-SeqAlignment-Examples-TailingPolyester CHRISARG "Beefing" up the RNA sequencing simulator polyester with polyA tails 2024-06-12T12:26:38
Bitcoin-Secp256k1 BRTASTIC Perl interface to libsecp256k1 2024-09-17T22:11:45
Bluesky SANKO The Bluesky Social Network 2024-12-03T01:56:20
Bot-Telegram VASYAN A micro^W nano framework for creating telegram bots based on WWW::Telegram::BotAPI 2024-06-17T11:13:27
Bundle-WATERKIP WATERKIP A mono repo for perl scripts and modules which WATERKIP likes 2024-02-27T23:00:33
Business-CAMT MARKOV ISO20022 Cash Management (CAMT) messages 2024-11-25T08:57:16
Business-ID-VehiclePlate PERLANCAR Parse Indonesian vehicle plate number 2024-08-07T00:05:46
Business-PAYONE ARTHAS Perl library for PAYONE online payment system 2024-10-17T09:59:35
Business-Tax-US-Form_1040-Worksheets JKEENAN IRS Form 1040 worksheets calculations 2024-03-20T19:16:50
CLI-Meta-less PERLANCAR Metadata for 'cp' Unix commnd 2024-09-27T08:41:45
CPAN-Namespace-Check-Visibility CONTRA Check if a namespace exists on public CPAN 2024-12-18T12:39:35
CPAN-Requirements-Dynamic LEONT Dynamic prerequisites in meta files 2024-04-27T15:17:57
CPANSA-DB BDFOY the CPAN Security Advisory data as a Perl data structure, mostly for CPAN::Audit 2024-11-17T20:32:36
CSAF GDT Common Security Advisory Framework 2024-04-23T21:49:42
CVSS GDT CVSS (Common Vulnerability Scoring System) command line interface 2024-07-30T22:11:37
CXC-DB-DDL DJERIUS DDL for table creation, based on SQL::Translator::Schema 2024-04-04T16:24:13
CXC-DB-DDL-Field-Pg DJERIUS DBD::Pg specific Field class 2024-06-27T14:28:18
CXC-Data-Visitor DJERIUS Invoke a callback on every element at every level of a data structure. 2024-03-23T17:04:24
CXC-PDL-Bin1D DJERIUS one dimensional binning functions 2024-01-20T20:50:24
Cache-Memcached-PDeque HAIJENP Implements a priority deque using memcached as storage 2024-10-25T23:24:58
Cache-MemcachedBinary XMOLEX Perl extension for Memcached server with binary protocol. 2024-01-22T15:13:42
Captcha-Stateless-Text HIGHTOWE stateless, text-based CAPTCHAs 2024-04-17T21:19:21
Carp-Object DAMI a replacement for Carp or Carp::Clan, object-oriented 2024-04-28T17:58:22
Carp-Patch-ExcludePackage PERLANCAR Exclude some packages from stack trace 2024-03-15T00:06:01
Carp-Patch-OutputToBrowser PERLANCAR Output stacktrace to browser as HTML instead of returning it 2024-04-25T00:05:19
Catalyst-Plugin-Flash ARISTOTLE put values on the stash of the next request 2024-04-09T05:06:19
Catalyst-Plugin-Profile-DBI-Log BIGPRESH Capture queries executed during a Catalyst route with DBI::Log 2024-08-29T23:41:08
Catalyst-View-EmbeddedPerl JJNAPIORK Catalyst View wrapper for Template::EmbeddedPerl 2024-09-25T22:17:09
Catalyst-View-EmbeddedPerl-PerRequest JJNAPIORK Catalyst View wrapper for Template::EmbeddedPerl 2024-09-25T23:20:52
Catalyst-View-EmbeddedPerl-PerRequest-ValiantRole JJNAPIORK Role to add Valiant HTML Formbuilder support 2024-10-03T21:32:43
Catmandu-Store-OpenSearch NJFRANCK A searchable store backed by Opensearch 2024-07-03T07:23:38
Chart-ECharts GDT Apache ECharts wrapper for Perl 2024-11-21T22:24:32
CheerLights-API NOTHANS A Perl module for accessing the CheerLights API 2024-11-06T02:28:43
Chess-ELO-FIDE NICEPERL Download and store FIDE ratings 2024-02-24T19:06:41
Circle-Block CHENGYU the block module for Circle::Chain SDK 2024-08-29T06:33:17
Circle-Chain CHENGYU The great new Circle::Chain! 2024-08-29T02:33:58
Circle-Common CHENGYU the common module for Circle::Chain SDK 2024-08-29T06:31:49
Circle-Miner CHENGYU The miner module for circle chain sdk. 2024-12-04T13:38:23
Circle-Node CHENGYU The great new Circle::Node! 2024-09-09T13:37:01
Circle-User CHENGYU the user module for Circle::Chain SDK 2024-08-29T06:36:47
Circle-Wallet CHENGYU the circle chain SDK in PERL 2024-08-29T06:36:58
Common-Log-Parser RRWO Parse the common log format lines used by Apache 2024-02-09T15:12:27
CommonsLang YUPEN Commonly used functions for Perl language 2024-12-25T02:31:45
Comparer PERLANCAR Reusable comparer subroutines 2024-02-08T00:11:13
Comparer-by_similarity PERLANCAR Compare similarity to a reference string 2024-02-23T02:06:32
Comparer-date_in_text PERLANCAR Compare date found in text (or text asciibetically, if no date is found) 2024-04-18T00:05:43
Comparer-file_mtime PERLANCAR Compare file's mtime (modification time) 2024-10-06T00:05:31
Comparer-file_num_links PERLANCAR Compare file's number of (hard) links 2024-11-24T00:06:08
Comparer-file_size PERLANCAR Compare file's size 2024-12-01T00:05:53
Comparer-from_sortkey PERLANCAR Compare keys generated by a SortKey:: module 2024-03-16T00:05:16
Comparer-similarity PERLANCAR Compare similarity to a reference string 2024-02-24T00:06:09
Complete-Nutrient PERLANCAR Completion routines related to nutrients 2024-05-31T00:05:25
Compression-Util TRIZEN Implementation of various techniques used in data compression. 2024-03-21T01:02:57
Config-IniFiles-Check-Health HORSHACK 2024-09-09T13:06:48
Config-Proxy SGRAY Loader class for HTTP proxy configuration parsers. 2024-12-10T12:47:30
Consumer-NonBlock EXODIST Send data between processes without blocking. 2024-07-02T19:53:48
Couch-DB MARKOV thick CouchDB interface 2024-05-29T16:37:08
Crate CARELINE Everything that PDK modules needs 2024-10-05T12:14:57
Crypt-Bear LEONT BearSSL for Perl 2024-11-12T20:07:54
Crypt-Credentials LEONT Manage credential files 2024-01-31T01:30:24
Crypt-PQClean-Sign GUL Post-Quantum Cryptography with keypair 2024-12-23T12:37:49
Crypt-Passphrase-Bcrypt-AES LEONT A peppered AES-encrypted Bcrypt encoder for Crypt::Passphrase 2024-01-28T18:15:23
Crypt-Passphrase-Bcrypt-Compat LEONT A bcrypt encoder for Crypt::Passphrase 2024-04-08T14:24:10
Crypt-URandom-Password STIGTSP Generate passwords from cryptographically secure pseudorandom bytes 2024-12-27T22:59:54
Crypt-URandom-Token STIGTSP Generate secure strings for passwords, secrets and similar 2024-12-28T20:03:58
DBD-Mock-Session-GenerateFixtures UXYZAB When a real DBI database handle ($dbh) is provided, the module generates DBD::Mock::Session data. Otherwise, it returns a DBD::Mock::Session object populated with generated data. This not a part form DBD::Mock::Session distribution just a wrapper around it. 2024-04-29T18:25:02
DBIx-Class-FilterColumn-Encrypt LEONT Transparently encrypt columns in DBIx::Class 2024-02-03T15:22:04
DBIx-Class-Helper-ColumnNames RRWO Retrieve column names from a resultset 2024-09-23T22:20:45
DBIx-Class-ResultSet-PrettyPrint PTC Pretty print DBIx::Class result sets. 2024-10-14T12:10:32
DBIx-HoldMyPlace LANX Automagic SQL Placeholders from interpolated variables 2024-10-24T17:09:34
DBIx-QuickORM EXODIST Actively maintained Object Relational Mapping that makes getting started Quick and has a rich feature set. 2024-10-26T07:48:12
DBIx-Squirrel CPANIC A module for working with databases 2024-08-08T20:01:38
DWIM-Block DCONWAY Use AI::Chat without having to write the infrastructure code 2024-06-26T22:36:44
Daje-Generate JANESKIL lib::Generate 2024-09-22T15:46:05
Daje-Plugin-GeneratePerl JANESKIL It's new $module 2024-12-13T14:31:42
Daje-Plugin-GenerateSQL JANESKIL It's new $module 2024-12-12T07:35:48
Daje-Plugin-GenerateSchema JANESKIL It's new $module 2024-12-12T16:54:45
Daje-Tools-DataSections JANESKIL It's new $module 2024-12-05T16:13:18
Daje-Tools-Datasections JANESKIL Load and store data sections in memory from a named *.pm 2024-12-07T14:41:02
Daje-Tools-Filechanged JANESKIL It's new $module 2024-12-08T10:11:41
Daje-Workflow-Database JANESKIL It's new $module 2024-12-24T15:22:30
Daje-Workflow-Database-Model JANESKIL It's new $module 2024-12-29T07:48:59
Daje-Workflow-Loader JANESKIL It's new $module 2024-12-22T13:51:40
Dancer2-Controllers RAWLEYFOW A tool to allow OO style route declaration in Dancer2 2024-02-14T22:00:57
Dancer2-Plugin-NYTProf GEEKRUTH NYTProf, in your Dancer2 application! 2024-07-02T13:03:01
Dancer2-Session-DBI EPISODEIV DBI based session engine for Dancer 2024-08-29T13:55:42
Data-Annotation POLETTIX [Put something meaningful here!] 2024-11-13T22:16:57
Data-Checks PEVANS XS functions to assist in value constraint checking 2024-06-19T13:26:59
Data-Dump-HTML-Collapsible PERLANCAR Dump Perl data structures as HTML document with collapsible sections 2024-03-08T08:22:33
Data-Dump-HTML-PopUp PERLANCAR Dump Perl data structures as HTML document with nested pop ups 2024-03-18T13:24:01
Data-Dump-IfSmall PERLANCAR Like Data::Dump but reference with dump larger than a certain size will be dumped as something like 'LARGE:ARRAY(0x5636145ea5e8)' 2024-03-18T00:06:06
Data-Dump-SkipObjects PERLANCAR Like Data::Dump but objects of some patterns are dumped tersely 2024-03-19T00:05:05
Data-Dumper-UnDumper BIGPRESH load Data::Dumper output, including self-references 2024-04-25T21:42:30
Data-FastPack-JPacker DRCLAW backend class for packing FastPack data files into web loadable JPack 2024-11-11T00:47:35
Data-FastPack DRCLAW FastPack Record format, parsing and serialising module 2024-11-08T04:39:52
Data-HTML-Element SKIM Data objects for HTML elements. 2024-01-06T17:04:11
Data-HTML-Footer SKIM Data object for HTML footer. 2024-05-31T09:32:54
Data-ISO8583 CADE 2024-06-08T22:52:33
Data-Identifier LION format independent identifier object 2024-09-18T14:36:10
Data-InfoBox SKIM Data objects for info box. 2024-09-15T11:37:07
Data-JPack DRCLAW Offline/Online Web application and data system 2024-11-08T04:40:03
Data-LnArray-XS LNATION Arrays 2024-07-12T09:58:12
Data-Login SKIM Data objects for login. 2024-02-05T22:13:16
Data-Message-Board SKIM Data objects for message board. 2024-05-27T18:30:24
Data-MiniDumpX PERLANCAR A simplistic data structure dumper (demo for Plugin::System) 2024-04-14T00:06:13
Data-Navigation-Item SKIM Data object for navigation item. 2024-03-04T11:53:10
Data-Person SKIM Data objects for person. 2024-05-27T08:46:48
Data-Random-Person SKIM Generate random person. 2024-07-05T00:10:57
Data-Record-Serialize-Encode-html DJERIUS encode a record as html 2024-01-10T17:34:01
Data-Sah-FilterBundle-Array PERLANCAR More array-related Sah filters 2024-01-29T00:06:31
Data-Sah-FilterBundle-Filename-Safe PERLANCAR Sah filters related to removing problematic characters from filename 2024-02-10T00:06:19
Data-Section-Pluggable PLICEASE Read structured data from __DATA__ 2024-12-05T05:27:18
Data-Section-Pluggable-Plugin-Yaml PLICEASE Data::Section::Pluggable Plugin for YAML 2024-12-05T12:02:28
Data-Section-Writer PLICEASE Write __DATA__ section files for Data::Section, Data::Section::Simple or Mojo::Loader::data_section 2024-12-04T00:15:50
Data-Structure-Deserialize-Auto TYRRMINAL Deserializes data structures from perl, JSON, YAML, or TOML data, from strings or files 2024-02-22T18:13:45
Data-TagDB LION Work with Tag databases 2024-09-10T15:25:24
Data-Text-Simple SKIM Data objects for text in language. 2024-02-29T17:29:50
Data-Tranco GBROWN An interface to the Tranco domain list. 2024-06-03T13:35:31
Data-Transfigure TYRRMINAL performs rule-based data transfigurations of arbitrary structures 2024-02-19T20:39:03
Database-Abstraction NHORNE database abstraction layer 2024-01-29T19:03:18
Date-Business BPSCHUCK fast calendar and business date calculations 2024-10-09T01:15:25
Date-Holidays-Adapter-USA GENE Adapter for USA holidays 2024-03-19T20:38:52
Date-Holidays-Adapter-USExtended GENE Adapter for the USExtended module holidays 2024-09-23T22:23:33
Date-Holidays-CW WATERKIP Curacoa's official holidays 2024-02-08T07:49:12
Date-Holidays-USA GENE Provides United States of America holidays 2024-03-19T20:09:45
Date-Holidays-USExtended GENE Provides an extended set of United States holidays 2024-09-23T22:23:44
Date-Parse-Modern BAKERSCOT Provide string to unixtime conversions 2024-01-14T00:42:01
DateTime-Format-Intl JDEGUEST A Web Intl.DateTimeFormat Class Implementation 2024-10-09T02:07:15
DateTime-Format-PDF SKIM PDF DateTime Parser and Formatter. 2024-04-01T09:23:07
DateTime-Format-Unicode JDEGUEST Unicode CLDR Formatter for DateTime 2024-09-10T10:06:43
DateTime-Locale-FromCLDR JDEGUEST DateTime Localised Data from Unicode CLDR 2024-08-01T22:59:44
DateTime-Schedule TYRRMINAL Determine scheduled days in range based on inclusions/exclusions 2024-06-11T20:45:23
Debug-Helper-Flag AAHAZRED Define and import boolean constant DEBUG_FLAG helping to optimize code. 2024-10-10T07:48:38
Devel-Confess-Patch-UseDataDumpHTMLCollapsible PERLANCAR Use Data::Dump::HTML::Collapsible to stringify reference 2024-04-26T00:05:16
Devel-Confess-Patch-UseDataDumpHTMLPopUp PERLANCAR Use Data::Dump::HTML::PopUp to stringify reference 2024-04-28T00:06:05
Devel-Confess-Patch-UseDataDumpIfSmall PERLANCAR Use Data::Dump::IfSmall format refs 2024-03-20T00:05:59
Devel-Confess-Patch-UseDataDumpSkipObjects PERLANCAR Use Data::Dump::SkipObjects to stringify some objects 2024-03-21T00:06:11
Devel-Confess-Source-Patch-ExcludePackage PERLANCAR Exclude some packages from source trace 2024-02-25T00:05:42
Devel-Cover-Report-Codecov-Service-GithubActions TOBYINK gather env vars from Github Actions for Codecov report 2024-09-06T07:41:09
Devel-StatProfiler MBARBON low-overhead sampling code profiler 2024-06-24T21:51:40
Device-Chip-From-Sensirion PEVANS a collection of chip drivers for Sensirion sensors 2024-10-23T11:08:42
Device-Chip-SCD4x PEVANS chip driver for SCD40 and SCD41 2024-01-17T16:23:46
Dist-Build LEONT A modern module builder, author tools not included! 2024-04-26T10:50:10
Dist-Build-XS-Alien LEONT Dist::Build extension to use Alien modules. 2024-08-31T19:19:30
Dist-Build-XS-PkgConfig LEONT Dist::Build extension to use pkg-config. 2024-09-13T20:11:49
Dist-Zilla-App-Command-DiffMint HAARG Compare files to what a minting profile produces 2024-10-15T08:56:46
Dist-Zilla-Plugin-DistBuild LEONT Build a Build.PL that uses Dist::Build 2024-04-26T10:55:35
Dist-Zilla-Plugin-DynamicPrereqs-Meta LEONT Add dynamic prereqs to to the metadata in our Dist::Zilla build 2024-04-27T15:50:03
Dist-Zilla-Plugin-GitHub-Offline LEONT Add a GitHub repo's info to META.{yml,json} 2024-02-06T19:19:02
Dist-Zilla-Plugin-Sah-SchemaBundle PERLANCAR Plugin to use when building Sah-SchemaBundle-* distribution 2024-03-22T00:05:48
Dist-Zilla-Plugin-SimpleBootstrap HAARG Bootstrap a Dist::Zilla library 2024-10-04T23:31:37
Dist-Zilla-Plugin-Sorter PERLANCAR Plugin to use when building Sorter::* distribution 2024-05-07T00:05:19
Dist-Zilla-Plugin-Test-Pod-Coverage-TrustMe HAARG An author test for Pod Coverage 2024-10-09T04:35:48
Dist-Zilla-Role-GetDistFileURL PERLANCAR Get URL to a file inside a Perl distribution 2024-03-23T00:05:56
Dist-Zilla-Stash-OnePasswordLogin RJBS get login credentials from 1Password 2024-05-25T16:30:09
Drought-PET-Thornthwaite AALLGOOD Calculate potential evapotranspiration (PET) using the Thornthwaite method 2024-12-12T21:22:38
Environment-Is PLICEASE Detect environments like Docker or WSL 2024-11-23T20:54:33
Eugener EUGENER A test package. DOnt install. 2024-11-26T14:55:51
Eugener-test EUGENER A test package. DOnt install. 2024-11-20T13:32:00
Eugener_test EUGENER A test package. DOnt install. 2024-11-20T13:34:56
Eugenertest EUGENER A test package. DOnt install. 2024-11-20T14:04:58
Exercises-API NOBUNAGA API Ninja's Exercises API 2024-07-02T19:49:44
ExtUtils-Builder LEONT An overview of the foundations of the ExtUtils::Builder Plan framework 2024-04-25T12:14:45
ExtUtils-Builder-Compiler LEONT Portable compilation 2024-04-25T13:18:11
ExtUtils-Typemaps-Misc LEONT A collection of miscelaneous typemap templates 2024-06-20T19:43:50
ExtUtils-Typemaps-Signal LEONT asdasd 2024-01-29T20:58:52
Extender DOMERO Dynamically enhance Perl objects with additional methods from other modules or custom subroutines 2024-07-17T10:06:50
Extism EXTISM Extism Perl SDK 2024-06-06T04:07:08
FFI-Platypus-Lang-V PLICEASE Documentation and tools for using Platypus with the V programming language 2024-12-19T01:16:18
Feed-Data-AlJazeera LNATION The great new Feed::Data::AlJazeera! 2024-05-09T05:50:01
Feed-Data-BBC LNATION Waiting for comedians to present the news 2024-05-02T08:38:34
Feed-Data-CNN LNATION The rest of the world will follow. 2024-05-02T10:11:29
File-FindUniq PERLANCAR Find unique or duplicate file {contents,names} 2024-12-05T07:59:52
File-Information LION generic module for extrating information from filesystems 2024-10-11T03:10:43
File-ShareDir-Tiny LEONT Locate per-dist and per-module shared files 2024-08-25T13:07:29
File-SharedVar CDRAKE Pure-Perl extension to share variables between Perl processes using files and file locking for their transport 2024-10-17T12:03:33
File-Strfile SAMYOUNG OO strfile interface 2024-10-30T16:27:36
File-Util-Rename PERLANCAR Utilities related to renaming files 2024-02-12T00:06:03
File-ValueFile LION module for reading and writing ValueFile files 2024-10-03T00:30:39
Filter-Syntactic DCONWAY Source filters based on syntax, instead of luck 2024-06-26T22:39:31
Frame CRABAPP Bare-bones, real-time web framework (WIP) 2024-10-05T23:42:01
Fred-Fish-DBUG CLEACH Perl implementation of the Fred Fish C/C++ macros for Perl. 2024-09-25T18:58:19
FreeDesktop-Icons HANJE Use icon libraries quick & easy 2024-05-31T17:26:09
Full TEAM common pragmata for Perl scripts and modules 2024-09-14T01:53:27
Future-IO-Impl-AnyEvent MATHIAS Future::IO implementation using AnyEvent 2024-11-27T21:09:50
GCC-Builtins BLIAKO access GCC compiler builtin functions via XS 2024-03-19T13:31:21
Game-Cribbage LNATION The great new Game::Cribbage! 2024-05-15T00:15:17
Game-EnergyLoop JMATES a simple energy system 2024-11-05T19:13:51
Game-Kezboard JMATES a SDL game where cards are used to move around a board 2024-01-12T00:56:02
Game-Snake LNATION A clone of the classic snake game using raylib 2024-12-29T20:33:35
Games-Sudoku-Html SHE Visualize and play collections of standard 9×9 Sudoku in your browser. 2024-02-24T20:23:44
Games-Sudoku-PatternSolver SHE Solve, generate and play Sudoku 9×9 grids. 2024-01-09T21:26:03
Games-Sudoku-Pdf SHE Produce pdf files from your digital Sudoku sources or collections. 2024-02-24T19:57:08
Genealogy-FindaGrave NHORNE Find URLs on FindaGrave for a person 2024-11-11T13:01:21
Generate JANESKIL lib::GenerateSQL 2024-09-22T09:42:48
Geo-Coder-GeoApify NHORNE Provides a Geo-Coding functionality using https://www.geoapify.com/maps-api/ 2024-10-23T17:12:59
Geo-Leaflet MRDVT Generates Leaflet web page 2024-11-09T02:48:31
Geography-States-Borders GENE Return the borders of states and provinces 2024-01-24T19:03:21
Getopt-Lazier JOJESSF Lazy Getopt-like BS 2024-09-02T15:31:38
Github-ReleaseFetcher TEODESIAN Fetch either the latest or a particular named version of a file in a release from github 2024-08-13T22:09:19
Google-Protobuf-Loader MATHIAS Automatically load .proto file using the standard "use" syntax. 2024-09-22T20:40:43
Graphics-ColorNamesCMYK PERLANCAR Define CMYK values for common color names 2024-05-10T00:05:12
Graphics-ColorNamesCMYK-All PERLANCAR CMYK colors from all Graphics::ColorNamesCMYK::* 2024-06-03T00:06:12
Graphics-ColorNamesCMYK-BannersCom PERLANCAR Basic CMYK colors from banners.com 2024-05-17T00:05:09
Graphics-ColorNamesCMYK-JohnDecemberCom PERLANCAR CMYK color names from johndecember.com 2024-05-19T00:05:21
Graphics-ColorNamesCMYK-Pantone PERLANCAR Pantone colors 2024-05-14T00:05:54
Graphics-ColorNamesCMYK-ToutesLesCouleursCom PERLANCAR CMYK colors from http://toutes-les-couleurs.com/ (red) 2024-05-16T00:06:24
Graphics-ColorNamesLite PERLANCAR Define RGB values for common color names (lite version) 2024-05-09T00:05:39
HATX HOEKIT A fluent interface for Hash and Array Transformations 2024-06-28T13:43:31
Hades-Realm-Rope LNATION Hades realm for Moose 2024-05-20T13:39:42
Hash-Iter PERLANCAR Generate a coderef iterator for a hash 2024-11-04T08:09:16
HashData-Color-CMYK-JohnDecemberCom PERLANCAR CMYK color names (from johndecember.com) 2024-05-18T00:05:57
HashData-Color-CMYK-ToutesLesCouleursCom PERLANCAR CMYK color names (from ToutesLesCouleursCom) 2024-05-15T00:06:01
HashData-Color-PantoneToCMYK PERLANCAR Mapping of Pantone color names to CMYK values 2024-05-08T00:05:41
HashData-ColorCode-CMYK-JohnDecemberCom PERLANCAR CMYK color names (from johndecember.com) 2024-05-22T00:06:06
HashData-ColorCode-CMYK-Pantone PERLANCAR Mapping of Pantone color names to CMYK values 2024-05-23T00:05:32
HashData-ColorCode-CMYK-ToutesLesCouleursCom PERLANCAR CMYK color names (from ToutesLesCouleursCom) 2024-05-24T00:06:00
HashDataBundle-Display-Resolution PERLANCAR HashData::* modules related to Display::Resolution 2024-11-10T00:05:43
IO-Async-Loop-Epoll-FD LEONT Use IO::Async with Epoll and special filehandles 2024-01-27T16:45:26
IO-SocketAlarm NERDVANA Perform asynchronous actions when a socket changes status 2024-08-27T06:08:13
IPC-MicroSocket PEVANS minimal request/response or pub/sub mechanism 2024-08-05T13:49:53
IPCamera-Reolink SFOBERSKI Reolink API provides access to the System, Security, Network, Video input, Enc, Record, PTZ, and Alarm functions of a Reolink IP Camera or NVR via HTTP(S)/REST 2024-01-04T22:06:26
ImgurAPI DILLANBH Imgur API client 2024-03-20T03:11:21
ImgurAPI-Client DILLANBH 2024-03-20T03:31:39
Intellexer-API HAX Perl API client for the Intellexer, a webservice that, "enables developers to embed Intellexer semantics products using XML or JSON." 2024-03-04T02:34:33
JIRA-REST-Lite SHINGO Lightweight wrapper around Jira's REST API 2024-08-16T01:20:46
JSON-LD PLICEASE Load and dump JSON files 2024-12-07T15:40:25
JSON-Ordered-Conditional LNATION A conditional language within an ordered JSON struct 2024-04-06T06:47:37
JSON-ToHTML ARISTOTLE render JSON-based Perl datastructures as HTML tables 2024-04-09T04:28:11
Kanboard-API BARBARITO A Perl interface to the Kanboard API 2024-07-28T23:46:12
Kelp-Module-Beam-Wire BRTASTIC Beam::Wire dependency injection container for Kelp 2024-06-02T14:32:03
Kelp-Module-Storage-Abstract BRTASTIC Abstract file storage for Kelp 2024-10-16T20:04:19
Kelp-Module-YAML BRTASTIC YAML encoder / decoder for Kelp 2024-06-24T19:18:49
KelpX-Controller BRTASTIC Base custom controller for Kelp 2024-07-08T14:43:24
Knowledge RSPIER a great new dist 2024-04-27T11:13:53
LaTeX-Easy-Templates BLIAKO Easily format content into PDF/PS/DVI with LaTeX templates. 2024-03-15T21:43:58
Langertha GETTY The clan of fierce vikings with axe and shield to AId your rAId 2024-08-03T20:56:05
Linux-Landlock MBALLARIN An interface to the Landlock sandboxing facility of Linux 2024-05-09T20:12:52
List-Stream RAWLEYFOW Simple, fast, functional processing of list data 2024-10-07T15:49:41
Local-Acme CONTRA The great new Local::Acme! 2024-11-19T07:43:34
Locale-CLDR-Locales-Aa JGNI Locale::CLDR – Data Package ( Perl localization data for Afar ) 2024-02-25T13:32:59
Locale-CLDR-Locales-Ab JGNI Locale::CLDR – Data Package ( Perl localization data for Abkhazian ) 2024-02-25T13:34:25
Locale-CLDR-Locales-An JGNI Locale::CLDR – Data Package ( Perl localization data for Aragonese ) 2024-02-25T13:39:26
Locale-CLDR-Locales-Ann JGNI Locale::CLDR – Data Package ( Perl localization data for Obolo ) 2024-02-25T13:40:49
Locale-CLDR-Locales-Apc JGNI Locale::CLDR – Data Package ( ) 2024-02-25T13:42:12
Locale-CLDR-Locales-Arn JGNI Locale::CLDR – Data Package ( Perl localization data for Mapuche ) 2024-02-25T13:43:47
Locale-CLDR-Locales-Ba JGNI Locale::CLDR – Data Package ( Perl localization data for Bashkir ) 2024-02-25T13:49:23
Locale-CLDR-Locales-Bal JGNI Locale::CLDR – Data Package ( Perl localization data for Baluchi ) 2024-02-25T13:49:34
Locale-CLDR-Locales-Bew JGNI Locale::CLDR – Data Package ( Perl localization data for Betawi ) 2024-02-25T13:54:02
Locale-CLDR-Locales-Bgc JGNI Locale::CLDR – Data Package ( Perl localization data for Haryanvi ) 2024-02-25T13:56:59
Locale-CLDR-Locales-Bgn JGNI Locale::CLDR – Data Package ( Perl localization data for Western Balochi ) 2024-02-25T13:57:19
Locale-CLDR-Locales-Bho JGNI Locale::CLDR – Data Package ( Perl localization data for Bhojpuri ) 2024-02-25T13:58:45
Locale-CLDR-Locales-Blo JGNI Locale::CLDR – Data Package ( Perl localization data for Anii ) 2024-02-25T14:00:25
Locale-CLDR-Locales-Blt JGNI Locale::CLDR – Data Package ( Perl localization data for Tai Dam ) 2024-02-25T14:00:36
Locale-CLDR-Locales-Bss JGNI Locale::CLDR – Data Package ( Perl localization data for Akoose ) 2024-02-25T14:08:19
Locale-CLDR-Locales-Byn JGNI Locale::CLDR – Data Package ( Perl localization data for Blin ) 2024-02-25T14:08:31
Locale-CLDR-Locales-Cad JGNI Locale::CLDR – Data Package ( Perl localization data for Caddo ) 2024-02-25T14:11:41
Locale-CLDR-Locales-Cch JGNI Locale::CLDR – Data Package ( Perl localization data for Atsam ) 2024-02-25T14:11:52
Locale-CLDR-Locales-Ceb JGNI Locale::CLDR – Data Package ( Perl localization data for Cebuano ) 2024-01-06T19:23:24
Locale-CLDR-Locales-Cho JGNI Locale::CLDR – Data Package ( Perl localization data for Choctaw ) 2024-02-25T14:16:44
Locale-CLDR-Locales-Cic JGNI Locale::CLDR – Data Package ( Perl localization data for Chickasaw ) 2024-02-25T14:19:31
Locale-CLDR-Locales-Co JGNI Locale::CLDR – Data Package ( Perl localization data for Corsican ) 2024-02-25T14:21:02
Locale-CLDR-Locales-Csw JGNI Locale::CLDR – Data Package ( Perl localization data for Swampy Cree ) 2024-02-25T14:22:49
Locale-CLDR-Locales-Cv JGNI Locale::CLDR – Data Package ( Perl localization data for Chuvash ) 2024-02-25T14:25:39
Locale-CLDR-Locales-Doi JGNI Locale::CLDR – Data Package ( Perl localization data for Dogri ) 2024-01-06T19:33:59
Locale-CLDR-Locales-Dv JGNI Locale::CLDR – Data Package ( Perl localization data for Divehi ) 2024-02-25T14:35:09
Locale-CLDR-Locales-Frr JGNI Locale::CLDR – Data Package ( Perl localization data for Northern Frisian ) 2024-02-25T14:51:31
Locale-CLDR-Locales-Gaa JGNI Locale::CLDR – Data Package ( Perl localization data for Ga ) 2024-02-25T14:54:34
Locale-CLDR-Locales-Gez JGNI Locale::CLDR – Data Package ( Perl localization data for Geez ) 2024-02-25T14:57:36
Locale-CLDR-Locales-Gn JGNI Locale::CLDR – Data Package ( Perl localization data for Guarani ) 2024-02-25T14:59:14
Locale-CLDR-Locales-Hnj JGNI Locale::CLDR – Data Package ( Perl localization data for Hmong Njua ) 2024-02-25T15:09:00
Locale-CLDR-Locales-Ie JGNI Locale::CLDR – Data Package ( Perl localization data for Interlingue ) 2024-02-25T15:20:31
Locale-CLDR-Locales-Io JGNI Locale::CLDR – Data Package ( Perl localization data for Ido ) 2024-02-25T15:23:42
Locale-CLDR-Locales-Iu JGNI Locale::CLDR – Data Package ( Perl localization data for Inuktitut ) 2024-02-25T15:26:52
Locale-CLDR-Locales-Jbo JGNI Locale::CLDR – Data Package ( Perl localization data for Lojban ) 2024-02-25T15:28:43
Locale-CLDR-Locales-Kaj JGNI Locale::CLDR – Data Package ( Perl localization data for Jju ) 2024-02-25T15:34:54
Locale-CLDR-Locales-Kcg JGNI Locale::CLDR – Data Package ( Perl localization data for Tyap ) 2024-02-25T15:36:25
Locale-CLDR-Locales-Ken JGNI Locale::CLDR – Data Package ( Perl localization data for Kenyang ) 2024-02-25T15:39:38
Locale-CLDR-Locales-Kgp JGNI Locale::CLDR – Data Package ( Perl localization data for Kaingang ) 2024-01-06T20:28:00
Locale-CLDR-Locales-Kpe JGNI Locale::CLDR – Data Package ( Perl localization data for Kpelle ) 2024-02-25T15:51:57
Locale-CLDR-Locales-Kxv JGNI Locale::CLDR – Data Package ( Perl localization data for Kuvi ) 2024-02-25T15:59:25
Locale-CLDR-Locales-La JGNI Locale::CLDR – Data Package ( Perl localization data for Latin ) 2024-02-25T16:01:00
Locale-CLDR-Locales-Lij JGNI Locale::CLDR – Data Package ( Perl localization data for Ligurian ) 2024-02-25T16:05:34
Locale-CLDR-Locales-Lmo JGNI Locale::CLDR – Data Package ( Perl localization data for Lombard ) 2024-02-25T16:07:06
Locale-CLDR-Locales-Mai JGNI Locale::CLDR – Data Package ( Perl localization data for Maithili ) 2024-01-06T20:57:37
Locale-CLDR-Locales-Mdf JGNI Locale::CLDR – Data Package ( Perl localization data for Moksha ) 2024-02-25T16:18:24
Locale-CLDR-Locales-Mic JGNI Locale::CLDR – Data Package ( Perl localization data for Mi'kmaw ) 2024-02-25T16:25:46
Locale-CLDR-Locales-Mni JGNI Locale::CLDR – Data Package ( Perl localization data for Manipuri ) 2024-01-06T21:09:13
Locale-CLDR-Locales-Moh JGNI Locale::CLDR – Data Package ( Perl localization data for Mohawk ) 2024-02-25T16:30:37
Locale-CLDR-Locales-Mus JGNI Locale::CLDR – Data Package ( Perl localization data for Muscogee ) 2024-02-25T16:35:33
Locale-CLDR-Locales-Myv JGNI Locale::CLDR – Data Package ( Perl localization data for Erzya ) 2024-02-25T16:38:20
Locale-CLDR-Locales-No JGNI Locale::CLDR – Data Package ( Perl localization data for Norwegian ) 2024-01-06T21:31:12
Locale-CLDR-Locales-Nqo JGNI Locale::CLDR – Data Package ( Perl localization data for N’Ko ) 2024-02-25T16:49:31
Locale-CLDR-Locales-Nr JGNI Locale::CLDR – Data Package ( Perl localization data for South Ndebele ) 2024-02-25T16:49:40
Locale-CLDR-Locales-Nso JGNI Locale::CLDR – Data Package ( Perl localization data for Northern Sotho ) 2024-02-25T16:51:06
Locale-CLDR-Locales-Nv JGNI Locale::CLDR – Data Package ( Perl localization data for Navajo ) 2024-02-25T16:52:52
Locale-CLDR-Locales-Ny JGNI Locale::CLDR – Data Package ( Perl localization data for Nyanja ) 2024-02-25T16:54:29
Locale-CLDR-Locales-Oc JGNI Locale::CLDR – Data Package ( Perl localization data for Occitan ) 2024-02-25T16:56:13
Locale-CLDR-Locales-Osa JGNI Locale::CLDR – Data Package ( Perl localization data for Osage ) 2024-02-25T16:59:38
Locale-CLDR-Locales-Pap JGNI Locale::CLDR – Data Package ( Perl localization data for Papiamento ) 2024-02-25T17:02:20
Locale-CLDR-Locales-Pcm JGNI Locale::CLDR – Data Package ( Perl localization data for Nigerian Pidgin ) 2024-01-06T21:37:52
Locale-CLDR-Locales-Pis JGNI Locale::CLDR – Data Package ( Perl localization data for Pijin ) 2024-02-25T17:04:08
Locale-CLDR-Locales-Quc JGNI Locale::CLDR – Data Package ( Perl localization data for Kʼicheʼ ) 2024-02-25T17:10:41
Locale-CLDR-Locales-Raj JGNI Locale::CLDR – Data Package ( Perl localization data for Rajasthani ) 2024-02-25T17:10:54
Locale-CLDR-Locales-Rhg JGNI Locale::CLDR – Data Package ( Perl localization data for Rohingya ) 2024-02-25T17:12:17
Locale-CLDR-Locales-Rif JGNI Locale::CLDR – Data Package ( Perl localization data for Riffian ) 2024-02-25T17:13:41
Locale-CLDR-Locales-Sa JGNI Locale::CLDR – Data Package ( Perl localization data for Sanskrit ) 2024-01-06T21:50:35
Locale-CLDR-Locales-Sat JGNI Locale::CLDR – Data Package ( Perl localization data for Santali ) 2024-01-06T21:53:44
Locale-CLDR-Locales-Sc JGNI Locale::CLDR – Data Package ( Perl localization data for Sardinian ) 2024-01-06T21:55:19
Locale-CLDR-Locales-Scn JGNI Locale::CLDR – Data Package ( Perl localization data for Sicilian ) 2024-02-25T17:27:35
Locale-CLDR-Locales-Sdh JGNI Locale::CLDR – Data Package ( Perl localization data for Southern Kurdish ) 2024-02-25T17:29:16
Locale-CLDR-Locales-Shn JGNI Locale::CLDR – Data Package ( Perl localization data for Shan ) 2024-02-25T17:36:55
Locale-CLDR-Locales-Sid JGNI Locale::CLDR – Data Package ( Perl localization data for Sidamo ) 2024-02-25T17:37:33
Locale-CLDR-Locales-Skr JGNI Locale::CLDR – Data Package ( ) 2024-02-25T17:40:13
Locale-CLDR-Locales-Sma JGNI Locale::CLDR – Data Package ( Perl localization data for Southern Sami ) 2024-02-25T17:41:45
Locale-CLDR-Locales-Smj JGNI Locale::CLDR – Data Package ( Perl localization data for Lule Sami ) 2024-02-25T17:43:11
Locale-CLDR-Locales-Sms JGNI Locale::CLDR – Data Package ( Perl localization data for Skolt Sami ) 2024-02-25T17:45:00
Locale-CLDR-Locales-Ss JGNI Locale::CLDR – Data Package ( Perl localization data for Swati ) 2024-02-25T17:49:56
Locale-CLDR-Locales-Ssy JGNI Locale::CLDR – Data Package ( Perl localization data for Saho ) 2024-02-25T17:51:22
Locale-CLDR-Locales-St JGNI Locale::CLDR – Data Package ( Perl localization data for Southern Sotho ) 2024-02-25T17:51:52
Locale-CLDR-Locales-Su JGNI Locale::CLDR – Data Package ( Perl localization data for Sundanese ) 2024-01-06T22:11:13
Locale-CLDR-Locales-Syr JGNI Locale::CLDR – Data Package ( Perl localization data for Syriac ) 2024-02-25T17:56:10
Locale-CLDR-Locales-Szl JGNI Locale::CLDR – Data Package ( Perl localization data for Silesian ) 2024-02-25T17:57:55
Locale-CLDR-Locales-Tig JGNI Locale::CLDR – Data Package ( Perl localization data for Tigre ) 2024-02-25T18:04:08
Locale-CLDR-Locales-Tn JGNI Locale::CLDR – Data Package ( Perl localization data for Tswana ) 2024-02-25T18:07:12
Locale-CLDR-Locales-Tok JGNI Locale::CLDR – Data Package ( Perl localization data for Toki Pona ) 2024-02-25T18:08:49
Locale-CLDR-Locales-Tpi JGNI Locale::CLDR – Data Package ( Perl localization data for Tok Pisin ) 2024-02-25T18:09:03
Locale-CLDR-Locales-Trv JGNI Locale::CLDR – Data Package ( Perl localization data for Taroko ) 2024-02-25T18:13:13
Locale-CLDR-Locales-Trw JGNI Locale::CLDR – Data Package ( Perl localization data for Torwali ) 2024-02-25T18:13:24
Locale-CLDR-Locales-Ts JGNI Locale::CLDR – Data Package ( Perl localization data for Tsonga ) 2024-02-25T18:15:02
Locale-CLDR-Locales-Tyv JGNI Locale::CLDR – Data Package ( Perl localization data for Tuvinian ) 2024-02-25T18:18:06
Locale-CLDR-Locales-Ve JGNI Locale::CLDR – Data Package ( Perl localization data for Venda ) 2024-02-25T18:24:31
Locale-CLDR-Locales-Vec JGNI Locale::CLDR – Data Package ( Perl localization data for Venetian ) 2024-02-25T18:25:52
Locale-CLDR-Locales-Vmw JGNI Locale::CLDR – Data Package ( Perl localization data for Makhuwa ) 2024-02-25T18:28:42
Locale-CLDR-Locales-Wa JGNI Locale::CLDR – Data Package ( Perl localization data for Walloon ) 2024-02-25T18:30:55
Locale-CLDR-Locales-Wal JGNI Locale::CLDR – Data Package ( Perl localization data for Wolaytta ) 2024-02-25T18:33:42
Locale-CLDR-Locales-Wbp JGNI Locale::CLDR – Data Package ( Perl localization data for Warlpiri ) 2024-02-25T18:33:50
Locale-CLDR-Locales-Xnr JGNI Locale::CLDR – Data Package ( Perl localization data for Kangri ) 2024-02-25T18:37:03
Locale-CLDR-Locales-Yrl JGNI Locale::CLDR – Data Package ( Perl localization data for Nheengatu ) 2024-01-06T22:42:43
Locale-CLDR-Locales-Za JGNI Locale::CLDR – Data Package ( Perl localization data for Zhuang ) 2024-02-25T18:44:50
Locale-Intl JDEGUEST A Web Intl.Locale Class Implementation 2024-10-07T05:24:54
Locale-Unicode-Data JDEGUEST Unicode CLDR SQL Data 2024-08-01T22:43:58
Locale-Unicode JDEGUEST Unicode Locale Identifier compliant with BCP47 and CLDR 2024-05-17T08:05:23
Log-Any-Simple MATHIAS A very thin wrapper around Log::Any, using a functional interface that dies automatically when you log above a given level. 2024-04-24T19:51:03
Log-Log4perl-Config-YamlConfigurator SVW Reads Log4perl YAML configurations 2024-05-29T07:51:19
MFab-Plugins-Datadog DDROWN Mojolicious plugin for Datadog APM integration 2024-11-06T16:24:14
MIDI-RtMidi-ScorePlayer GENE Play a MIDI score in real-time 2024-07-10T23:51:51
MPGA NNZ MPGA – a module that makes it easy to write PERL programs 2024-10-05T14:26:55
Mail-Colander POLETTIX Categorize and manage email messages 2024-11-28T06:49:09
Mail-Sieve POLETTIX Categorize and manage email messages 2024-11-16T10:11:54
Map-Metro-Plugin-Map-London ETJ Map::Metro map for London 2024-09-02T10:23:10
Map-Tube-Hamburg GWS Interface to the Hamburg U- and S-Bahn maps including AKN 2024-12-09T01:59:08
Map-Tube-Rome GDT Interface to the Rome tube map 2024-08-27T16:01:05
Markdown-Perl MATHIAS Very configurable Markdown processor written in pure Perl, supporting the CommonMark spec and many extensions 2024-03-31T21:17:51
Math-GSL-Alien HAKONH Easy installation of the GSL shared library 2024-07-17T09:42:10
Math-JS SISYPHUS Emulate JavaScript arithmetic in perl 2024-01-11T01:26:01
Math-LiveStats CDRAKE Pure perl module to make mean, standard deviation, and p-values available for given window sizes in streaming data 2024-10-11T04:34:55
Math-NLopt DJERIUS Math::NLopt – Perl interface to the NLopt optimization library 2024-05-01T07:53:48
Math-NumberBase-XS ZARABOZO Lighting fast number converter from one base to another base 2024-11-11T05:30:35
Math-Recaman SIMONW Calculate numbers in Recamán's sequence 2024-06-25T17:25:03
Math-Symbolic-Custom-Collect MJOHNSON Collect up Math::Symbolic expressions 2024-09-27T09:17:04
Math-Symbolic-Custom-CollectSimplify MJOHNSON Simplify Math::Symbolic expressions using Math::Symbolic::Custom::Collect 2024-12-13T10:30:30
Math-Symbolic-Custom-Matrix MJOHNSON Matrix routines for Math::Symbolic 2024-12-08T10:54:28
Math-Symbolic-Custom-Polynomial MJOHNSON Polynomial routines for Math::Symbolic 2024-11-27T17:41:18
Math-Symbolic-Custom-ToShorterString MJOHNSON Shorter string representations of Math::Symbolic trees 2024-09-16T19:09:06
MetaCPAN-Pod-HTML HAARG Format Pod as HTML for MetaCPAN 2024-08-26T14:55:52
Microsoft-Teams-WebHook TYRRMINAL Microsoft Teams WebHook with AdaptiveCards for formatting notifications 2024-02-20T19:13:14
Minima TESSARIN Efficient web framework built with modern core classes 2024-10-04T21:57:09
Mo-utils-CSS SKIM Mo CSS utilities. 2024-01-06T14:56:51
Mo-utils-Country SKIM Mo country utilities. 2024-04-11T13:41:33
Mo-utils-Email SKIM Mo utilities for email. 2024-01-07T23:51:14
Mo-utils-IRI SKIM Mo utilities for IRI. 2024-02-29T21:11:02
Mo-utils-Time SKIM Mo time utilities. 2024-04-12T14:28:06
Mo-utils-TimeZone SKIM Mo timezone utilities. 2024-04-03T16:34:52
Mo-utils-URI SKIM Mo utilities for URI. 2024-02-11T16:17:45
Module-Features-PluginSystem PERLANCAR Features of modules that generate text tables 2024-03-25T00:05:33
Module-Pluggable-_ModuleFeatures PERLANCAR Features declaration for Module::Pluggable 2024-03-26T00:05:20
Mojo-UserAgent-Role-Retry SSMN Retry requests on failure 2024-12-29T07:39:35
Mojo-UserAgent-Role-TotalTimeout KARJALA Role for Mojo::UserAgent that enables setting total timeout including redirects 2024-11-06T09:41:19
MojoUserAgentRoleRetry SSMN Retry requests on failure 2024-12-29T00:59:46
Mojolicious-Plugin-Authentication-OIDC TYRRMINAL OpenID Connect implementation integrated into Mojolicious 2024-04-25T19:27:09
Mojolicious-Plugin-Authorization-AccessControl TYRRMINAL Integrate Authorization::AccessControl into Mojolicious 2024-05-16T23:23:55
Mojolicious-Plugin-BModel BCDE Catalyst-like models in Mojolicious 2024-09-16T17:46:31
Mojolicious-Plugin-Badge GDT Badge Plugin for Mojolicious 2024-09-19T21:29:36
Mojolicious-Plugin-Config-Structured-Bootstrap TYRRMINAL Autoconfigure Mojolicious application and plugins 2024-05-20T13:39:53
Mojolicious-Plugin-Credentials LEONT A credentials store in mojo 2024-01-31T01:34:25
Mojolicious-Plugin-Cron-Scheduler TYRRMINAL Mojolicious Plugin that wraps Mojolicious::Plugin::Cron for job configurability 2024-04-16T11:48:54
Mojolicious-Plugin-Data-Transfigure TYRRMINAL Mojolicious adapter for Data::Transfigure 2024-05-18T03:42:37
Mojolicious-Plugin-INIConfig-Extended HESCO Mojolicious Plugin to overload a Configuration 2024-02-13T02:33:46
Mojolicious-Plugin-Migration-Sqitch TYRRMINAL Run Sqitch database migrations from a Mojo app 2024-04-30T15:37:52
Mojolicious-Plugin-Module-Loader TYRRMINAL Automatically load mojolicious namespaces 2024-04-19T14:09:36
Mojolicious-Plugin-ORM-DBIx TYRRMINAL Easily load and access DBIx::Class functionality in Mojolicious apps 2024-04-03T13:32:06
Mojolicious-Plugin-SendEmail TYRRMINAL Easily send emails from Mojolicious applications 2024-04-01T20:40:24
Mojolicious-Plugin-Sessionless TYRRMINAL Installs noop handlers to disable Mojolicious sessions 2024-04-16T12:45:37
Mojolicious-Plugin-WebComponent RES An effort to make creating and using custom web components easier 2024-02-29T16:06:39
MooX-Pack LNATION The great new MooX::Pack! 2024-04-20T01:52:17
MooseX-JSONSchema GETTY Adding JSON Schema capabilities to your Moose class 2024-08-03T20:36:33
MooseX-Types-StrictScalarTypes DCANTRELL strict Moose type constraints for integers, numbers, and Booleans 2024-09-01T10:27:38
Mslm MSLM The official Perl Library for Mslm APIs. 2024-01-16T04:34:02
Multi-Dispatch DCONWAY Multiple dispatch for Perl subs and methods 2024-06-26T22:42:28
Music-Dice GENE Define and roll musical dice 2024-11-30T22:57:09
Neo4j-Driver-Plugin-LWP AJNN Neo4j::Driver plug-in for libwww-perl 2024-12-11T07:09:57
Net-Async-OpenExchRates VNEALV Interaction with OpenExchangeRates API 2024-04-20T11:46:28
Net-EANSearch JANW Perl module for EAN and ISBN lookup and validation using the API on https://www.ean-search.org 2024-02-13T15:30:27
Net-EPP-MITMProxy GBROWN A generic EPP proxy server framework. 2024-05-02T11:56:41
Net-EPP-Server GBROWN A simple EPP server implementation. 2024-04-08T09:38:21
Net-LineNotify SHINGO A simple wrapper for LINE Notify API 2024-09-29T10:48:48
Net-MailChimp ARTHAS Perl library with MINIMAL interface to use MailChimp API. 2024-03-14T13:52:35
Net-OpenSSH-More TEODESIAN Net::OpenSSH submodule with many useful features 2024-08-09T00:03:26
Net-OpenVPN-Manager ATOY Start OpenVPN Manager and return PSGI handler 2024-03-08T18:07:11
Net-PaccoFacile ARTHAS Perl library with MINIMAL interface to use PaccoFacile API. 2024-03-01T16:16:12
Net-RDAP-Server GBROWN an RDAP server framework. 2024-10-22T15:56:38
Net-SNMP-Mixin-PoE GAISSMAI mixin class for power over ethernet related infos from 2024-09-10T21:05:54
Number-Iterator LNATION The great new Number::Iterator! 2024-04-18T19:45:31
Number-Iterator-XS LNATION iterate numbers faster 2024-07-26T03:56:33
OSLV-Monitor VVELOX OS level virtualization monitoring extend for LibreNMS. 2024-09-10T21:09:59
Object-Pad-LexicalMethods PEVANS operator for lexical method call syntax 2024-09-20T19:02:48
Object-Pad-Operator-Of PEVANS access fields of other instances 2024-08-22T11:30:12
Ogma LNATION Command Line Applications via Rope 2024-05-07T08:27:11
OpenAPI-PerlGenerator CORION create Perl client SDKs from OpenAPI specs 2024-03-24T11:02:37
OpenFeature-SDK CATOUC OpenFeature SDK for Perl 2024-08-17T19:40:04
OpenMP OODLER Metapackage for using OpenMP in Perl 2024-07-19T21:12:29
OpenSearch LHRST It's new $module 2024-05-15T15:22:31
PDK-Concern CARELINE PDK::Concern::H3c::Netdisco – Explore and manage LLDP topology for H3C devices 2024-10-17T13:32:50
PDK-Content CARELINE Content parsing and management for PDK 2024-10-06T13:51:02
PDK-Crate CARELINE Everything that PDK modules needs 2024-10-05T12:19:02
PDK-DBI CARELINE PDK::DBI- A Moose-based wrapper for MySQL|Postgresql database operations using DBIx::Custom 2024-10-10T03:28:18
PDK-Utils CARELINE Utility functions for PDK 2024-10-07T06:42:24
PDL-Complex ETJ handle complex numbers (DEPRECATED – use native complex) 2024-11-26T02:13:32
PDL-Fit ETJ Levenberg-Marquardt fitting routine for PDL 2024-12-09T12:50:50
PDL-GSL ETJ parameter estimations and probability density functions for distributions. 2024-12-09T06:08:00
PDL-Graphics-IIS ETJ Display PDL images on IIS devices (saoimage/ximtool) 2024-09-30T06:20:14
PDL-Graphics-Limits ETJ derive limits for display purposes 2024-11-25T23:17:09
PDL-IO-Browser ETJ 2D data browser for PDL 2024-11-26T00:27:38
PDL-IO-Dicom ETJ a module for reading DICOM images. 2024-12-04T02:35:06
PDL-IO-ENVI ETJ read ENVI data files into PDL 2024-12-04T04:14:07
PDL-IO-GD ETJ Interface to the GD image library. 2024-12-03T05:35:52
PDL-IO-HDF ETJ A PDL interface to the HDF4 library. 2024-12-03T04:08:00
PDL-IO-IDL ETJ I/O of IDL Save Files 2024-12-04T02:48:09
PDL-Minuit ETJ Minuit 1 optimization routines for PDL 2024-09-30T12:57:29
PDL-Opt-GLPK SOMMREY PDL interface to the GNU Linear Programming Kit 2024-02-21T20:32:39
PDL-Opt-Simplex ETJ Simplex optimization routines 2024-12-09T13:46:51
PDL-Perldl2 ETJ Simple shell (version 2) for PDL 2024-11-26T02:48:28
PDL-Transform-Proj4 ETJ PDL::Transform interface to the Proj4 projection library 2024-12-03T08:19:30
POE-Wheel-Run-DaemonHelper VVELOX Helper for the POE::Wheel::Run for easy controlling logging of stdout/err as well as restarting with backoff. 2024-01-16T18:57:00
Parallel-TaskExecutor MATHIAS Cross-platform executor for parallel tasks executed in forked processes 2024-04-13T20:02:27
Parse-SNI OLEG parse Server Name Indication from TLS handshake 2024-01-23T07:57:10
Password-OnePassword-OPCLI RJBS get items out of 1Password with the "op" CLI 2024-05-25T15:24:06
Perl-Critic-Policy-Plicease-ProhibitArrayAssignAref PLICEASE Don't assign an anonymous arrayref to an array 2024-12-28T21:26:23
Perl-PrereqScanner-Scanner-DistBuild LEONT scan for Dist::Build dependencies 2024-07-12T12:03:35
Perl-Version-Bumper BOOK Update use VERSION on any Perl code 2024-11-20T08:48:15
PerlIO-win32console TONYC Win32 console output layer 2024-05-26T13:03:53
Perlgram-Bot AMIRCANDY 2024-02-26T10:23:19
Plack-App-CPAN-Changes SKIM Plack application for CPAN::Changes object. 2024-03-14T18:23:48
Plack-App-Catmandu-OAI NJFRANCK drop in replacement for Dancer::Plugin::Catmandu::OAI 2024-08-23T07:58:26
Plack-App-Catmandu-SRU NJFRANCK drop in replacement for Dancer::Plugin::Catmandu::SRU 2024-07-30T09:27:07
Plack-App-ChangePassword SKIM Plack change password application. 2024-02-08T21:15:14
Plack-App-Login-Request SKIM Plack application for request of login information. 2024-04-29T14:23:02
Plack-App-Storage-Abstract BRTASTIC Serve files with Storage::Abstract 2024-10-13T20:10:13
Plack-Middleware-Static-Precompressed ARISTOTLE serve a tree of static pre-compressed files 2024-03-14T11:30:12
Plack-Middleware-Validate_Google_IAP_JWT HKOBA Validate JWT from Google IAP 2024-12-18T05:31:51
Plack-Middleware-Zstandard PLICEASE Compress response body with Zstandard 2024-05-10T18:08:23
Plugin-System-_ModuleFeatures PERLANCAR Features declaration for Plugin::System 2024-03-27T00:05:42
Pod-Weaver-Plugin-Sah-SchemaBundle PERLANCAR Plugin to use when building Sah::SchemaBundle::* distribution 2024-02-26T00:06:02
Pongo HAPPYBEAR A Perl MongoDB interface using XS and the MongoDB C driver. 2024-11-29T05:14:14
Poz YTURTLE A simple, composable, and extensible data validation library for Perl. 2024-12-08T07:09:15
Protocol-Sys-Virt-Devel EHUELS Development helper for Protocol::Sys::Virt and its dependants 2024-08-31T20:48:14
Protocol-Sys-Virt EHUELS Transport independent implementation of the remote LibVirt protocol 2024-08-31T21:36:13
QRCode-Any PERLANCAR Common interface to QRCode functions 2024-05-06T00:06:19
Qhull DJERIUS a really awesome library 2024-03-05T20:37:59
Quaint LNATION The great new Quaint! 2024-10-27T12:51:58
RDF-Cowl ZMUGHAL A lightweight API for working with OWL 2 ontologies 2024-02-15T03:37:41
RT-Extension-Import-CSV BPS RT-Extension-Import-CSV Extension 2024-05-15T18:16:51
RT-Extension-SMSWebhook-Twilio BPS RT-Extension-SMSWebhook-Twilio Extension 2024-06-13T22:40:55
Random-Simple BAKERSCOT Simple, usable, real world random numbers 2024-11-08T23:59:53
Raylib-FFI PERIGRIN Perl FFI bindings for raylib 2024-06-27T05:58:30
RecentInfo-Manager CORION 2024-11-03T07:32:19
Regex-Common ARFREITAS Provide commonly requested regular expressions 2024-08-12T22:48:17
Regexp-IntInequality HAUKEX generate regular expressions to match integers greater than / less than / etc. a value 2024-03-08T17:59:24
Result-Simple KFLY A dead simple perl-ish Result like F#, Rust, Go, etc. 2024-11-23T09:23:32
Rex-Commands-PerlSync BRTASTIC Sync directories, better 2024-10-01T18:26:54
Rope-Cmd LNATION Command Line Applications via Rope 2024-08-30T20:00:03
RxPerl-Extras KARJALA extra operators for RxPerl 2024-08-06T10:18:15
SMS-Send-CZ-Smsmanager RADIUSCZ SMS::Send driver for SMS Manager – Czech Republic 2024-06-10T20:58:38
SPVM-HTTP-Tiny KIMOTO HTTP Client 2024-02-23T08:53:30
SPVM-IO-Socket-SSL KIMOTO Sockets for SSL. 2024-10-28T02:23:49
SPVM-Net-DNS-Native KIMOTO Short Description 2024-10-21T07:04:37
SPVM-R KIMOTO Porting R language Features 2024-06-26T05:10:09
SPVM-Resource-Eigen KIMOTO Resource for C++ Eigen library 2024-07-16T23:56:40
SQL-Formatter PLICEASE Format SQL using the rust sqlformat library 2024-10-05T00:09:29
STIX GDT Structured Threat Information Expression (STIX) 2024-11-18T11:00:07
Sah-PSchemaBundle PERLANCAR Convention for Sah-PSchemaBundle-* distribution 2024-06-06T00:06:05
Sah-PSchemaBundle-Array PERLANCAR Parameterized schemas related to array type 2024-06-07T00:06:17
Sah-PSchemaBundle-Perl PERLANCAR Parameterized schemas related to Perl 2024-06-08T00:06:02
Sah-PSchemaBundle-Re PERLANCAR Various regular-expression (parameterized) schemas 2024-06-09T00:05:56
Sah-SchemaBundle PERLANCAR Convention for Sah-SchemaBundle-* distribution 2024-03-28T00:05:49
Sah-SchemaBundle-Array PERLANCAR Sah schemas related to array type 2024-03-29T00:05:36
Sah-SchemaBundle-ArrayData PERLANCAR Sah schemas related to ArrayData 2024-03-30T00:05:33
Sah-SchemaBundle-Binary PERLANCAR Sah schemas related to binary data 2024-03-17T00:05:16
Sah-SchemaBundle-Bool PERLANCAR Sah schemas related to bool data type 2024-03-24T00:05:52
Sah-SchemaBundle-BorderStyle PERLANCAR Sah schemas related to BorderStyle 2024-03-31T00:05:05
Sah-SchemaBundle-Business-ID-BCA PERLANCAR Sah schemas related to BCA (Bank Central Asia) bank 2024-04-23T00:05:53
Sah-SchemaBundle-Business-ID-Mandiri PERLANCAR Sah schemas related to Mandiri bank 2024-04-30T00:05:43
Sah-SchemaBundle-Business-ID-NIK PERLANCAR Sah schemas related to Indonesian citizenship registration numbers (NIK) 2024-05-01T00:05:13
Sah-SchemaBundle-Business-ID-NKK PERLANCAR Sah schemas related to Indonesian family card number (NKK) 2024-05-02T00:05:52
Sah-SchemaBundle-Business-ID-NOPPBB PERLANCAR Sah schemas related to Indonesian property tax numbers (NOP PBB) 2024-05-03T00:05:32
Sah-SchemaBundle-Business-ID-NPWP PERLANCAR Sah schemas related to Indonesian taxpayer registration number (NPWP) 2024-05-04T00:05:59
Sah-SchemaBundle-Business-ID-SIM PERLANCAR Sah schemas related to Indonesian driving license number (nomor SIM) 2024-05-05T00:06:14
Sah-SchemaBundle-CPAN PERLANCAR Sah schemas related to CPAN 2024-06-15T00:07:21
Sah-SchemaBundle-Chrome PERLANCAR Various Sah schemas related to Google Chrome 2024-06-12T00:06:44
Sah-SchemaBundle-Code PERLANCAR Various schemas related to 'code' type and coderefs 2024-06-10T04:51:45
Sah-SchemaBundle-Collection PERLANCAR Various Sah collection (array/hash) schemas 2024-06-16T00:05:16
Sah-SchemaBundle-Color PERLANCAR Sah schemas related to color codes/names 2024-06-12T00:06:55
Sah-SchemaBundle-ColorScheme PERLANCAR Sah schemas related to color schemes 2024-06-23T15:45:50
Sah-SchemaBundle-ColorTheme PERLANCAR Sah schemas related to ColorTheme 2024-06-30T00:05:31
Sah-SchemaBundle-Comparer PERLANCAR Sah schemas related to Comparer 2024-04-21T00:05:30
Sah-SchemaBundle-Country PERLANCAR Various Sah schemas related to country codes/names 2024-07-14T00:05:31
Sah-SchemaBundle-Currency PERLANCAR Various Sah currency schemas 2024-07-21T00:06:11
Sah-SchemaBundle-DBI PERLANCAR Schemas related to DBI 2024-07-28T00:06:12
Sah-SchemaBundle-DNS PERLANCAR Schemas related to DNS 2024-08-04T00:05:19
Sah-SchemaBundle-Data-Sah PERLANCAR Sah schemas related to Data::Sah 2024-08-11T00:06:03
Sah-SchemaBundle-DataSizeSpeed PERLANCAR Sah schemas related to data sizes & speeds (filesize, transfer speed, etc) 2024-08-02T21:50:19
Sah-SchemaBundle-Nutrient PERLANCAR Sah schemas related to nutrients 2024-06-04T02:10:55
Sah-SchemaBundle-Path PERLANCAR Schemas related to filesystem path 2024-04-01T00:06:15
Sah-SchemaBundle-Perl PERLANCAR Sah schemas related to Perl 2024-04-02T00:05:40
Sah-SchemaBundle-SortKey PERLANCAR Sah schemas related to SortKey 2024-04-22T00:06:02
Sah-SchemaBundle-Sorter PERLANCAR Sah schemas related to Sorter 2024-04-03T00:14:57
Sah-Schemas-Business-ID-BCA PERLANCAR Sah schemas related to BCA (Bank Central Asia) bank 2024-01-19T00:06:10
Sah-Schemas-Business-ID-Mandiri PERLANCAR Sah schemas related to Mandiri bank 2024-01-20T00:05:58
Sah-Schemas-Business-ID-NIK PERLANCAR Sah schemas related to Indonesian NIK numbers 2024-01-09T07:04:01
Sah-Schemas-Business-ID-NKK PERLANCAR Sah schemas related to Indonesian family card number (NKK) 2024-01-09T09:11:12
Sah-Schemas-Business-ID-NOPPBB PERLANCAR Sah schemas related to Indonesian property tax numbers (NOP PBB) 2024-01-12T00:11:12
Sah-Schemas-Business-ID-NPWP PERLANCAR Sah schemas related to Indonesian taxpayer registration number (NPWP) 2024-01-11T00:11:24
Sah-Schemas-Business-ID-SIM PERLANCAR Sah schemas related to Indonesian driving license number (nomor SIM) 2024-01-15T00:19:01
Sah-Schemas-Comparer PERLANCAR Sah schemas related to Comparer 2024-02-16T00:06:37
Sah-Schemas-HashData PERLANCAR Sah schemas related to HashData 2024-01-24T00:05:49
Sah-Schemas-SortKey PERLANCAR Sah schemas related to SortKey 2024-02-18T14:01:38
Sah-Schemas-Sorter PERLANCAR Sah schemas related to Sorter 2024-04-03T00:05:43
Salus LNATION The great new Salus! 2024-05-09T20:06:13
Seven LNATION The great new Seven! 2024-04-13T03:30:11
Shannon-Entropy-XS LNATION Calculate the Shannon entropy H of a given input string faster. 2024-07-18T19:43:55
Slack-BlockKit RJBS a toolkit for building BlockKit blocks for Slack 2024-07-04T01:51:26
Slackware-SBoKeeper SAMYOUNG SlackBuild package manager helper 2024-10-31T22:09:33
SlapbirdAPM-Agent-Dancer2 RAWLEYFOW Agent software for the Perl application performance monitor, Slapbird. slapbirdapm.com 2024-08-25T20:49:02
SlapbirdAPM-Agent-Mojo RAWLEYFOW Agent software for the Perl application performance monitor, Slapbird. slapbirdapm.com 2024-08-09T21:00:04
SlapbirdAPM-Agent-Plack RAWLEYFOW A Plack agent software for the Perl application performance monitor, Slapbird. slapbirdapm.com 2024-08-18T02:37:49
SmsAero SMSAERO Send SMS via smsaero.ru 2024-12-09T11:55:19
Socket-More-Interface DRCLAW Query network interfaces of your system 2024-01-15T22:26:01
Socket-More-Lookup DRCLAW System DNS Lookup Routines 2024-01-17T00:58:57
Socket-More-Resolver DRCLAW Loop Agnostic Asynchronous DNS Resolving 2024-01-17T22:58:34
Software-Security-Policy TIMLEGGE Create a Security Policy for your distribution 2024-12-16T03:23:46
Sort-BySimilarity PERLANCAR Sort by most similar to a reference string 2024-02-02T00:05:29
Sort-Key-SortKey PERLANCAR Thin wrapper for Sort::Key to easily use SortKey::* 2024-04-04T00:05:05
Sort-SubBundle-BySimilarity PERLANCAR Sort::Sub subroutines that sort items based on how similar it is to the target string 2024-01-18T00:05:32
Sort-SubBundle-DefHash PERLANCAR Sort::Sub subroutines related to DefHash 2024-01-13T00:11:24
Sort-SubBundle-Rinci PERLANCAR Sort::Sub subroutines related to Rinci 2024-01-16T00:11:13
Sort-SubBundle-Sah PERLANCAR Sort::Sub subroutines related to Sah 2024-01-17T00:05:53
SortExample PERLANCAR Sort examples 2024-02-27T00:05:08
SortExample-Color-Rainbow-EN PERLANCAR Ordered list of names of colors in the rainbow, in English 2024-04-05T00:06:12
SortKey PERLANCAR Reusable sort key generators 2024-02-14T00:05:41
SortKey-Num-by_length PERLANCAR String length as sort key 2024-02-15T00:05:40
SortKey-Num-file_mtime PERLANCAR File modification time as sort key 2024-10-13T00:05:46
SortKey-Num-file_num_links PERLANCAR File number of (hard) links as sort key 2024-12-08T00:05:11
SortKey-Num-file_size PERLANCAR File size as sort key 2024-12-15T00:05:21
SortKey-Num-length PERLANCAR String length as sort key 2024-02-15T00:05:51
SortKey-Num-pattern_count PERLANCAR Number of occurrences of string/regexp pattern as sort key 2024-04-06T00:05:41
SortKey-Num-similarity PERLANCAR Similarity to a reference string as sort key 2024-04-08T00:05:21
SortKey-Num-similarity_jaccard PERLANCAR Jaccard coefficient of a string to a reference string, as sort key 2024-05-30T00:05:29
SortKey-date_in_text PERLANCAR Date found in text as sort key 2024-04-19T00:05:23
SortSpec PERLANCAR Specification of sort specification 2024-04-09T00:05:37
SortSpec-Perl-CPAN-ChangesGroup-PERLANCAR PERLANCAR Specification to sort changes group heading PERLANCAR-style 2024-04-10T00:05:24
Sorter PERLANCAR Sorter 2024-02-07T00:11:23
Sorter-by_similarity PERLANCAR Sort by most similar to a reference string 2024-02-13T00:06:16
Sorter-file_by_mtime PERLANCAR Sort files by mtime (modification time) 2024-10-20T00:06:08
Sorter-file_by_num_links PERLANCAR Sort files by number of (hard) links 2024-12-22T00:06:07
Sorter-file_by_size PERLANCAR Sort files by size 2024-12-29T00:05:07
Sorter-from_comparer PERLANCAR Sort by comparer generated by a Comparer:: module 2024-04-11T00:05:17
Sorter-from_sortkey PERLANCAR Sort by keys generated by a SortKey:: module 2024-04-12T00:05:58
SpeL-Wizard WDAEMS engine to build audio files from the spel files generated by SpeL and maintain their up-to-dateness 2024-06-10T08:18:20
SpeL-Wizard-20240610-TRIAL WDAEMS engine to build audio files from the spel files generated by SpeL and maintain their up-to-dateness 2024-06-10T08:02:44
Sq DAVIDRAAB The Sq Language 2024-12-25T05:30:48
Sqids MYSOCIETY generate short unique identifiers from numbers 2024-04-06T10:43:27
Standup-Diary SMONFF Manage a simple journal in Markdown files 2024-11-23T14:08:21
Storage-Abstract BRTASTIC Abstraction for file storage 2024-10-13T14:20:10
Str-Iter PERLANCAR Generate a coderef iterator to iterate a string one (or more) character(s) at a time 2024-11-17T00:06:14
String-Mask-XS LNATION mask sensitive data faster 2024-07-03T21:44:29
String-Random-Regexp-regxstring BLIAKO Generate random strings from a regular expression 2024-06-28T23:27:57
Sumu-Perl-Modules CEEJAY Perl Modules 2024-09-28T16:29:04
Sumu-Windows-Upm4win CEEJAY User Pass Manager For Windows 2024-12-13T16:44:11
Super-Powers LNATION The hiddden truth 2024-05-02T04:21:41
Switch-Back DCONWAY given/when for a post-given/when Perl 2024-06-26T22:42:39
Switch-Right DCONWAY Switch and smartmatch done right this time 2024-06-26T22:45:36
Syntax-Keyword-Assert PEVANS debugging checks that throw exceptions 2024-10-01T14:24:23
Syntax-Keyword-PhaserExpression PEVANS phasers as arbitrary expressions rather than blocks 2024-10-28T21:33:23
Syntax-Operator-Is PEVANS match operator using Data::Checks constraints 2024-07-08T14:59:03
Sys-Async-Virt EHUELS LibVirt protocol implementation for clients 2024-09-15T20:23:53
Sys-Ebpf TAKEMIO Pure-Perl interface for eBPF (extended Berkeley Packet Filter) 2024-10-04T10:02:24
Sys-GetRandom-FFI RRWO get random bytes from the system 2024-12-27T00:55:22
Sys-GetRandom-PP MAUKE pure Perl interface to getrandom(2) 2024-06-15T05:21:14
TAP-Formatter-JUnit-PrintTxtStdout DERIV 2024-01-31T10:09:30
TLV-EMV-Parser GHE A module for parsing EMV TLV strings 2024-01-15T21:42:01
TLV-EMV-Tags GHE A module that holds all EMV tags 2024-01-15T21:42:12
TLV-Parser GHE A module for parsing TLV strings 2024-01-15T21:26:13
TableData-Business-ID-BPOM-FoodAdditive PERLANCAR Food additives in BPOM 2024-04-10T11:10:00
TableData-Business-ID-BPOM-NutritionLabelRef PERLANCAR Nutrients 2024-05-27T00:05:19
TableData-Business-ID-Kemenkes-RDA PERLANCAR Indonesian RDA (AKG, Angka Kecukupan Gizi) 2024-07-02T03:05:09
TableData-Health-Nutrient PERLANCAR Nutrients 2024-05-25T00:05:57
TableDataRole-Source-DBI PERLANCAR Role to access table data from DBI 2024-05-28T00:05:38
TableDataRole-Source-SQLite PERLANCAR Role to access table data from SQLite database table/query 2024-05-29T00:05:31
Tags-HTML-CPAN-Changes SKIM Tags helper for CPAN::Changes object. 2024-03-14T09:55:49
Tags-HTML-ChangePassword SKIM Tags helper for change password. 2024-02-07T20:04:02
Tags-HTML-DefinitionList SKIM Tags helper for definition list. 2024-05-17T16:54:28
Tags-HTML-Element SKIM Tags helper for HTML elements. 2024-01-06T18:37:31
Tags-HTML-Footer SKIM Tags helper for HTML footer. 2024-06-03T15:29:04
Tags-HTML-Image SKIM Tags helper class for image presentation. 2024-04-20T13:32:39
Tags-HTML-Login-Request SKIM Tags helper for login request. 2024-04-29T11:23:37
Tags-HTML-Message-Board SKIM Tags helper for message board. 2024-06-03T16:01:31
Tags-HTML-Navigation-Grid SKIM Tags helper for navigation grid. 2024-05-10T18:53:42
Tags-HTML-Tree SKIM Tags helper for Tree. 2024-05-01T16:50:02
Task-Map-Tube MANWAR Bundles Map::Tube::* map packages. 2024-12-12T11:04:59
Task-Map-Tube-Bundle MANWAR Bundles Map::Tube::* map packages. 2024-12-12T11:33:02
Task-MemManager CHRISARG A memory allocator for low level code in Perl. 2024-08-25T23:42:18
Task-MemManager-CMalloc CHRISARG Allocates buffers using C's malloc 2024-12-02T03:33:50
Tcl-Tk-Tkwidget-Tix VKON 2024-01-01T18:54:55
Tcl-Tk-Tkwidget-treectrl VKON 2024-01-01T08:54:34
Temperature-Calculate-DegreeDays AALLGOOD Perl package to compute cooling, heating, and growing degree days 2024-12-03T20:23:00
Template-EmbeddedPerl JJNAPIORK Validation Library and more 2024-09-13T22:16:50
Template-Plexsite DRCLAW Class for interlinked templating 2024-11-12T03:59:54
Template-Plugin-Package PETDANCE allow calling of class methods on arbitrary classes that do not accept the class name as their first argument. 2024-03-12T04:32:11
Term-ANSI-Sprintf LNATION sprintf with ANSI colors 2024-08-25T09:46:37
Test-SpellCheck PLICEASE Check spelling of POD and other documents 2024-12-29T15:22:23
Test-SpellCheck-Plugin-Lang-EN-US PLICEASE US English language dictionary for Test::SpellCheck 2024-12-29T15:25:31
Test2-Plugin-DBBreak JOSERIJO Automatic breakpoint on failing tests for the perl debugger 2024-10-23T12:08:14
Test2-Tools-ComboObject PLICEASE Combine checks and diagnostics into a single test as an object 2024-11-22T07:22:27
Test2-Tools-MIDI JMATES test MIDI file contents 2024-04-09T23:42:34
Text-Schmutz RRWO You̇r screen is quiṭe dirty, please cleȧn it. 2024-07-11T22:41:24
Text-Table-Boxed JIMAVERA Automate separators and rules for Text::Table 2024-12-12T01:46:12
Text-Template-Tiny JV Variable substituting template processor 2024-07-05T11:10:37
Tie-Array-ArrayData PERLANCAR Access ArrayData object as a tied array 2024-01-23T00:05:50
Tie-Array-TableData PERLANCAR Access TableData object as a tied array 2024-01-22T00:05:54
Tie-Hash-DataSection PLICEASE Access __DATA__ section via tied hash 2024-12-24T05:56:04
Tie-Hash-HashData PERLANCAR Access HashData object as a tied hash 2024-02-09T00:05:25
Time-RTM CADE Run-time metrics stats 2024-12-01T23:49:06
Tiny-Prof TIMKA Perl profiling made simple to use. 2024-04-26T07:19:38
Tk-AppWindow HANJE an application framework based on Tk 2024-02-28T15:29:57
Tk-DynaMouseWheelBind HANJE Wheel scroll panes filled with widgets 2024-05-20T18:53:11
Tk-FileBrowser HANJE Multi column file system explorer 2024-03-29T21:22:08
Tk-PodViewer HANJE Simple ROText based pod viewer. 2024-08-20T20:06:36
Tk-Terminal HANJE Running system commands in a Tk::Text widget. 2024-07-03T09:24:21
Tradestie-WSBetsAPI NOBUNAGA Tradestie's Wallstreet Bets API 2024-07-01T19:57:16
URI-Shorten TEODESIAN Shorten URIs so that you don't have to rely on external services 2024-05-07T08:50:48
URI-Shortener TEODESIAN Shorten URIs so that you don't have to rely on external services 2024-05-07T15:53:48
UserAgent-Any MATHIAS Wrapper above any UserAgent library, supporting sync and async calls. 2024-11-15T21:01:30
UserAgent-Any-JSON MATHIAS Specialization of UserAgent::Any for JSON APIs. 2024-11-16T20:16:37
UserPassManagerForWindows CEEJAY User Pass Manager For Windows 2024-12-13T15:39:41
Version-libversion-XS GDT Perl binding for libversion 2024-05-01T20:09:03
WWW-Gemini ANTONOV 2024-03-11T02:51:49
WWW-Suffit-Plugin-ConfigAuth ABALAMA The Suffit plugin for authentication and authorization providing via configuration 2024-02-22T08:17:35
WWW-Suffit-Plugin-FileAuth ABALAMA The Suffit plugin for authentication and authorization by password file 2024-02-22T11:39:04
WWW-Suffit-Plugin-SuffitAuth ABALAMA The Suffit plugin for Suffit API authentication and authorization providing 2024-02-22T08:16:09
Weather-API-Base DKECHAG Base/util module for Weather API clients 2024-10-30T23:56:19
Weather-OWM DKECHAG Perl client for the OpenWeatherMap (OWM) API 2024-10-06T19:54:59
Web-ACL VVELOX A helper for creating basic apikey/slug/IP based ACLs. 2024-01-02T20:17:08
Web-Async TEAM Future-based web+HTTP handling 2024-04-23T16:50:24
WebGPU-Direct ATRODO Direct access to the WebGPU native APIs. 2024-01-29T03:54:38
WebService-Chroma LNATION chromadb client 2024-12-16T20:45:59
WebService-GrowthBook DERIV 2024-07-02T11:17:20
WebService-Hydra DERIV 2024-09-30T03:56:43
WebService-Xential WATERKIP A Xential REST API module 2024-09-18T01:25:55
Webservice-CVEDB-API HAX Fast Vulnerability lookups using CVE_ID and CPE23 2024-09-15T22:49:58
Webservice-InternetDB-API HAX Fast IP Lookups for Open Ports and Vulnerabilities using InternetDB API 2024-09-08T20:11:16
Webservice-Ipify-API HAX Lookup your IP address using Ipify.org 2024-09-08T21:44:08
Webservice-KeyVal-API OODLER Perl API client for the REPLACE API service, https://keyval.org/. 2024-09-23T19:21:15
Webservice-Purgomalum-API HAX Filter and removes profanity and unwanted text from input using PurgoMalum.com's free API 2024-09-20T22:41:00
Webservice-Sendy-API OODLER Sendy's integration API Perl client and commandline utility 2024-12-29T21:28:13
Whelk BRTASTIC A friendly API framework based on Kelp 2024-07-03T13:59:32
Win32-Console-DotNet BRICKPOOL Win32 Console .NET interface 2024-07-29T07:05:25
Win32API-RecentFiles CORION recently accessed file API functions on Windows 2024-07-29T18:16:24
XDR-Gen EHUELS Generate (de)serializers for XDR definitions 2024-06-08T15:05:53
XDR-Parse EHUELS Parse XDR (eXternal Data Representation) definitions into an AST (Abstract Syntax Tree) 2024-05-17T13:01:54
XTP DYLIBSO XTP Perl SDK 2024-10-30T23:18:31
Xerarch LNATION The great new Xerarch! 2024-10-09T19:27:16
YAGL RLOVELAND Yet Another Graph Library 2024-12-08T23:12:44
YAML-Ordered-Conditional LNATION A conditional language within an ordered YAML struct 2024-04-06T06:05:51
Zleep LNATION zleep 2024-09-07T06:11:28
_Acme-Local CONTRA The great new _Acme::Local! 2024-11-19T07:35:37
blib-tiny PLICEASE Like blib but lighter 2024-12-22T23:29:29
e TIMKA The great new e! 2024-05-08T15:09:45
eugener-test EUGENER A test package. DOnt install. 2024-11-20T12:58:19
kraken PHILIPPE api.kraken.com connector 2024-04-05T09:11:35
kura KFLY Store constraints for Data::Checks, Type::Tiny, Moose and more. 2024-08-18T13:31:06
lib-root HERNAN find perl root and push lib modules path to @INC 2024-03-30T17:27:02
mojo-util-benchmark CRLCU A set of utilities for working with collections of data. 2024-02-07T13:49:03
optional EXODIST Pragma to optionally load a module (or pick from a list of modules) and provide a constant and some tools for taking action depending on if it loaded or not. 2024-05-14T21:33:17
papersway SPWHITTON PaperWM-like window management for Sway/i3wm 2024-04-12T07:52:39
perl-libssh QGARNIER Support for the SSH protocol via libssh. 2024-05-28T08:35:27
perlwhich MMCCLENN locate a Perl module 2024-01-03T04:29:55
this_mod PERLANCAR Load "this module" 2024-01-06T07:55:12

Stats

Number of new CPAN distributions this period: 897

Number of authors releasing new CPAN distributions this period: 195

Authors by number of new CPAN distributions this period:

No Author Distributions
1 PERLANCAR 206
2 JGNI 100
3 SKIM 36
4 LNATION 26
5 PLICEASE 20
6 LEONT 20
7 CHRISARG 17
8 ETJ 16
9 TYRRMINAL 15
10 JANESKIL 11
11 BRTASTIC 10
12 DJERIUS 10
13 CONTRA 10
14 PEVANS 9
15 SANKO 9
16 GDT 8
17 OODLER 8
18 MATHIAS 8
19 DRCLAW 7
20 HANJE 7
21 CHENGYU 7
22 GENE 7
23 TULAMILI 6
24 CARELINE 6
25 UTASHIRO 6
26 JDEGUEST 6
27 ABALAMA 6
28 GBROWN 6
29 DCONWAY 5
30 EHUELS 5
31 KIMOTO 5
32 MJOHNSON 5
33 RAWLEYFOW 5
34 EUGENER 5
35 HAX 5
36 LION 4
37 WATERKIP 4
38 JJNAPIORK 4
39 DAVECROSS 4
40 CORION 4
41 JMATES 4
42 TEODESIAN 4
43 HAARG 4
44 RRWO 4
45 BLIAKO 4
46 SAMYOUNG 4
47 JBARRETT 3
48 ARTHAS 3
49 ARISTOTLE 3
50 CEEJAY 3
51 NJFRANCK 3
52 EXODIST 3
53 SVW 3
54 POLETTIX 3
55 RJBS 3
56 DERIV 3
57 OLOOEEZ 3
58 BPS 3
59 NHORNE 3
60 STIGTSP 3
61 VVELOX 3
62 PERIGRIN 3
63 SHINGO 3
64 GHE 3
65 SHE 3
66 KARJALA 2
67 TIMKA 2
68 DILLANBH 2
69 SCHROEDER 2
70 SSMN 2
71 NHUBBARD 2
72 EXTISM 2
73 WDAEMS 2
74 KFLY 2
75 CDRAKE 2
76 MARKOV 2
77 GETTY 2
78 BIGPRESH 2
79 SMONFF 2
80 CADE 2
81 MMCCLENN 2
82 YOSHIMASA 2
83 ZMUGHAL 2
84 DKECHAG 2
85 MANWAR 2
86 SPWHITTON 2
87 TEAM 2
88 BAKERSCOT 2
89 BOD 2
90 VKON 2
91 AALLGOOD 2
92 BIGFOOT 2
93 NOBUNAGA 2
94 GWS 1
95 DCANTRELL 1
96 NICEPERL 1
97 HAIJENP 1
98 DAKKAR 1
99 JKEENAN 1
100 HAKONH 1
101 SGRAY 1
102 BDFOY 1
103 ARFREITAS 1
104 ATOY 1
105 CPANIC 1
106 AJNN 1
107 DOMM 1
108 TESSARIN 1
109 CAVAC 1
110 DYLIBSO 1
111 HOEKIT 1
112 LHRST 1
113 TOBYINK 1
114 SIDNEY 1
115 CRLCU 1
116 PHILIPPE 1
117 DAVIDRAAB 1
118 PTC 1
119 JANW 1
120 MAUKE 1
121 YUPEN 1
122 DOMERO 1
123 SOMMREY 1
124 RES 1
125 OLEG 1
126 EPISODEIV 1
127 NERDVANA 1
128 ATRODO 1
129 OLIVER 1
130 JOSERIJO 1
131 SHLOMIF 1
132 CLEACH 1
133 ABECKER 1
134 RADIUSCZ 1
135 NAUTOFON 1
136 SKAJI 1
137 HORSHACK 1
138 ZARABOZO 1
139 MBARBON 1
140 HIGHTOWE 1
141 RLOVELAND 1
142 HKOBA 1
143 GREGK 1
144 JOJESSF 1
145 TIMLEGGE 1
146 JOHNMERTZ 1
147 LANX 1
148 CHRISC 1
149 MBALLARIN 1
150 VASYAN 1
151 NNZ 1
152 ANTONOV 1
153 RSPIER 1
154 MYSOCIETY 1
155 TAKEMIO 1
156 JFORGET 1
157 SISYPHUS 1
158 PETDANCE 1
159 TONYC 1
160 JAMTWOIN 1
161 SIMONW 1
162 JIMAVERA 1
163 GEEKRUTH 1
164 BRICKPOOL 1
165 PDURDEN 1
166 JV 1
167 MRDVT 1
168 QGARNIER 1
169 BOOK 1
170 BARBARITO 1
171 DAMI 1
172 HESCO 1
173 HAPPYBEAR 1
174 CRABAPP 1
175 SFOBERSKI 1
176 HAUKEX 1
177 LITCHIE 1
178 GUL 1
179 TRIZEN 1
180 YTURTLE 1
181 BPSCHUCK 1
182 NOTHANS 1
183 AMIRCANDY 1
184 HERNAN 1
185 EGOR 1
186 BCDE 1
187 DDROWN 1
188 CATOUC 1
189 GAISSMAI 1
190 VNEALV 1
191 AAHAZRED 1
192 MSLM 1
193 SMSAERO 1
194 XMOLEX 1
195 UXYZAB 1

List of new CPAN distributions – Dec 2024

Perlancar

Published by perlancar on Monday 06 January 2025 01:29

dist author abstract date
Ac_me-Local CONTRA The great new Ac_me::Local! 2024-12-06T13:35:37
Acme-Version-Same CONTRA Module for testing CPAN Pause indexing 2024-12-19T08:38:15
Acme STIGTSP foo() returns "Foo" 2024-12-05T16:35:21
App-Changelog OLOOEEZ Simple command-line CHANGELOG.md generator written in Perl 2024-12-01T14:35:19
App-Standup-Diary SMONFF Manage a simple Markdown journal for your daily standups 2024-12-01T17:05:39
App-Tickit-Hello SKIM Tickit application with hello world. 2024-12-18T19:17:34
App-datasection PLICEASE Work with __DATA__ section files from the command line 2024-12-22T14:02:22
App-repeat PERLANCAR Repeat a command a number of times 2024-12-06T06:58:51
Bencher-ScenarioBundle-Ref-Util PERLANCAR Benchmark Ref::Util 2024-12-04T03:38:56
Bluesky SANKO The Bluesky Social Network 2024-12-03T01:56:20
CPAN-Namespace-Check-Visibility CONTRA Check if a namespace exists on public CPAN 2024-12-18T12:39:35
Circle-Miner CHENGYU The miner module for circle chain sdk. 2024-12-04T13:38:23
CommonsLang YUPEN Commonly used functions for Perl language 2024-12-25T02:31:45
Comparer-file_size PERLANCAR Compare file's size 2024-12-01T00:05:53
Config-Proxy SGRAY Loader class for HTTP proxy configuration parsers. 2024-12-10T12:47:30
Crypt-PQClean-Sign GUL Post-Quantum Cryptography with keypair 2024-12-23T12:37:49
Crypt-URandom-Password STIGTSP Generate passwords from cryptographically secure pseudorandom bytes 2024-12-27T22:59:54
Crypt-URandom-Token STIGTSP Generate secure strings for passwords, secrets and similar 2024-12-28T20:03:58
Daje-Plugin-GeneratePerl JANESKIL It's new $module 2024-12-13T14:31:42
Daje-Plugin-GenerateSQL JANESKIL It's new $module 2024-12-12T07:35:48
Daje-Plugin-GenerateSchema JANESKIL It's new $module 2024-12-12T16:54:45
Daje-Tools-DataSections JANESKIL It's new $module 2024-12-05T16:13:18
Daje-Tools-Datasections JANESKIL Load and store data sections in memory from a named *.pm 2024-12-07T14:41:02
Daje-Tools-Filechanged JANESKIL It's new $module 2024-12-08T10:11:41
Daje-Workflow-Database JANESKIL It's new $module 2024-12-24T15:22:30
Daje-Workflow-Database-Model JANESKIL It's new $module 2024-12-29T07:48:59
Daje-Workflow-Loader JANESKIL It's new $module 2024-12-22T13:51:40
Data-Section-Pluggable PLICEASE Read structured data from __DATA__ 2024-12-05T05:27:18
Data-Section-Pluggable-Plugin-Yaml PLICEASE Data::Section::Pluggable Plugin for YAML 2024-12-05T12:02:28
Data-Section-Writer PLICEASE Write __DATA__ section files for Data::Section, Data::Section::Simple or Mojo::Loader::data_section 2024-12-04T00:15:50
Drought-PET-Thornthwaite AALLGOOD Calculate potential evapotranspiration (PET) using the Thornthwaite method 2024-12-12T21:22:38
FFI-Platypus-Lang-V PLICEASE Documentation and tools for using Platypus with the V programming language 2024-12-19T01:16:18
File-FindUniq PERLANCAR Find unique or duplicate file {contents,names} 2024-12-05T07:59:52
Game-Snake LNATION A clone of the classic snake game using raylib 2024-12-29T20:33:35
JSON-LD PLICEASE Load and dump JSON files 2024-12-07T15:40:25
Map-Tube-Hamburg GWS Interface to the Hamburg U- and S-Bahn maps including AKN 2024-12-09T01:59:08
Math-Symbolic-Custom-CollectSimplify MJOHNSON Simplify Math::Symbolic expressions using Math::Symbolic::Custom::Collect 2024-12-13T10:30:30
Math-Symbolic-Custom-Matrix MJOHNSON Matrix routines for Math::Symbolic 2024-12-08T10:54:28
Mojo-UserAgent-Role-Retry SSMN Retry requests on failure 2024-12-29T07:39:35
MojoUserAgentRoleRetry SSMN Retry requests on failure 2024-12-29T00:59:46
Neo4j-Driver-Plugin-LWP AJNN Neo4j::Driver plug-in for libwww-perl 2024-12-11T07:09:57
PDL-Fit ETJ Levenberg-Marquardt fitting routine for PDL 2024-12-09T12:50:50
PDL-GSL ETJ parameter estimations and probability density functions for distributions. 2024-12-09T06:08:00
PDL-IO-Dicom ETJ a module for reading DICOM images. 2024-12-04T02:35:06
PDL-IO-ENVI ETJ read ENVI data files into PDL 2024-12-04T04:14:07
PDL-IO-GD ETJ Interface to the GD image library. 2024-12-03T05:35:52
PDL-IO-HDF ETJ A PDL interface to the HDF4 library. 2024-12-03T04:08:00
PDL-IO-IDL ETJ I/O of IDL Save Files 2024-12-04T02:48:09
PDL-Opt-Simplex ETJ Simplex optimization routines 2024-12-09T13:46:51
PDL-Transform-Proj4 ETJ PDL::Transform interface to the Proj4 projection library 2024-12-03T08:19:30
Perl-Critic-Policy-Plicease-ProhibitArrayAssignAref PLICEASE Don't assign an anonymous arrayref to an array 2024-12-28T21:26:23
Plack-Middleware-Validate_Google_IAP_JWT HKOBA Validate JWT from Google IAP 2024-12-18T05:31:51
Poz YTURTLE A simple, composable, and extensible data validation library for Perl. 2024-12-08T07:09:15
SmsAero SMSAERO Send SMS via smsaero.ru 2024-12-09T11:55:19
Software-Security-Policy TIMLEGGE Create a Security Policy for your distribution 2024-12-16T03:23:46
SortKey-Num-file_num_links PERLANCAR File number of (hard) links as sort key 2024-12-08T00:05:11
SortKey-Num-file_size PERLANCAR File size as sort key 2024-12-15T00:05:21
Sorter-file_by_num_links PERLANCAR Sort files by number of (hard) links 2024-12-22T00:06:07
Sorter-file_by_size PERLANCAR Sort files by size 2024-12-29T00:05:07
Sq DAVIDRAAB The Sq Language 2024-12-25T05:30:48
Sumu-Windows-Upm4win CEEJAY User Pass Manager For Windows 2024-12-13T16:44:11
Sys-GetRandom-FFI RRWO get random bytes from the system 2024-12-27T00:55:22
Task-Map-Tube MANWAR Bundles Map::Tube::* map packages. 2024-12-12T11:04:59
Task-Map-Tube-Bundle MANWAR Bundles Map::Tube::* map packages. 2024-12-12T11:33:02
Task-MemManager-CMalloc CHRISARG Allocates buffers using C's malloc 2024-12-02T03:33:50
Temperature-Calculate-DegreeDays AALLGOOD Perl package to compute cooling, heating, and growing degree days 2024-12-03T20:23:00
Test-SpellCheck PLICEASE Check spelling of POD and other documents 2024-12-29T15:22:23
Test-SpellCheck-Plugin-Lang-EN-US PLICEASE US English language dictionary for Test::SpellCheck 2024-12-29T15:25:31
Text-Table-Boxed JIMAVERA Automate separators and rules for Text::Table 2024-12-12T01:46:12
Tie-Hash-DataSection PLICEASE Access __DATA__ section via tied hash 2024-12-24T05:56:04
Time-RTM CADE Run-time metrics stats 2024-12-01T23:49:06
UserPassManagerForWindows CEEJAY User Pass Manager For Windows 2024-12-13T15:39:41
WebService-Chroma LNATION chromadb client 2024-12-16T20:45:59
Webservice-Sendy-API OODLER Sendy's integration API Perl client and commandline utility 2024-12-29T21:28:13
YAGL RLOVELAND Yet Another Graph Library 2024-12-08T23:12:44
blib-tiny PLICEASE Like blib but lighter 2024-12-22T23:29:29

Stats

Number of new CPAN distributions this period: 76

Number of authors releasing new CPAN distributions this period: 33

Authors by number of new CPAN distributions this period:

No Author Distributions
1 PLICEASE 11
2 JANESKIL 9
3 ETJ 9
4 PERLANCAR 8
5 STIGTSP 3
6 CONTRA 3
7 AALLGOOD 2
8 SSMN 2
9 LNATION 2
10 MJOHNSON 2
11 MANWAR 2
12 CEEJAY 2
13 CHENGYU 1
14 GUL 1
15 OODLER 1
16 GWS 1
17 CADE 1
18 TIMLEGGE 1
19 DAVIDRAAB 1
20 YTURTLE 1
21 JIMAVERA 1
22 HKOBA 1
23 YUPEN 1
24 RRWO 1
25 CHRISARG 1
26 SGRAY 1
27 OLOOEEZ 1
28 SANKO 1
29 SMONFF 1
30 SMSAERO 1
31 RLOVELAND 1
32 SKIM 1
33 AJNN 1

Add a security policy to your distributions

blogs.perl.org

Published by Robert Rothenberg on Sunday 05 January 2025 22:31

Adding a SECURITY or SECURITY.md file to your Perl distributions will let people know:

  1. How to contact the maintainers if they find a security issue with your software
  2. What software will be supported for security issues

The contact point is very important for modules that have been around for a long time and have had several authors over the years. When there is a long list of maintainers, it's not clear who to contact.

You don't want people reporting security vulnerabilities in public on the RT or GitHub issues for your project, nor do you want a post on IRC, Reddit or social media about it.

If your software is on GitHub, you can set up private vulnerability reporting. GitLab has a similar system.

Otherwise, a single email address is acceptable. An alias that forwards to all of the maintainers or at the very least, a single maintainer who has agreed to that role will work.

It's also important to realise as a maintainer that you are not on your own when you receive a vulnerability report. You are welcome and even encouraged to reach out to CPANSec for assistance triaging and fixing the issue, as well as handling notifications and reporting.

The supported software version may seem obvious, but it's important to spell out: will you be updating only the latest version? What versions of Perl will you support? If your module uses or embeds other libraries, how will they be supported?

Fortunately it is not difficult to write a security policy. The CPAN Security Group (CPANSec) has written Guidelines for Adding a Security Policy to Perl Distributions. (Note: I am one of the authors of that document.)

The guidelines include a template for a Perl distribution with a single author that you can use as a basis for your distributions. There is also Software::Security::Policy that will be integrated with build tools in the future to help generate one.

We'd like more people to use the document and provide feedback to CPANSec to improve the advice, and perhaps add alternative templates.

You don't even have to release a new version of your modules immediately. Just adding a SECURITY.md file in the root of the GitHub repo will be helpful enough.

Note: edited for typos.

Add a security policy to your distributions

CPAN Security Group

Published by Robert Rothenberg on Sunday 05 January 2025 17:15

Adding a SECURITY or SECURITY.md file to your Perl distributions will let people know:

  1. How to contact the maintainers if they find a security issue with your software
  2. What software will be supported for security issues

The contact point is very important for modules that have been around for a long time and have had several authors over the years. When there is a long list of maintainers, it’s not clear who to contact.

You don’t want people reporting security vulnerabilities in public on the RT or GitHub issues for your project, nor do you want a post on IRC, Reddit or social media about it.

If your software is on GitHub, you can set up private vulnerability reporting. GitLab has a similar system.

Otherwise, a single email address is acceptable. An alias that forwards to all of the maintainers or at the very least, a single maintainer who has agreed to that role will work.

It’s also important to realise as a maintainer that you are not on your own when you receive a vulnerability report. You are welcome and even encouraged to reach out to CPANSec for assistance triaging and fixing the issue, as well as handling notifications and reporting.

The supported software version may seem obvious, but it’s important to spell out: will you be updating only the latest version? What versions of Perl will you support? If your module uses or embeds other libraries, how will they be supported?

Fortunately it is not difficult to write a security policy. The CPAN Security Group (CPANSec) has written Guidelines for Adding a Security Policy to Perl Distributions. (Note: I am one of the authors of that document.)

The guidelines include a template for a Perl distribution with a single author that you can use as a basis for your distributions. There is also Software::Security::Policy that will be integrated with build tools in the future to help generate one.

We’d like more people to use the document and provide feedback to CPANSec to improve the advice, and perhaps add alternative templates.

You don’t even have to release a new version of your modules immediately. Just adding a SECURITY.md file in the root of the GitHub repo will be helpful enough.

This was originally posted on blogs.perl.org.

(dxxix) 20 great CPAN modules released last week

Niceperl

Published by Unknown on Saturday 04 January 2025 22:56

Updates for great CPAN modules released last week. A module is considered great if its favorites count is greater or equal than 12.

  1. App::Ack - A grep-like program for searching source code
    • Version: v3.8.1 on 2025-01-01, with 131 votes
    • Previous CPAN version: v3.8.0 was 11 days before
    • Author: PETDANCE
  2. App::Cmd - write command line apps with less suffering
    • Version: 0.337 on 2024-12-30, with 49 votes
    • Previous CPAN version: 0.336 was 1 year, 4 months, 4 days before
    • Author: RJBS
  3. App::Netdisco - An open source web-based network management tool.
    • Version: 2.081003 on 2024-12-31, with 17 votes
    • Previous CPAN version: 2.080003 was 2 months, 1 day before
    • Author: OLIVER
  4. CPAN::Audit - Audit CPAN distributions for known vulnerabilities
    • Version: 20250103.001 on 2025-01-04, with 14 votes
    • Previous CPAN version: 20241208.001 was 27 days before
    • Author: BRIANDFOY
  5. DateTime::Format::Flexible - DateTime::Format::Flexible - Flexibly parse strings and turn them into DateTime objects.
    • Version: 0.37 on 2024-12-31, with 14 votes
    • Previous CPAN version: 0.36 was 2 months, 14 days before
    • Author: THINC
  6. Getopt::Long::Descriptive - Getopt::Long, but simpler and more powerful
    • Version: 0.116 on 2024-12-30, with 58 votes
    • Previous CPAN version: 0.115 was 1 month, 23 days before
    • Author: RJBS
  7. MCE - Many-Core Engine for Perl providing parallel processing capabilities
    • Version: 1.901 on 2025-01-02, with 108 votes
    • Previous CPAN version: 1.900 was 3 months, 22 days before
    • Author: MARIOROY
  8. MooseX::Getopt - A Moose role for processing command line options
    • Version: 0.78 on 2025-01-03, with 21 votes
    • Previous CPAN version: 0.76 was 1 year, 16 days before
    • Author: ETHER
  9. MooseX::NonMoose - easy subclassing of non-Moose classes
    • Version: 0.27 on 2025-01-03, with 16 votes
    • Previous CPAN version: 0.26 was 10 years, 10 months, 6 days before
    • Author: PLICEASE
  10. Net::SSH::Perl - Perl client Interface to SSH
    • Version: 2.143 on 2025-01-04, with 20 votes
    • Previous CPAN version: 2.142 was 1 year, 4 months, 28 days before
    • Author: BRIANDFOY
  11. PDL - Perl Data Language
    • Version: 2.098 on 2025-01-03, with 57 votes
    • Previous CPAN version: 2.095 was 1 month, 29 days before
    • Author: ETJ
  12. PDL::Stats - a collection of statistics modules in Perl Data Language, with a quick-start guide for non-PDL people.
    • Version: 0.853 on 2025-01-04, with 15 votes
    • Previous CPAN version: 0.852 was 7 days before
    • Author: ETJ
  13. SPVM - The SPVM Language
    • Version: 0.990035 on 2025-01-04, with 34 votes
    • Previous CPAN version: 0.990033 was 18 days before
    • Author: KIMOTO
  14. Test::File - test file attributes
    • Version: 1.994 on 2025-01-03, with 12 votes
    • Previous CPAN version: 1.993 was 2 years, 2 days before
    • Author: BRIANDFOY
  15. Test::Output - Utilities to test STDOUT and STDERR messages.
    • Version: 1.035 on 2025-01-03, with 14 votes
    • Previous CPAN version: 1.034 was 1 year, 5 months, 29 days before
    • Author: BRIANDFOY
  16. Test::Warnings - Test for warnings and the lack of them
    • Version: 0.036 on 2025-01-03, with 18 votes
    • Previous CPAN version: 0.033 was 11 months, 11 days before
    • Author: ETHER
  17. Text::CSV_XS - Comma-Separated Values manipulation routines
    • Version: 1.58 on 2024-12-30, with 102 votes
    • Previous CPAN version: 1.57 was 1 month, 18 days before
    • Author: HMBRAND
  18. TheSchwartz - reliable job queue
    • Version: 1.18 on 2024-12-31, with 14 votes
    • Previous CPAN version: 1.17 was 3 years, 1 day before
    • Author: AKIYM
  19. Unicode::Tussle - Tom's Unicode Scripts So Life is Easier
    • Version: 1.119 on 2025-01-03, with 13 votes
    • Previous CPAN version: 1.115 was 3 years, 23 days before
    • Author: BRIANDFOY
  20. XML::Hash::XS - Simple and fast hash to XML and XML to hash conversion written in C
    • Version: 0.64 on 2025-01-01, with 13 votes
    • Previous CPAN version: 0.62 was 4 days before
    • Author: YOREEK

(dxcvii) metacpan weekly report - Mojolicious

Niceperl

Published by Unknown on Saturday 04 January 2025 22:52

This is the weekly favourites list of CPAN distributions. Votes count: 43

Week's winner: Mojolicious (+2)

Build date: 2025/01/04 21:51:46 GMT


Clicked for first time:


Increasing its reputation:

London Perl Mongers on GitHub Pages

Perl Hacks

Published by Dave Cross on Saturday 04 January 2025 11:19

The London Perl Mongers have had a website for a very long time. Since some time in 1998, I think. At first, I hosted a static site for us. Later on, we bought our own server and hosted it at a friendly company around Silicon Roundabout. But for most of the lifetime of the organisation, it’s been hosted on a server donated to us by Exonetric (for which we are extremely grateful).

But all good things come to an end. And last week, we got an email saying the Exonetric was closing down and we would need to find alternative hosting by the end of February.

The code for the site is on GitHub, so I had a quick look at it to see if there was anything easy we could do.

I was slightly surprised to find it was a PSGI application. Albeit a really simple PSGI application that basically served content from a /root directory, having passed it through some light Template Toolkit processing first. Converting this to a simple static site that could be hosted on GitHub Pages was going to be simple.

Really, all it needed was a ttree configuration file that reads all of the files from /root, processes them and writes the output to /docs. The configuration file I created looked like this:

src = root
dest = docs

copy = \.(gif|png|jpg|pdf|css|js)$
copy = ^CNAME$

recurse

verbose

To be honest, most of the static web site work I do these days uses a static site builder that’s rather more complex than that, so it was really refreshing to remind myself that you can do useful things with tools as simple as ttree.

The next step was to add a GitHub Actions workflow that publishes the site to the GitHub Pages server each time something changes. That’s all pretty standard stuff too:

name: Generate web page

on:
  push:
    branches: 'master'
  workflow_dispatch:

jobs:
  build:
    if: github.repository_owner == 'LondonPM'
    runs-on: ubuntu-latest

    steps:
      - name: Install TT
        run: |
          sudo apt-get update
          sudo apt-get -y install libtemplate-perl

      - name: Checkout
        uses: actions/checkout@v4

      - name: Create pages
        run: ttree -f ttreerc 2>&1 > ttree.log

      - name: Archive ttree logs
        uses: actions/upload-artifact@v4
        with:
          name: ttree.log
          path: ./ttree.log
          retention-days: 3

      - name: Update pages artifact
        uses: actions/upload-pages-artifact@v3
        with:
          path: docs/

  deploy:
    needs: build
      if: github.repository_owner == 'LondonPM'
      permissions:
        pages: write
        id-token: write
      environment:
        name: github-pages
        url: ${{ steps.deployment.outputs.page_url }}
      runs-on: ubuntu-latest
      steps:
        - name: Deploy to GitHub Pages
          id: deployment
          uses: actions/deploy-pages@v4

The only slightly complex lines here are the two lines that say if: github.repository_owner == 'LondonPM'. We’re hoping that other people will fork this repo in order to work on the site, but it’s only the main fork that should attempt to publish the current version on the GitHub Pages servers.

There was a bit of fiddling with DNS. Temporarily, we used the domain londonperl.com as a test deployment (because I’m the kind of person who just happens to have potentially useful domains lying around, unused!) but enough of us are slightly obsessed about using the correct TLD so we’ve settled on londonperl.org[*]. We’ve asked the nice people at the Perl NOC to redirect our old domain to the new one.

And it’s all working (well, with the exception of the redirection of the old domain). Thanks to Sue, Lee and Leo for the work they’ve done in the last few days to get it all working. And a big thanks to Mark and Exonetric for hosting the site for us for the last couple of decades.

These changes are already having the desired effect. People are submitting pull requests to update the website. Our website is probably more up-to-date than it has been for far too long. It’s even responsive now.

I realise there has been very little Perl in this post. But I thought it might be useful for other Perl Mongers groups who are looking for a simple (and free!) space to host their websites. Please let me know if you have any questions about the process.

[*] We wanted to use Cloudflare to manage the domain but their free service only supports top-level domains and london.pm.org (our original domain) is a subdomain – and none of us wanted to pay for the enterprise version.

The post London Perl Mongers on GitHub Pages appeared first on Perl Hacks.

CPAN Author’s Guide to Random Data for Security

CPAN Security Group

Published by Robert Rothenberg on Friday 03 January 2025 15:30

Any secret token that allows someone to access a resource or perform an action should be generated with a secure random number generator. Perl’s built-in rand function is not suitable for this: it is seeded by only 32-bits (4 bytes), and the output can be predicted easily.

There are many modules on CPAN with random number generators. Which ones should you use?

We have added a CPAN Author’s Guide to Random Data for Security. This recommends a few modules that are generaly portable, easy to use and have good defaults.

This week in PSC (174) | 2025-01-02

blogs.perl.org

Published by Perl Steering Council on Thursday 02 January 2025 23:59

Just Aristotle and Graham for our first meeting of the new year. Not much progress since the last one due to Christmas, New Year’s, sickness, and other personal circumstances. We discussed our framing of the version bump, the timeline for a decision, and the fact that constraints push us toward a dummy .0 third version component as the simplest way forward.

[P5P posting of this summary]

Leveraging Perl Frameworks for Seamless API Development

Please keep your information up-to-date

CPAN Security Group

Published by Robert Rothenberg on Tuesday 31 December 2024 11:00

Some end of year reminders for CPAN Authors:

Do all of your modules have up-to-date contact information? If not, please release new versions with an updated email address in the AUTHOR section.

(And while you’re at it, why not add a security policy to your distribution, so that people know how and where to report a security issue with your module.)

If you have a cpan.org email alias, does it forward to the correct email address? (You can edit your email settings in PAUSE.)

And most importantly, if you are taking time away from maintaining Perl modules, please add ADOPTME or NEEDHELP as co-maintainers to mark your modules as available.

Thanks, and best wishes for 2025.

This was originally posted on blogs.perl.org.

TPRC 2025 Papercall

Perl Foundation News

Published by Amber Krawczyk on Sunday 29 December 2024 13:47

The first deadline for the 2025 TPRC papercall is on January 15th! Get those papers in! Go to http://tprc.us for more information!

Why Do We Use Perl Scripts and PARMS in Batch Processing?

Perl on Medium

Published by Kavya on Saturday 28 December 2024 16:27

In corporate IT environments, Perl scripts and PARMS (parameters) play crucial roles in batch processing workflows. They are widely used…

The James Webb Space Telescope hangs like a Christmas tree ornament over Africa as it prepares to deploy its mirror and travel to its distant orbit. Image credit: NASA/ESA 25/Dec/2021.

PDL and the James Webb Space Telescope (broadcasting and dimension tricks)

I am an astronomer who has for 30 years used PDL for processing of astronomical data. (In fact this is one of the reasons I created it :-) see 'The Beginnings of PDL').

Continue reading...

Tags: broadcasting image processing spectra data reduction

What's new on CPAN - November 2024

perl.com

Published on Tuesday 24 December 2024 02:24

Welcome to “What’s new on CPAN”, a curated look at last month’s new CPAN uploads for your reading and programming pleasure. Enjoy!

APIs & Apps

Config & Devops

Data

  • Annotate data by defining rule chains with Data::Annotation (POLETTIX). See it in action in Mail::Colander (POLETTIX) to manage e-mail messages
  • Data::FastPack (DRCLAW) lets you encode/decode the FastPack data format “for storing records of opaque data related to a time index into a padded stream”
  • A couple of specialized iterator modules. Iterate over:
    • a hash with Hash::Iter (PERLANCAR)
    • a string, one or more characters at a time, with Str::Iter (PERLANCAR)
  • Recursively archive a directory to either a file or memory with Archive::Libarchive::Compress (PLICEASE)
  • Random::Simple (BAKERSCOT) will automatically upgrade/override the core rand() function to use the PCG pseudorandom number generator

Development & Version Control

Science & Mathematics

Web

Other

Merry Christmas, bless us, everyone

Perl Advent Calendar 2024

Published by Mark Fowler on Tuesday 24 December 2024 00:00

Merry Christmas, one and all.

A quarter of a century (and, obviously, twenty five days) ago I created the very first Perl Advent Calendar entry. This Christmas, I'd like to take a minute to talk about all the wonderful presents this has given us over the years.

Over this time the world has changed, and Perl's role in the world with it. Twenty five years ago was the dawn of the dot-com boom, where we were concerned with the battle between Perl and Python, and the new upstart of Java. Which would be the dominant language? Twenty five years later we can see the fallacy of this debate - all of the languages won. We live in a vastly more complicated world where the Internet is now always on, in our pockets and on our wrists, controlling everything from our light switches to how we interact with our governments. And powering this is a plurality of programming languages, each with its own advantages and disadvantages, quirks and foibles, allowing people to use the best language for the task at hand - Java, or Python, or our beloved Perl - or any number of interesting and exciting language brethren new and old.

With the development of the cloud and cloud technologies the old battle for the server is immaterial. Where we once used to fret over if Perl or Python was installed on "the server" and available for us (and which version!), we now have the ability to easily obtain whatever environment we want to use whichever language we want. Where we used to have to hand install software on the operating system this was supplanted by package systems, then by fleet management systems like ansible and puppet that could reproducibly install and manage any language we wanted across a whole fleet of machines, and then by virtual machine technologies like Amazon's AMI system that can be used to quickly create a "throwaway" machine with whatever machine image we want installed on it.

We now live in the Docker (container) world where each script can have its own version of Perl, with exactly the dependencies it needs installed just for it.

Perl 5

This changing environment has influenced Perl, allowing it to flourish in a way that we never would have imagined twenty five years ago. By making installing software easier we freed ourselves from the concept of the "core" Perl language extending what we could use out into reliably having whatever bits of CPAN we want at hand. This brought the philosophy of "CPAN is the language" to the forefront.

Much of the work on Perl in the last twenty five years has been adapting the core interpreter so that it's possible to modify it more and more by simply installing a module. Where we once begrudgingly relied on source code modifications to blindly manipulate the raw text of the code in order to add brand new language features we now exist in a world of pluggable syntax where such changes can be made in collaboration with perl's own parser giving us (almost) infinite adaptability.

The history of Perl has moved from higher level abstractions being built in large swaths of Perl code to code being made available on the CPAN that can integrate ever closer with the interpreter itself. Now finally in the last few years we've seen some of these experiments being turned into best practices that are built into the language itself.

When I first learned Perl in 1998, I started with the "pink" version of Larry Wall's "Programming Perl" book, which only covered Perl 4 and hence didn't cover the topic of objects at all. This resulted in some of the first Perl 5 code I wrote looking like this:

sub triangle_area {
    my $tri = shift;
    return $tri->{width} * $tri->{height} / 2;
}

my $shape = { width => 3, height => 4 };
print triangle_area($shape), "\n";

My understanding of Perl changed pretty quickly when I started reading the man pages for the version of Perl I had installed and got my hands on the "blue" second edition of "Programming Perl".

Learning Perl 5's object model meant the kind of Perl I would write would be more like this:

use strict;
use warnings;

package Triangle;

sub new {
    my $class = shift;
    my %args = @_;
    my $self = { width => $args{width}, height => $args{height} };
    return bless $self, $class;
}

sub width { return $self->{width} }
sub height { return $self->{height} }

sub area {
    my $self = shift;
    return $self->width * $self->height / 2;
}

package main;
my $shape = Triangle->new(width => 3, height => 4);
print $shape->area(), "\n";

This was so much better. We did't have to name the area method with a triangle_ prefix in order to disambiguate it from the any rectangle_area or circle_area function we might have in our code base.

Then in 2006 along came Moose which enabled a much more powerful way to write objects:

package Triangle;
use Moose;

has width => (is => 'ro');
has height => (is => 'ro');

sub area {
    my $self = shift;
    return $self->width * $self->height / 2;
}

package main;

use strict;
use warnings;

my $shape = Triangle->new(width => 3, height => 4);
print $shape->area(), "\n";

Later, in 2017, we had the first release of Mu which allows us to write something quite a bit shorter:

package Triangle;
use Mu;
ro 'width';
ro 'height';

sub area {
    my $self = shift;
    return $self->width * $self->height / 2;
}

package main;

use strict;
use warnings;

my $shape = Triangle->new(width => 3, height => 4);
print $shape->area(), "\n";

This is not only shorter, but it also has more error checking - if you don't pass both width and height to new, you'll get an error.

Last year we had the release of Perl 5.38. This brought into core a bunch of syntax (admirably still experimental) that we started as a community playing with in 2008 with MooseX::Declare - but implemented much better and safer. The code above can now be simplified even further:

use v5.38;
use feature 'class';

class Triangle {
    field $width :param;
    field $height :param;
    method area { return $width * $height / 2 }
}

my $shape = Triangle->new(width => 3, height => 4);
say $shape->area();

The Legacy of Perl

Perl has changed throughout the years, but it's always been Perl, with core ideas that have defined not only the "Perl way" of doing things for Perl, but elsewhere too!

These ideas have infected the way we write code, not just in Perl, but in all modern programming languages. Amazing things that sprung up in Perl have become table stakes in other languages. The idea of having a central repository such as the CPAN that is the defacto place where you can find open source libraries that can be easily installed have become the norm - just look at JavaScript's ever popular npm, Python's PyPI, and Ruby's RubyGems as examples. The concept of shipping these libraries with working tests like everything on the CPAN has been adopted everywhere, with CI/CD systems validating any serious software dependency on any commit.

These aspects of Perl - along with countless other things - means that twenty five years on not only can I still enjoy writing Perl code in more powerful and fun ways than I ever could, but when I need to use another language better suited to a particular niche, a lot of the things I loved about Perl twenty five years ago are already there waiting for me.

The Advent Calendar Itself

Speaking of things that other languages have adopted...

The story of the Perl Advent Calendar starts, like all good stories, with a bad idea in the pub the night before. I don't eat chocolate, so I was lamenting at a Perl Mongers social meeting that there were no good advent calendars for me - just the ones with a little picture behind the windows. I was saying that you should be able to get some other kind of reward. And then I thought how about some cool code?

So the Perl Advent Calendar was born. Or it was the very next day, when I put the whole thing together during my lunch break. Back then I just named a module for the day and included the module's POD as the advent calendar - next year I introduced a small description of why I'd picked it along with the POD, and the year after is when the full article format was introduced with links to search.cpan.org (and later metacpan) for the documentation.

This turned out to be surprisingly popular, with the website being featured in NTK and on Slashdot (getting mentioned by Slashdot was a big deal in 1999).

It wasn't long before there were imitators for other programming languages. It became a tradition in the software world to have an Advent Calendar for your language of choice (or area of programming language - Perl has seen quite a few separate calendars for things like Perl 6, Catalyst, and even futures and promises). We now even have the Advent of Code which is a small advent calendar of programming puzzles that's hugely popular (I, for my part, have never had time to do it since I was always spending time tweaking the Perl Advent Calendar at this time of year).

Through the years the Advent Calendar became too much for me to manage on my own. I could no longer keep writing all twenty five articles myself, and so I started taking submissions. I eventually gave the calendar away for others to maintain, took it back again years later, and then finally gave it away again. Like any good project, it's totally grown beyond me and has a life of its own.

The crucial thing about the calendar - more important than any one article, any one year, or even any one programming language - is the idea that we can all enjoy learning about our favorite programming language. Things don't have to be taught in boring instructions, but instead learning about something can be silly, daft, fun, and a treat! Why not have a story about how Santa's elves are all Perl programmers faced with saving Christmas, and the only way to do it is to use this module? Why not have a tale about how we can control Christmas lights with Perl? Create Christmas memes? Many a clever person in the Perl community has talked about optimizing projects for fun - attracting volunteers by making projects enjoyable to be a part of - and the Perl Advent Calendar embraces this idea of rewarding everyone that reads it with joy. This popular format has been copied by other languages.

A Merry Christmas to us all; Bless us, everyone

So, as I try to do every year, and on this twenty-fifth year of the Perl Advent Calendar, I wish you a Merry Christmas.

Perl has this concept of "blessing" references to turn them into objects. One way to look at it is it's Perl's way of making something more than what it is - improving it, giving it powers and abilities it didn't have before.

So when I say "Bless us, everyone" I'd like you to think about how Perl has "bless"ed everyone. Each programming language that has their own version of CPAN. Each programming language that has their own Advent Calendar. Everyone who's written something daft just for the heck of it, and then shared it so people can learn. These are all things that Perl has helped bring to the world, and means that - even if you've never used Perl - you're still a sort of Perl programmer. Because Perl is more than a language, a run-time - it's about the people and ideas behind it.

merry $christmas; bless $us, Everyone

Day 24: Perl Data Language reflections

PDL Advent calendar 2024

Published on Tuesday 24 December 2024 00:00

PDL is great to use. The community is pretty great, too!

Continue reading...

Tags: community API

A New Logo for Perl

Perl Advent Calendar 2024

Published by Olaf Alders on Monday 23 December 2024 00:00

The Backstory (2020)

For many years, the question of what is or is not Perl's logo has been quite murky. There is a fair amount of backstory and there is too much to dive into right here, but I will happily point you at Neil Bowers' tackling of the subject from 4 years ago: https://neilb.org/2020/12/04/perl-and-camels.html It's a quick, but informative read. I encourage you to take a peek.

The TL;DR of it all is that Neil suggested:

  • that Perl could adopt a new camel logo—separate from the one used on O'Reilly's book cover—and use it as the official symbol for the Perl language.
  • the goal would be to create a logo that represents not just the language but also the community, one that feels friendly and welcoming.
  • He acknowledged that the "camel association" will always be tied to Perl, even if a new logo is chosen, but suggested this as a pragmatic approach

The Perl Toolchain Summit (2024)

At the Perl Toolchain Summit in Lisbon this year, a small group of us had a chat about the logo (or non-logo) situation. The majority opinion was that someone should come up with a logo and present it for community use. Neil Bowers and I were nominated to take this on. Over the summer, Neil commissioned Zach Roszczewski to come up with a new camel. Babs Veloso, Neil and I gave some initial feedback. After we were happy that we could proceed, we widened the circle of participants to a small, shadowy cabal, chatting on TPRF Slack. Among these were Sébastien Feugère and Thibault Duponchelle, who had previous wrestled with the logo topic. Later, I participated in a call with the PSC, where they gave some feedback on the logo. When I was at the London Perl and Raku Workshop this past October, Sébastien, Thibault, Leo Lapworth and I got in a room together to discuss a path forward. We aimed to have a logo available for announcement as part of the Perl Advent Calendar, and here we are.

Over the past week, we have polled various others for opinions on the logo and various versions of it. The result of all of this is the logo you see at the top of this article.

Feedback on Sébastien Feugère's work was kindly given (in first name alphabetical order) by:

  • Aristotle Pagaltzis
  • Bruno Meneguele
  • D Ruth Holloway
  • Dallas Hogan
  • Graham Knop
  • Kenta Kobayashi
  • Leo Lapworth
  • Makoto Nozaki
  • Marc Perry
  • Mohammad Anwar
  • Philippe Bruhat
  • Robert Spier
  • Thibault Duponchelle

The License

The license for this logo is CC-BY. That means that you are free to create derivative works based on the logo, with the only condition being attribution. We would love for this logo to be used widely, so we wanted to go with a permissive license.

Who Put You in Charge?

Nobody. In the absence of a benevolent dictator or a governing body for all of the Perl communities, nobody has a mandate to create a logo for the Perl language and all of the communities attached to it. Our only hope is that this logo is seen as a gift and that if you like it, you will use it.

Traditionally the way that things work in our communities is that someone creates something in the hopes that it will be adopted by others. That may or may not happen, but the end result is entirely up to the various Perl communities. We hope that you like this logo. We hope that you use it. We are happy to work with you on using it, but we are not in charge of anything and it would be disingenuous to pretend it were otherwise.

What About The Perl and Raku Foundation?

This logo is not affiliated with The Perl and Raku Foundation in any way. The foundation has its own logo (the onion), which can also be used under certain conditions. As far as I can tell, there is no appetite within the foundation to wade into the Perl logo debate. Having said that, an onion is not a camel, and I refer you to Neil's blog post quoted above for an argument about why the logo really should just be a camel.

The logo currently lives in the metacpan/perl-assets repository. The repo is still a work in progress, but this is where you should be able to find static assets moving forward.

Where Can I Give Feedback?

Please open an issue if there's something you'd like to discuss. Items worth discussing are:

  • minor changes to the logo layout and look
  • general issues related to using the logo
  • offers of help

Items not currently worth discussing:

  • this should be something other than a camel
  • this requires a ground up redesign
  • I hate it

Are There Other Options?

Yes, we would like you to have many different options when it comes to using the camel. I'm including some of them below.

Neil Bowers was the initial owner of the new camel. He has transferred the ownership of the original camel artwork to me. My preference would be to transfer ownership to MetaCPAN, but it's not a legal entity, so I'm not entirely sure if that is possible. Since the license is CC-BY, I don't actually know how much ownership matters, but for the time being, I am the camel's steward.

What's Next?

We consider the logo to be production ready, but also a work in progress. We are in the process of approaching stakeholders and speaking to them about integrating the logo. In addition this, I expect the logo to be used in some way on both perl.com and metacpan.org.

There are still some assets which need to be settled -- like a favicon.ico, but if all goes well that should be taken care of in the very near future.

It is my hope that the various Perl communities can standardize on this logo in the near term. This doesn't have to be the forever logo for Perl, but just generally getting people on the same page would be an excellent start.

If you think this logo is a good fit, please accept it as our gift to you. If it's not a good fit for you, that's ok too. TIMTOWTDI!

If you are generating truly random numbers for esoteric distributions, you need PDL!

Continue reading...

Tags: Inverse CDF random numbers performance

Maintaining Perl 5 Core (Dave Mitchell): November 2024

Perl Foundation News

Published by alh on Sunday 22 December 2024 09:34


Dave writes:

This is my monthly report on work done during November 2024 covered by my TPF perl core maintenance grant.

I spent most of last month continuing to do various bits of code refactoring and test-adding on Extutils::ParseXS, as a precursor to adding reference-counted stack (PERL_RC_STACK) abilities to XS.

Summary: * 5:09 process p5p mailbox * 39:10 refactor Extutils::ParseXS

Total: * 44:19 TOTAL (HH::MM)

Maintaining Perl (Tony Cook) October 2024

Perl Foundation News

Published by alh on Sunday 22 December 2024 09:30


Tony writes:

``` [Hours] [Activity] 2024/10/01 Tuesday 1.17 #22547 work on revert, test code, testing, make PR 22635 0.08 #22633 review and approve 0.22 #22634 review and approve 1.17 #22629 review and comments

0.20 #22547 work on more tests

2.84

2024/10/02 Wednesday 0.23 #22629 review and approve 0.15 github notifications 0.30 #22639 review and comment 0.33 #22638 review and comment 0.50 #22614 check build logs and close

0.82 #22611 review post, review code and comment

2.33

2024/10/03 Thursday 1.27 #22641 review and comment 0.42 #22623 review code, try to work out a fix

1.08 #22623 more work out a fix

2.77

2024/10/08 Tuesday 0.20 #22644 comment 0.22 #22627 comment on how to get pre-processed source 0.10 #22642 comments 0.22 #22643 review discussion, research 2.02 #22644 revert ‘ in names removal, remove deprecation

messages, testing

2.76

2024/10/09 Wednesday 0.28 email to list about scheduled goto into block removal 2.92 #22644 finish up removing deprecation, work on feature guarding 0.32 Paul’s XSUB: research, comment

1.43 #22644 tokenizer updates

4.95

2024/10/10 Thursday 0.23 #22649 review and approve with comment 1.47 #22644 more guarding, test updates

0.90 #22644 testing, test updates

2.60

2024/10/14 Monday 2.15 #22644 feature specific tests 0.75 #22644 fix minor issues, testing, push for CI 1.78 #22647 review up to “ParseXS: refactor: centralise default

arg parsing”

4.68

2024/10/15 Tuesday 0.10 github notifications 1.17 #22644 check CI results, recheck changes and polish 2.25 #22647 more review up to refactor add Node::Sig class

(with side trip looking at the consolidated changes)

3.52

2024/10/16 Wednesday 0.60 github notifications 0.77 #22644 more polish, testing, push for CI 1.18 #22647 more review

2.38 #22647 more review

4.93

2024/10/17 Thursday 0.58 #22609 follow-up comment 0.98 #22647 more review and approve

0.20 #22644 check CI results, open PR 22675

1.76

2024/10/21 Monday 1.65 #22541 follow-up review and comments 0.58 github notifications 0.47 #22653 research and comment 0.48 #22681 review and approve 0.67 #22683 review and comments

0.38 #22682 try to figure out regen test failure

4.23

2024/10/22 Tuesday 0.22 #22530 comment

1.37 #22642 testing and comment

1.59

2024/10/23 Wednesday 0.70 #22683 research and comment 0.30 #22541 review updates and follow-up comment 1.35 cygwin address conflict #22695, open ticket, work on fix, testing, push for CI 0.38 #22588 testing, research and comment 0.12 #22695 check CI results, make PR 22696 0.10 #22690 review and approve 0.20 #22674 review and approve

0.80 #22689 review, research

3.95

2024/10/24 Thursday 0.97 #22696 adjust for comments, testing, force push 0.33 #22683 comment

0.23 review maint-votes, updates

1.53

2024/10/28 Monday 1.23 #22638 long comment 0.33 #22653 comment 0.62 #22530 research, comment

0.35 #22669 review and approve

2.53

2024/10/29 Tuesday 1.37 #22638 review updates 0.32 #22638 more review 0.47 #22641 review, comment 0.65 #22641 more review, comment 0.73 #22710 try to work out cause 0.17 #22696 recheck and apply to blead

0.70 #22683 comment

4.41

2024/10/30 Wednesday 1.57 #22541 review,comments 0.48 #22712 review, brief comment and approve

1.63 p5p list discussion follow-up

3.68

2024/10/31 Thursday 0.22 github notifications 0.30 #22696 checks, comment 1.70 #22638 review, research, comment 1.30 #15861 research and comment 0.55 #15861 follow-up

0.73 #22644 updates for comment

4.80

Which I calculate is 59.86 hours.

Approximately 33 tickets were reviewed or worked on, and 1 patches were applied. ```

use VERSION

Perl Advent Calendar 2024

Published by Philippe Bruhat on Sunday 22 December 2024 00:00

A yearly non-December gift

December is not the only season for gifts. Every year, sometime around the end of May, the Perl 5 Porters gift us with a new version of Perl. Or is it perl?

To quote "What's the difference between "perl" and "Perl"?" in perlfaq1:

"Perl" is the name of the language. Only the "P" is capitalized. The name of the interpreter (the program which runs the Perl script) is "perl" with a lowercase "p".

You may or may not choose to follow this usage. But never write "PERL", because perl is not an acronym.

The version of perl (the interpreter) is what you get when you type perl -v on the command-line:

    $ perl -v
    This is perl 5, version 40, subversion 0 (v5.40.0) built for x86_64-linux-gnu

    Copyright 1987-2024, Larry Wall

    Perl may be copied only under the terms of either the Artistic License or the
    GNU General Public License, which may be found in the Perl 5 source kit.

    Complete documentation for Perl, including FAQ lists, should be found on
    this system using "man perl" or "perldoc perl".  If you have access to the
    Internet, point your browser at https://www.perl.org/, the Perl Home Page.

You can also run this (the interpreter version is available in two different formats, either as a floating-point number, or a v-string):

    $ perl -E 'say for $], $^V'
    5.040000
    v5.40.0

What's in the box? New features!

New versions of Perl come with bug fixes, speed improvements, deprecations and also new features. It's still the same old Perl, that will continue to run your existing code. Perl version upgrades are so simple and drama-less they're almost boring. (The Perl 5 Porters support the two most recent stable releases of Perl, which should be reason enough to upgrade your binary.)

Long story short, Perl is extremely backwards compatible. This means that sensibly-written code from 20 years ago should still run under the next release of Perl. In other words, any perl interpreter should understand code written against older versions of the Perl language just fine. As I have personally experimented, this actually even applies to scripts targeting version 4 of the language!

With such a strong commitment to backwards compatibility, how does one even introduce new features to the language? To quote from "DESCRIPTION" in feature:

It is usually impossible to add new syntax to Perl without breaking some existing programs. This pragma provides a way to minimize that risk.

The feature module was introduced in Perl v5.10, to make it possible to introduce new features to the language without breaking existing scripts. A typical example would be the say feature, which makes it possible to add the say keyword to the language without breaking older scripts that might have defined a sub say.

If one wanted to use the say builtin, they would write:

use feature 'say';
say "Hello, world!";

And of course, code that already has a say subroutine defined would continue to work the same, as long as the feature is not enabled. This leaves time for the code's author to look at their code and decide if they want to update it to take advantage of new features of the language.

Note that enabling features always happens in the current lexical scope.

The gift of choice

Backwards-compatibility is preserved thanks to a compromise: people have to opt in to the new features. The unfortunate side-effect is that Perl will continue to look the same (sometimes giving the feeling it's stagnating) until you enable the new features!

It should be noted, however, that not all Perl features are guarded by the feature module. Syntax constructs that were syntax errors in previous versions of Perl can be introduced without a guard, and many were. The Syntax::Construct module has an exhaustive list of "syntactic constructs that are not implemented via the feature pragma, but are still not compatible with older versions of Perl".

Perl v5.40 knows about 25 features. While they can be enabled or disabled (some features are used to disable undesirable constructs, like indirect object notation) one by one, there is a better way than 25 lines of boilerplate.

use VERSION

A special case of the use builtin is use VERSION. It performs several operations:

Enforce running with a minimum version of the perl binary

The first thing that use VERSION does is to declare which minimum version of perl (the interpreter) you expect to run your code. If you demand a version later than that of the perl binary currently running your code, it's going to die at compile time.

    $ perl -Mv5.38 -e1
    Perl v5.38.0 required--this is only v5.36.0, stopped.
    BEGIN failed--compilation aborted.

Although the version in use VERSION can be written in either v-string style (v5.36) or numeric style (5.036), it is strongly recommended to use the former, as it's more readable and matches with the way people talk about Perl versions. (Unless the code is expected to actually be run on a perl older than v5.8, which was released in 2002).

Load the corresponding feature bundle

The feature module also defines "feature bundles", which allows to load (or disable) multiple features together. (See "FEATURE-BUNDLES" in feature for their definitions.)

The special use VERSION construct will implicitly load the corresponding feature bundle. For example:

use v5.10;

will implicitly load the corresponding feature bundle:

use feature ':5.10';

which will enable the say, state and switch features. The parser will now understand the corresponding keywords, and behave accordingly. Error messages might differ a lot when a feature is enabled or not.

Note that adding a subversion (e.g. use v5.36.3) will have no effect on the bundles loaded (feature bundles are guaranteed to be the same for all sub-versions). It will of course have an effect on the interpreter version check described above.

In addition to the implicit loading of features, use v5.12 or greater will enable strict, use v5.36 will enable warnings and use v5.40 will import builtin functions (using a similar version bundle scheme: see "Version-Bundles" in builtin).

Note that use VERSION is a lexical pragma, meaning that you could declare different version bundles for different parts of your code. For consistency, it's really recommended that you pick one version, and stick with it for the entire file. In fact, a future release of perl will disallow changing the version once one has been declared. So, really, don't do that.

The features included in bundles fall in two broad categories: new features, and deprecated features. Loading a bundle will perform the following two operations in a single line of code:

Enable modern Perl features

Before features become part of the "official" language, they are often introduced as experiments. Experimental features are available only when requested via use feature, and aren't part of a bundle. In fact, they'll even issue warnings when you use them. (See experimental for more about this.)

For example, the signatures feature was introduced in perl v5.20, and remained experimental until v5.34. That meant that, as long as the perl binary was more recent than v5.20, one could use signatures in their code with use feature 'signatures'. That specific feature has been added to all bundles since :5.36, which means that a single declaration (use v5.36, or any later version) allows one to write Perl subroutines using signatures.

Not all new features have to wait that long to become part of the language: module_true was introduced in perl v5.38, and was immediately added to the :5.38 feature bundle.

Deprecate discouraged features

Bundles have also been used to disable features that have become discouraged. These are made part of the :default feature bundle, and not included in later bundles.

Doing it this way makes it possible to preserve the behaviour of ancient, unmaintained scripts and modules. Even if they load some feature bundle (via use VERSION), any discouraged feature they might use will also be (retroactively) included in that bundle, preserving backward compatibitlity.

This is how the features indirect, multidimensional and bareword_filehandles came to be "removed" from later versions of Perl.

This is the strategy the Perl Steering Council has chosen to best stretch the language between the continuous introduction of new features and the preservation of backwards compatibility. For the record, many Perl 4 (which is functionally identical to Perl 3, from late 1989) scripts still run fine with perl v5.40.

Why pick a Perl version?

Line 0 semantics

When perl compiles Perl code, before it even reads the first byte of source code, it is in "Perl v5.8 compatibility mode". The :default bundle is implicitly loaded (it only contains features that are backward-compatible with traditional Perl).

This means that the "sensibly-written code from 20 years ago" mentioned above is very likely to just run unmodified, and simply work.

As explained above, unguarded syntactic features are available from line 0.

Line 1 semantics

We've seen that use VERSION automatically loads the corresponding feature bundle (and associated builtins). This single line of code enables all official features and disables all deprecated features for the given version of the Perl language.

In other words, putting a use VERSION line at the top (line 1) of a Perl script or module declares which version of the Perl language the code that follows is written under. And because the effect is lexical, a script can load other modules that declare they were written against a different version of the language, and everything works transparently.

I strongly believe that use VERSION should be the first line of any Perl code.

Declaring a baseline of the Perl language

For decades, the first recommendation made to Perl beginners and people asking for help on a Perl forum was to add use strict; use warnings at the beginning of their code. This made Perl more helpful, as it would point to likely errors in programming (like undeclared variables or undefined values).

Since Perl v5.36, these two statements are implicitly included via use VERSION. It also enables the official features of that version of the language, and disables the deprecated ones.

Therefore, use VERSION helps define a good baseline for the Perl language, so that the compiler can fully understand the code that follows. It's of course possible to include experimental features, or re-enable deprecated features (the latter is really not recommended), to fine-tune the specific dialect of Perl in which the code is written.

Future versions of perl implicitly promise that they will understand the dialect of Perl declared by use VERSION, and that they will run it to the best of their abilities.

The Once and Future Perl

The new "use strict and warnings"

Since the time of "use strict and warnings" as minimum requirements for decent Perl code, the language has evolved, and brought in more useful features. It also deprecated ancient features that were deemed bad ideas in a modern context (such as the indirect object notation).

Writing use VERSION as the first (active) line of any Perl code will declare to the perl interpreter (and to whoever is reading the code) which version of the Perl language the code that follows is written in.

So, just put a use VERSION line at the top of all your Perl files.

Whenever a new stable version is released (which happens every year towards the end of May), you should at least read the perldelta that accompanies it, and check if you see some new feature you think you'd want to use.

There might exist some compatibility modules that you can use, to get a taste of those new features on a version of perl that doesn't support them natively. They might behave slightly differently, though.

v5.36 (released in May 2022) contains a very good mix of stable features (default strict and warnings, signatures, isa), as well as the removal of deprecated features (indirect, multidimensional).

Most Linux distributions released in 2024 include a version of Perl that will support use v5.36.

Picking which version of Perl to code in

The version of the Perl language you want to use will depend on the context in which the code is run. Private or proprietary code has different constraints than an Open Source project or library distributed on CPAN.

Private or company code is only limited by the version of Perl used internally. It might be the stock perl from the operating system selected by the organization. It might be a perl compiled specifically for that purpose. Internal company or personal code can run on the bleeding edge!

An Open Source project will usually be shipped with or installed on top of common operating systems, and will usually be tied to the version of perl these operating systems package.

The authors of modules distributed via CPAN distributions might want their code run on a broader selection of perl versions.

However, you're unlikely to be able to start writing code with the latest version of the language very quickly:

  • maybe you're stuck with the version released by your OS vendor (but, do you know how easy it is to compile your own Perl?);

  • maybe you compile your own Perl, but it's a core part of your infrastructure, and upgrading takes time; (although the Perl parts are likely to be the easiest ones, given Perl's track record with backward and forward compatibility)

  • maybe you're a CPAN author, and you still want to support older versions of Perl.

Updating your Perl code at your own pace

At work, across all of our tens of thousands of Perl modules, over 30 different VERSION are declared with use VERSION. From v5.1 (someone typoed 5.010 as 5.001) up to v5.36, going through v5.10, v5.18.2 (someone didn't know the sub-version is ignored), v5.24, etc. Many files don't have a use VERSION line (using the Perl flavor of 2002, when our Perl code base was started). The word for this is "legacy".

Since the effect of use VERSION is lexical, it's possible to upgrade the version of the language your code uses one file at a time (or even one scope at a time, but see "Restrictions to use VERSION declarations" in perl5400delta for why you'll probably want to stick with the whole file).

I can confirm it's really nice to be able to first upgrade the Perl binary without changing a single line of code, and then choose which files to upgrade first.

That transition can be difficult, though:

  • v5.28 subtly changed the meaning of |, &, ^ and ~ (the bitwise feature is enabled)

  • v5.36 won't understand $fido = new Camel "Amelia" (the indirect feature is disabled)

  • v5.36 will complain about sub foo ($$) (the signatures feature is enabled, prototypes must be declared as an attribute)

  • v5.38 will complain about open FH, $file (the bareword_filehandles feature is disabled)

Picking exactly which version of the Perl language to use is the actual question one has to answer. And the answer will be different if one is a CPAN author, a hobbyist writing their own tools, an Open Source application developer or a developer for a company's web application or internal tooling. The answer depends on several factors: one of them is the programmer's desire to use recent Perl language features, and another is their expectations regarding the minimum version of the perl binary the code is expected to run on.

Updating your Perl code faster

With tens of thousands of files to potentially update, I didn't imagine for one second that I would do it manually. And even if my colleagues would also help, I knew that upgrading the use VERSION line in their code would make some of them uneasy.

So I wrote a module that would take Perl code, statically analyze it using PPI, and bump the declared version to the requested one, while being extra careful about the issues detailed above (and others). Since that code contained no company secret, I was allowed to open source it.

The code now lives on CPAN as Perl::Version::Bumper. And has improved a lot since my last commit in the company repository. I've actually deleted the code since, and we now depend on the CPAN module.

Here are a few examples of what it does, assuming we want to bump the example code to v5.40:

  • simply bump the version number:

    print "Hello, world!\n";

    becomes:

    use v5.40;
    print "Hello, world!\n";
  • remove compatibility modules that become unnecessary once the corresponding feature is enabled by the bundle:

    use Say::Compat;
    say "Hello, world";

    becomes:

    use v5.40;
    say "Hello, world";
  • remove warnings about experimental signatures, once they come out of experimental:

    use v5.20;
    use feature 'signatures';
    no warnings 'experimental::signatures';

    sub greeting ( $who ) { "Hello, $who!" }
    say greeting "world";

    becomes:

    use v5.40;

    sub greeting ( $who ) { "Hello, $who!" }
    say greeting "world";
  • rewrites prototypes when enabling the signatures feature:

    use v5.10;
    sub greeting ( $ ) { sprintf "Hello, %s!", shift }
    say greeting "world";

    becomes:

    use v5.40;
    sub greeting :prototype( $ ) { sprintf "Hello, %s!", shift }
    say greeting "world";
  • disable features that might cause problems, and add a warning about them:

    use v5.10;
    say "hello, world!" | "@"; # flip the capital bit on the first letter

    becomes:

    use v5.40;

    # IMPORTANT: Please double-check the use of bitwise operators
    # before removing the `no feature 'bitwise';` line below.
    # See manual pages 'feature' (section "The 'bitwise' feature")
    # and 'perlop' (section "Bitwise String Operators") for details.
    no feature 'bitwise';
    say "hello, world!" | "@"; # flip the capital bit on the first letter
  • In safe mode, stop at the last version that compiles (v5.38 disabled the bareword_filehandles feature, turning their use into a compile-time error):

    open FH, 'greeting.txt' or die "Can't open file: $!";
    print FH "Hello, world!\n";

    becomes:

    use v5.36;
    open FH, 'greeting.txt' or die "Can't open file: $!";
    print FH "Hello, world!\n";

Since the module is meant to upgrade older Perl code, I made sure it can run on perl binaries as old as v5.10. And it can use perl5.10.0 to upgrade source code up to v5.40!

The distribution contains a small command-line utility to process many files at a time: perl-version-bump.

It runs in safe mode by default, meaning it will start at the version of the perl used to run it, and decrease the target version number until the generated code compiles, or give up.

If I can suggest some New Year Resolutions for 2025:

  • decide which version of the Perl language you want to code against in your various projects,

  • start consistently adding use VERSION on line 1 of all your Perl files,

  • and bump the existing versions where it makes sense!

Day 22: Clearing the Runway

PDL Advent calendar 2024

Published on Sunday 22 December 2024 00:00

The North Pole Workshop’s logistics department has been busy this year with upgrading the sleigh’s dash-cam with a new more powerful computer. They’ve asked the research and development department if there is anything that can be done with the extra cycles to make the journey safer. After bouncing around a couple ideas, they came up with a plan for an autoland system…but since Santa and the reindeer do not operate in typical environments (such as roofs), this would not be a typical autoland system (which use microwave/radio guidance) so they couldn’t select anything off-the-shelf (and they do know their shelves).

Continue reading...

Tags: image processing computer vision

That Time Perl+OpenMP Saved Christmas

Perl Advent Calendar 2024

Published by oodler on Saturday 21 December 2024 00:00

It was Christmas Eve, and Santa was facing a nightmare. The sleigh’s new GPS system, upgraded for the first time in centuries from following the Star of Bethlehem, was malfunctioning. As Santa checked the screen, the map was a chaotic mess — locations were wrong, some coordinates did not make sense, and the sleigh was heading straight into the mountains instead of over the City of New Orleans!

Santa's CURRENT position read-out indicated he was over the Appalachians at the following coordinates:

  Sleigh Latitude  Sleigh Longitude  Sleigh Altitude (ft)
       38.0000° N        -81.500° W              300

When he should be nearly exactly at,

  Sleigh Latitude  Sleigh Longitude  Sleigh Altitude (ft)
       29.9500° N        -90.070° W              300

"We can't afford this!" Santa shouted. "We’ve got billions of presents to deliver, and the system's down. And I want some gumbo!"

"Santa, we can fix it," Jingles, the lead elf, said with a frantic smile. "We just need more computing power. If we use OpenMP, we can parallelize the calculations and solve this quickly."

Santa stared. “What are you talking about, Jingles? I'm a giant elf, not a Scottish engineer on a television show for nerds!”

“We’ll solve the GPS problem by recalculating the distances to each delivery location. The sleigh’s GPS relies on triangulating data from multiple satellites. Right now, it's too slow to process the data for each location one by one. We can use OpenMP to divide the problem into smaller parts, calculate distances in parallel, and get this fixed fast!”

The data format of the positional satellites consisted of their positions in latitude, longitude, with an altitude; so the computations are necessarily in 3D space, and could contain any number of lines:

  39.2497677581748 -66.1173923826129 29161.8658117126
  -39.9677413540029 -41.3796046007432 23577.9949741844
  82.2366387689737 153.417562140013 20022.1066827945
  -43.4383552881127 -44.5406041422343 28011.9118605715
  14.0767035175103 4.23608833137735 27766.7951824014
  40.8573795733001 162.321349651587 25625.9162363042
  -26.9656081428904 27.0935089406365 23681.3611776769
  70.1644045619636 6.85910122836034 26946.7435635683
  -64.5469805915126 -14.9091572762404 24893.2320145114
  80.875127931392 -109.736894500449 23367.1123572306
  5.62494420727084 -70.3599057022578 24677.4930437516
  -78.594647140356 -69.1886836681495 21775.1041983417
  -20.7093134304093 50.3824566178804 28396.5251214701
  -8.19130244183 28.3379349990834 24113.3081697615
  -62.1626942859846 -165.892484372947 27881.1415552865
  -39.1505435434735 -14.0167682855066 25391.598017652
  -14.701859640773 33.3797684668173 28958.4392020613
  22.7094543766397 28.9295184727116 29847.2350918171
  58.9987788505186 -87.6847921052664 29544.1317147911
  83.6874173858257 -149.058764882263 22417.9224396509
  -8.01336267852399 97.8876777856595 27879.4674084787
  -55.3867650906297 -107.353651427755 21389.9702111095
  -78.8588152992001 -155.558248147836 25430.0402744441
  9.88995820014878 -0.204367766261981 20832.5618074863
  -76.8565255868645 -14.4804333171123 27013.5287117141
  -0.16890065869049 -40.7974093702016 22440.2960018416
  8.56759320194605 14.0242190926548 24229.1350707098
  89.3116725410715 19.3710347706399 28181.9446348641
  ...

The distance formula was computationally expensive, involving square roots and trigonometry. But by using OpenMP, the task could be split into multiple OS threads, each calculating the distance to one satellite at the same time. The results would then be aggregated, and the sleigh's GPS would know exactly where to direct its heading.

The code would parallelize the work by dividing the list of satellites among a number of pthreads using OpenMP's #pragma omp for construct! OpenMP::Simple handles the required #include <omp.h> and makes it easy to query the environment for information, such as OMP_NUM_THREADS.

Jingles quickly typed up a solution in Perl, his favorite programming language. The solution was simple but critically offloaded the triangulation computations to Inline::C code containing OpenMP directives, using the OpenMP module on CPAN.

use strict;
use warnings;

use OpenMP;

use Inline (
    C => 'DATA',
    with => qw/OpenMP::Simple/,
);

my $omp = OpenMP->new;

$omp->env->omp_num_threads($ENV{OMP_NUM_THREADS} // 8); # accept number of threads via commandline

# Sleigh's CURRENT position (latitude, longitude, altitude)
my $sleigh_lat = 38.0000;
my $sleigh_lon = -81.500;
my $sleigh_alt = 300.0; # in meters

# Satellite positions in tab-delimited format
my @satellites = ();
open my $FH, "<", "./satellite-data.txt" || die $!;

foreach my $line (<$FH>) {
  chomp $line;
  push @satellites, [split(/[\s\t]+/, $line)];
}

# Function to calculate distance from sleigh to each satellite using OpenMP::Simple,
# a subclass of Inline::C!
my $distances = calculate_distances($sleigh_lat, $sleigh_lon, $sleigh_alt, \@satellites);

# Print the calculated distances
foreach my $distance (@$distances) {
    print "Distance: $distance meters\n";
}

Santa watched as Jingles split up the computational load. Each satellite’s data was handled in parallel by different threads, and within seconds, the recalculations were done. The GPS latency issues were fixed. Jingles already had some thoughts of improvements he could make using OpenMP's ability to target GPUs directly, but was quite happy with the current resolution.

Just as the final calculations finished, a gentle voice spoke, “When Faith sanctifies morally neutral technology, Good things are possible at Internet scale.”

Santa turned to see the Holy Family - Baby Jesus in the arms of His Virgin Mother accompanied by His foster father, Joseph; by the sleigh, smiling serenely. “Thank you,” Santa whispered. “Merry Christmas.”

With the sleigh back on track, Santa soared into the night sky.

When things settled down, Santa was able to look at Jingles' full code, and it was something to behold!

use strict;
use warnings;

use OpenMP;

use Inline (
    C => 'DATA',
    with => qw/OpenMP::Simple/,
);

my $omp = OpenMP->new;

$omp->env->omp_num_threads($ARGV[0] // 8); # accept number of threads via commandline

# Sleigh's CURRENT position (latitude, longitude, altitude)
my $sleigh_lat = 38.0000;
my $sleigh_lon = -81.500;
my $sleigh_alt = 300.0; # in meters

# Satellite positions in tab-delimited format
my @satellites = ();
open my $FH, "<", "./satellite-data.txt" || die $!;

foreach my $line (<$FH>) {
  chomp $line;
  push @satellites, [split(/[\s\t]+/, $line)];
}

# Function to calculate distance from sleigh to each satellite using Inline::C
my $distances = calculate_distances($sleigh_lat, $sleigh_lon, $sleigh_alt, \@satellites);

# Print the calculated distances
foreach my $distance (@$distances) {
    print "Distance: $distance meters\n";
}

__DATA__
__C__

#include <math.h>

// Function to convert geographic coordinates to Cartesian (x, y, z)
void geo_to_cartesian(double lat, double lon, double alt, double *x, double *y, double *z) {
  double R = 6371000; // Earth's radius in meters
  double lat_rad = lat * M_PI / 180.0;
  double lon_rad = lon * M_PI / 180.0;

  *x = (R + alt) * cos(lat_rad) * cos(lon_rad);
  *y = (R + alt) * cos(lat_rad) * sin(lon_rad);
  *z = (R + alt) * sin(lat_rad);
}

// Function to calculate Euclidean distance between two points (x1, y1, z1) and (x2, y2, z2)
double calculate_distance(double x1, double y1, double z1, double x2, double y2, double z2) {
  return sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2) + pow(z2 - z1, 2));
}

/* C function parallelized with OpenMP */

// Main function to calculate the distances from the sleigh to each satellite
AV* calculate_distances(double sleigh_lat, double sleigh_lon, double sleigh_alt, AV *satellites) {
    int satellite_count = av_len(satellites) + 1; // The number of satellites
    AV* distances = newAV(); // Create a new Perl array (AV) to hold the distances

    double sleigh_x, sleigh_y, sleigh_z;

    // Convert sleigh's geographic coordinates to Cartesian coordinates
    geo_to_cartesian(sleigh_lat, sleigh_lon, sleigh_alt, &sleigh_x, &sleigh_y, &sleigh_z);

    // Fetch satellite data into local arrays
    double *sat_latitudes = malloc(satellite_count * sizeof(double));
    double *sat_longitudes = malloc(satellite_count * sizeof(double));
    double *sat_altitudes = malloc(satellite_count * sizeof(double));

    // Populate satellite data into local arrays (from the Perl array)
    for (int i = 0; i < satellite_count; i++) {
      AV *satellite = (AV*) SvRV(*av_fetch(satellites, i, 0)); // Fetch the satellite at index i
      sat_latitudes[i] = ((double) SvNV(*av_fetch(satellite, 0, 0))); // Latitude
      sat_longitudes[i] = ((double) SvNV(*av_fetch(satellite, 1, 0))); // Longitude
      sat_altitudes[i] = ((double) SvNV(*av_fetch(satellite, 2, 0))); // Altitude
    }

    // Declare a temporary array to hold distances for each thread
    double *_distances = malloc(satellite_count * sizeof(double));

    PerlOMP_GETENV_BASIC // read common environmental variables, provided by OpenMP::Simple

    // Start parallel region
    #pragma omp parallel shared(_distances)
    {
      // Parallel for loop to compute distances in parallel
      #pragma omp for
      for (int i = 0; i < satellite_count; i++) {
          _distances[i] = 0.0; // Initialize

          double sat_x, sat_y, sat_z;

          // Convert satellite's geographic coordinates to Cartesian coordinates
          geo_to_cartesian(sat_latitudes[i], sat_longitudes[i], sat_altitudes[i], &sat_x, &sat_y, &sat_z);

          // Calculate the distance from the sleigh to this satellite
          _distances[i] = calculate_distance(sleigh_x, sleigh_y, sleigh_z, sat_x, sat_y, sat_z);
      }
    }

    // Combine the results from all threads into the main distances array inside the parallel region
    for (int i = 0; i < satellite_count; i++) {
      av_push(distances, newSVnv(_distances[i]));
    }

    // Free the private distance arrays and satellite data arrays
    free(_distances);
    free(sat_latitudes);
    free(sat_longitudes);
    free(sat_altitudes);

    // Return the AV containing the distances to Perl
    return distances;
}

__END__

See More:

https://metacpan.org/pod/OpenMP
https://metacpan.org/pod/OpenMP::Simple
https://metacpan.org/pod/OpenMP::Environment
Everyone is welcome to join the Perl+OpenMP Project at https://github.com/Perl-OpenMP/!

Day 21: Fun and Games with Images

PDL Advent calendar 2024

Published on Saturday 21 December 2024 00:00

If you are manipulating images, you need PDL!

For years, I've had this urge to use PDL to take a bitmap image and trace the outlines to make an SVG file that I could scale up to A0 poster size without the resulting pixelation. Yes, there are already tools that do that, but where's the fun in that? It's Christmas, the time for Fun and Games!

Continue reading...

Tags: image processing broadcasting