Special variable ${^LAST_SUCCESSFUL_PATTERN} in Perl v5.38
Please checkout for more information in the post below:
https://theweeklychallenge.org/blog/perl-regex
Environment variable PERL_RAND_SEED in Perl v5.38
Please checkout the post for more information:
https://theweeklychallenge.org/blog/random-in-perl
Published by Abigail Rivers on Tuesday 25 March 2025 12:10
Published by U. Windl on Tuesday 25 March 2025 11:32
I wrote some simple perl script that creates an Net::LDAP::LDIF
object on an input file and then reads the contents using $ldif->read_entry()
.
After some processing I'm writing the entries again to STDOUT
using $ldif->write_entry($entry)
.
The code works fine for "normal" LDIF files, but when processing an LDIF file that contains include
, it fails like this:
First line of LDIF entry does not begin with "dn:" at
...
Is there a way "pass though" such include
lines?
An example of such input would be:
dn: cn=schema,cn=config
objectClass: olcSchemaConfig
cn: schema
include: file:///etc/openldap/schema/core.ldif
include: file:///etc/openldap/schema/cosine.ldif
Such include files would contain DNs themselves, like this:
dn: cn=core,cn=schema,cn=config
objectClass: olcSchemaConfig
cn: core
#...
The module version I'm using is perl-ldap-0.65-1.3.1.x86_64
(perl 5.26), just in case.
Published by /u/briandfoy on Tuesday 25 March 2025 11:31
Published by mauke on Monday 24 March 2025 21:14
Porting/release_managers_guide.pod: use more neutral tag message The tag message is just an example, but most releases aren't .0 versions, so "first release!" doesn't generalize well for release engineers looking for guidance. (Also, update the sample output to match the new tag example.)
Published by Powermaster Prime on Monday 24 March 2025 20:25
I was looking everywhere on how to make and display a QR Code for our 2FA in our Perl based web application.
Every example I found was not usable or applicable for my use case, and quite frankly I hate asking questions on here due to the community attitude.
My use case was to generate a 2FA QR Code based on an encrypted otpauth path that could be scanned by Google Authenticator or Microsoft Authenticator. That QR code would be generated and returned via my ajax call as a temporary image in browser memory, NOT server side.
Below is the answer as simplified as I can make it. If you have any questions, feel free to ask.
Published by v4169sgr on Monday 24 March 2025 13:59
For my sins, I run a legacy Perl 5.24 install on which I have built an app of 15 years standing. Recently I have discovered that my Microsoft Outlook integration needed to send scheduled emails breaks on Windows boxes with 64 bit Office installs, while it runs fine with 32 bit Office installs.
The exact error thrown is:
No type library matching "Microsoft Outlook" found at ../Perl/lib/Mail/Outlook.pm line 111
While there do appear to be plenty of people who've encountered this issue, I do have some constraints which is why their solutions might not apply to my situation. First, I am unfortunately not open to upgrading my installation. Given enough time, I'd love to do that but there's never enough time, especially when there are tight deadlines! Second, I do not have the ability to directly manually tinker with the Registry settings on the machines this application must run on, as local admin rights are locked down.
I'm definitely not afraid though of tinkering with the modules. There are no external dependencies I have to satisfy so it is my private playground to hack around as I like with.
How would I go about finding the exact changes needed at the Module level (or even as calls in my code) to address this issue? I've taken a good look around the Meta CPAN site but am none the wiser (all I can see is file permission and version bumps). I still want the application to run with 32 bit Office installs as well as 64 bit Office installs.
Published by /u/tseeling on Monday 24 March 2025 13:39
I was testing some older scripts on a newly installed AIX 7.3 machine with perl 5.38.1 and I noticed something strange.
When being in a directory with test data, and the test data happens to include a usr/lib
directory with libraries the perl
binary also uses then ldd /usr/bin/perl
suddenly shows that perl wants to use the libraries referenced with the relative paths!
I have no idea how this works and why. In my (limited) tests I could not reproduce this on AIX 7.2 with perl 5.28.1.
Is this some behaviour introduced with a perl version > 5.28 or would it rather be AIX-specific? I have no clue how to further investigate.
$ ldd /usr/bin/perl /usr/bin/perl needs: ... usr/lib/libdl.a(shr.o) usr/lib/libcrypt.a(shr.o) ... usr/lib/libpthreads.a(shr_comm.o)
Published by /u/s-ro_mojosa on Monday 24 March 2025 13:11
I seem to recall there was a Perl Lightning Talk a few years back where the speaker was attempting to teach his son (possibly grandson?) Perl. The catch was kiddo didn't understand English. I think he was a native Mandarin speaker, if I'm not mistaken. The talk covers his father's (grandfather's?) efforts to redefine Perl keywords in Chinese characters to ease the learning process.
Does anyone have the YouTube link to this talk? I can't seem to find it anywhere.
Published by /u/briandfoy on Monday 24 March 2025 11:31
Published by Gabor Szabo on Monday 24 March 2025 07:32
Originally published at Perl Weekly 713
Hi there!
Ramadan seems to have a very positive impact on Mohammad Sajid Anwar (manwar), author of The Weekly Challenge and co-editor of The Perl Weekly newsletter. He learns all kinds of new things and writes long blog posts about them. Some of them are Perl related, some are not. Anyway, see the links in this newsletter.
I, on the other hand, was recently contacted by a number of people wanting to migrate from Perl to Rust or Python. My first question is why. After all even if I end up helping them with the move, I need to understand why do they want to move. Because of this I started to have some picture of why people feel the urge to move away from Perl. However, my sample is too small and probably rather biased. None of the people who contacted me wanted to move to Java or C, or NodeJS. That's can be for many reasons, one of them the fact that I don't mention those languages on my LinkedIn profile.
So I'd like to get your help in understanding the central motivations for wanting to move away from Perl. If your company has moved away or is discussing the idea, I'd love to hear from you (a private email would be excellent) to understand the real pain points.
On the other hand, if your company has recently moved to Perl or is planning to do so, I'd love to hear about that too. If they need help I'd be glad to help them too and I am sure people in the Perl community would be thrilled to hear such stories. Even if we can't publish the names of the companies.
Enjoy your week!
--
Your editor: Gabor Szabo.
Listing achievements of the CPANSec group all along 2024.
An interesting direction. As far as I know DEV.to has a feature to automatically create articles from an RSS feed on your blog. So one could write the original on her own blog site and then easily post it on DEV.to as well even setting the canonical_url on DEV to point to the original article.
GitHub Actions meets Map::Tube
Read the article and then comment on Reddit.
END blocks are one of the 'magic' features of Perl. It effectively allows you to execute more code even after exit() was called or even after your program has dieed. Rob has a lot more to say about it.
Generating Perl code using ChatGPT.
Follow the discussion on reddit
No type library matching "Microsoft Outlook" found at ../Perl/lib/Mail/Outlook.pm line 111
Some unicode characters for you: 🐪 🐫 🦙.
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.
Welcome to a new week with a couple of fun tasks "Equal Strings" and "Sort Column". 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.
Enjoy a quick recap of last week's contributions by Team PWC dealing with the "Broken Keys" and "Reverse Letters" tasks in Perl and Raku. You will find plenty of solutions to keep you busy.
Breakdown analysis is something, I always prefer. It helps understand the flow, great work. Keep it up.
Big fan of CPAN. Just love the compact solutions. Very crafty. well done.
Parameter validation in the method signature is one of the coolest feature of Raku language. In this post post, you'll find it used with full liberty. Great work, thanks for sharing.
The detailed analysis that you get to see in the post, truly remarkable. There is nothing left for imagination. Everything is covered, super cool.
What an art of regex, incredible. You need to take a deep breath first before you look at it. Smart hacker, I would say.
Always make you do it at the prompt and not writing bulky script. And when you are comfortable then show you the beast. Great art, keep it up.
I must admit, at times, I start questioning my knowledge. I need to catch up with fellow members. Very impressive work, thanks for sharing knowledge with us.
With regex based solution, I always need explanation otherwise you spend good amount of time to get your head around if it is a complex one. Here you even have DIY tool to test it as well. Great work.
It took me a while to understand the gibberish at the top. The next line explains the mystery, everybody calm down. No one can match the creative mind of team members. Keep it up great work.
I knew, PostScript would make a statement here. Not that I understand what it says, I just love how it talks. Thank you for sharing the knowledge week after week.
For all Python fans, you must checkout this. You will not disappointed, I promise. Well done and keep it up.
There is no Perl in this article except the logo at the top of the web site.
Great CPAN modules released last week;
MetaCPAN weekly report.
Virtual Event
Virtual event
Paris, France
Munich, Germany
Paris, France
Paris, France
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.
Published by Dimitrios Kechagias on Monday 24 March 2025 06:31
I started using DEV at the suggestion of Perl Weekly, and I was quite pleased with it - until I discovered that links to dev.to are effectively "shadowbanned" on several major platforms (Reddit, Hacker News, etc.). Posts containing DEV URLs would simply not be shown to users, making it impossible to share content effectively.
To work around this, I thought I would need a way to publish my DEV articles on my own domain so I could freely share them. There are some DEV tutorials out there that explain how to consume the API using frontend frameworks like React, however I don't enjoy frontend at all and I did not want to spend much time on that.
My solution was to get a simple Perl script that builds static versions of the articles, along with an index page. A Perl 5 script will run anywhere, including an old shared linux hosting account I still keep on IONOS, and I really like the speed of static sites.
I thought this is an ideal task to start with ChatGPT. Indeed, after 10-15 mins in a few prompts I had a sort-of working solution without having to open up the API documentation, nor writing any CSS. I then spent an hour or two fixing bugs, refactoring some of the ancient-looking code and tweaking / adding features (e.g. tag index pages) - tasks that I enjoy.
Here is the result. You can find the Perl script and assets in this repo.
It will run on pretty much any Perl 5 version (tested down to 5.10) with some basic CPAN modules (LWP::UserAgent, JSON, Path::Tiny).
To use it, check the project out from the repo and change 2 lines in devtostatic.pl with your username and your desired blog name:
my $username = 'your_dev_to_username';
my $blogname = "your_blog_name";
Generate the static site to a target_directory
:
perl dev_to_static.pl target_directory
You can run it on your web host, or run locally and copy the resulting directory to your host.
A nightly cron can update the site with new articles.
Published by Dimitrios Kechagias on Monday 24 March 2025 01:32
I started using DEV at the suggestion of Perl Weekly, and I was quite pleased with it - until I discovered that links to dev.to are effectively "shadowbanned" on several major platforms (Reddit, Hacker News, etc.). Posts containing DEV URLs would simply not be shown to users, making it impossible to share content effectively.
To work around this, I thought I would need a way to publish my DEV articles on my own domain so I could freely share them. There are some DEV tutorials out there that explain how to consume the API using frontend frameworks like React, however I don't enjoy frontend at all and I did not want to spend much time on that.
My solution was to get a simple Perl script that builds static versions of the articles, along with an index page. A Perl 5 script will run anywhere, including an old shared linux hosting account I still keep on IONOS, and I really like the speed of static sites.
I thought this is an ideal task to start with ChatGPT. Indeed, after 10-15 mins in a few prompts I had a sort-of working solution without having to open up the API documentation, nor writing any CSS. I then spent an hour or two fixing bugs, refactoring some of the ancient-looking code and tweaking / adding features (e.g. tag index pages) - tasks that I enjoy.
Here is the result. You can find the Perl script and assets in this repo.
It will run on pretty much any Perl 5 version (tested down to 5.10) with some basic CPAN modules (LWP::UserAgent, JSON, Path::Tiny).
To use it, check the project out from the repo and change 2 lines in dev_to_static.pl with your username and your desired blog name:
my $username = 'your_dev_to_username';
my $blogname = "your_blog_name";
Generate the static site to a target_directory
:
perl dev_to_static.pl target_directory
You can run it on your web host, or run locally and copy the resulting directory to your host.
A nightly cron can update the site with new articles.
Published by Amber Lucas on Sunday 23 March 2025 19:32
Unlocking Additional Rewards and Network Security by LePerlinging Your Claiming PERL via DappRadar
Published on Sunday 23 March 2025 14:18
The examples used here are from the weekly challenge problem statement and demonstrate the working solution.
You have a broken keyboard which sometimes type a character more than once. You are given a string and actual typed string. Write a script to find out if the actual typed string is meant for the given string.
What we’re faced with here is a problem of removing consecutive duplicated letters. The trick is that some letters may be correctly duplicated in succession! For example “coffeescript”has two f’s and two e’s which are not in error. We’re given the correct version so wee need to track the current correct letter and find deviations.
Another special case to consider is when the deviations occur at the end of the string and we get all of the same repeated letters as in the “rrakuuuu”example. To address this we check if the repeated letters remaining match the last known good letter.
Our solution is to loop over the letters in the candidate string guided by the original word. We do this all in one subroutine, the code is not so unwieldy to need to be broken into smaller pieces.
sub loop_compare{
my($n, $s) =
@_;
my
@n = split //, $n;
my
@s = split //, $s;
my $current_n = q//;
my $current_s = q//;
{
my $previous_n = $current_n;
$current_n = shift
@n;
$current_s = shift
@s;
if($current_s ne $current_n && $current_s eq $previous_n){
unshift
@n, $current_n;
{
$current_s = shift
@s;
redo if $current_s eq $previous_n &&
@s > 0;
unshift
@s, $current_s;
}
}
return 0 if $current_s ne $current_n && $current_s ne $previous_n;
redo if
@n > 0 &&
@s > 0;
}
return 1 if (
@n == 0 &&
@s ==0) || (
@s == grep {$_ eq $current_s}
@s);
return 0;
}
◇
Fragment referenced in 2.
We really just need one subroutine to co-ordinate the inputs and run the main loop that’s required.
Putting it all together...
The rest of the code just runs some simple tests.
MAIN:{
say loop_compare q/perl/, q/perrrl/;
say loop_compare q/raku/, q/rrakuuuu/;
say loop_compare q/python/, q/perl/;
say loop_compare q/coffeescript/, q/cofffeescccript/;
}
◇
Fragment referenced in 2.
$ perl perl/ch-1.pl 1 1 0 1
You are given a string. Write a script to reverse only the alphabetic characters in the string.
First we separate the alphabetic characters from the string, then we reverse them, then we finish by recombining the reversed alphabetic characters with the non-alphabetic characters.
We’ll put everything together in a single subroutine.
The rest of the code drives some tests.
MAIN:{
say reverse_letters q/p-er?l/;
say reverse_letters q/wee-k!L-y/;
say reverse_letters q/_c-!h_all-en!g_e/;
}
◇
Fragment referenced in 9.
$ perl perl/ch-2.pl l-re?p yLk-e!e-w _e-!g_nel-la!h_c
Published by /u/niceperl on Sunday 23 March 2025 17:18
Published by Unknown on Sunday 23 March 2025 18:17
This is the weekly favourites list of CPAN distributions. Votes count: 62
This week there isn't any remarkable distribution
Build date: 2025/03/22 22:53:29 GMT
Clicked for first time:
Increasing its reputation:
Published by Mohammad Sajid Anwar on Sunday 23 March 2025 12:46
Please find my learning experience in the post below:
https://theweeklychallenge.org/blog/terraform-docker
Each week Mohammad S. Anwar sends out The Weekly Challenge, a chance for all of us to come up with solutions to two weekly tasks. My solutions are written in Python first, and then converted to Perl. It's a great way for us all to practice some coding.
You have a broken keyboard which sometimes type a character more than once.
You are given a string and actual typed string.
Write a script to find out if the actual typed string is meant for the given string.
This is a two liner for both the Perl and Python solutions. I can use a regular expression to see if the typed
value contains one or more of each character in the name
variable.
The thing that needs to be handled is escaping any characters that have special meaning in a regular expression. Thankfully Perl has quotemeta and Python has re.escape method to handle this.
The entire regular expressions starts with ^
to signify the start of the string. It then has each letter (escaped if required) followed by a +
character, which means one or more of that letter. The regular expression ends with a $
for the end of the string.
Python
def broken_keys(name: str, typed: str) -> bool:
r = '^' + '+'.join(map(re.escape, name)) + '+$'
return re.search(r, typed)
Perl
sub main ( $name, $typed ) {
my $r = '^' . join( '+', map { quotemeta } split //, $name ) . '+$';
say $typed =~ $r ? 'true' : 'false';
}
$ ./ch-1.py perl perrrl
True
$ ./ch-1.py raku rrakuuuu
True
$ ./ch-1.py python perl
False
$ ./ch-1.py coffeescript cofffeescccript
True
You are given a string.
Write a script to reverse only the alphabetic characters in the string.
Let's start with discussion about my Perl solution. This also is a two liner. The first line extracts all the letters from the string, and stores it in the array called @letters
. The second line replaces all the letters by calling pop(@letters)
each time a letter is found.
The regular expression has three modifiers:
i
is for a case insensitive searchg
is for global (replace all occurrences)e
will evaluate the right side as an expression.
sub main ($str) {
my @letters = grep { /[a-z]/i } split //, $str;
$str =~ s/[a-z]/pop(@letters)/ige;
say $str;
}
I was thinking that my Python solution would be use the same logic. But it turns out that letters.pop()
is only computed once, and thus all the letters are replaced with the last letter found.
I'm not entirely sure the reasons why, and given that this isn't my day job, I'm not going to spend too much time on finding out why :)
My Python solution starts out the same by extracting all the letters found into list called letters
.
def reversed_letters(typed: str) -> str:
letters = [s for s in typed if s.isalpha()]
I then go though each character in the original string. If it is a letter, I take the last letter from the letters
list and add it to the new_string
variable. If it isn't, I add the character to the new_string
variable.
new_string = ''
for char in typed:
if char.isalpha():
new_string += letters.pop()
else:
new_string += char
return new_string
One thing to note is the Perl solution will only match the 26 letters of the English alphabet. The Python solution will match characters of any alphabet.
The second and third examples are surrounded in quotes as the exclamation mark (!
) has special meaning in bash.
$ ./ch-2.py p-er?l
l-re?p
$ ./ch-2.py 'wee-k!L-y'
yLk-e!e-w
$ ./ch-2.py '_c-!h_all-en!g_e'
_e-!g_nel-la!h_c
Published by Mastering Secure HAPI Staking for Maximum Returns on Sunday 23 March 2025 06:51
Published by Mohammad Sajid Anwar on Sunday 23 March 2025 03:19
Learning GitHub Actions for Map::Tube.
Please checkout the post for more information.
https://theweeklychallenge.org/blog/github-actions
Published on Sunday 23 March 2025 00:00
Published by JohnT on Friday 21 March 2025 21:12
I was trying to set up a bash script, which uses the following code, to avoid odd path names getting split, which is what happened with a simple ':' etc. So I used the code for a SECTION SIGN eg § which is \u0A7
while read -d '' LINE ; do
some actions ;
done < <( find * -type f -printf "%p"$'\u0A7'"%s\0" ; )
But now I've given myself another headache, cut and csvtool don't work on this unicode character. (Well csvtool does split but leaves a trailing REPLACEMENT CHARACTER on the first col string. I thought I'd replace the csvtool with a bit of inline perl code, eg.
perl -n -e 'chomp ; @sx = split(/\N{SECTION SIGN}/,$_) ; print "$sx[0] :: $sx[1]\n" ; ' <<< 12345$'\u0A7'abcdef
12345� :: abcdef
This is the same result as with csvtool. The � is the REPLACEMENT CHARACTER, and I expect this is something to do with leaving behind a part of the 2-byte unicode char.
So, my question (and I've tried several things till my brain hurt) is what unicode encodes/decodes do I need to add to get this perl code to return the correct split strings?
Published by bulk88 on Friday 21 March 2025 14:22
small .h trick for faster win32 interp compiles cl.exe in the terminal is much faster by eye. PERL_CORE only, since CPAN XS assumes the built-in out the box headers/tokens/structs/linker libs selected by p5p decades ago will never change. Since CPAN has been caught doing "-DPERL_CORE" in the past then including p5 core headers, include a provision to enable #include full W32 headers, since it might be difficult to #undef then #include the OS headers a 2nd time with different CPP defines. "#define NONLS" too many core interp .c files need the ANSI/Wide code page apis to special case each .c. Just leave it out for now. A benefit is smaller .pdb or whatever GCC's dbg symbol file format is. So faster debugger startup. Also GCC uncontrollably includes all "#define"s in its symbol disk format (which isnt a separate file, but a many MBs memory mapped data structure embedded into the particular .exe or .dll, on disk, and in VM). Since Perl isn't a Win32 GUI app, keep the GUI APIs out of the compiler if possible and toss the "text" ASAP in the phases of compiling. Whether whole MS .h files are skipped, or CPP discards large chunks of APIs before reaching the C parser/.obj/.pdb files, is implementation specific behaviour by particular MSVCs and Mingw. Our side was completed, in requesting to exclude stuff.
Published by mauke on Friday 21 March 2025 14:15
Porting/release_managers_guide.pod: minor adjustments - After installing, perl shouldn't need any `-Ilib` options. - Hyperlinks should be clickable.
Published by mauke on Friday 21 March 2025 14:12
Prepare Module::Corelist for 5.41.11
Published by mauke on Friday 21 March 2025 13:55
Bump the perl version in various places for 5.41.11
Published by Demeter P. Chen on Thursday 20 March 2025 17:11
I have 2 similar files which contains the following
hello
peppa
The only difference is that
./c/d/b.txt
has blank line which contains space
while ./c/d/m.txt
has empty line in line 3
Running the find . -name "*.txt" -type f -exec perl -00 -ne 'print "$ARGV\n" if ($_ =~ /hello\s+peppa/msi);' {} \;
will print ./c/d/b.txt
but not ./c/d/m.txt
. I expecting it also print ./c/d/m.txt
Below is the hexdump of the file if it help
[user@host]$ hexdump -v -C ./c/d/m.txt
00000000 68 65 6c 6c 6f 0a 20 20 20 20 0a 0a 20 20 20 20 |hello. .. |
00000010 70 65 70 70 61 0a |peppa.|
00000016
[user@host]$ hexdump -v -C ./c/d/b.txt
00000000 68 65 6c 6c 6f 0a 20 20 20 20 0a 20 0a 20 20 20 |hello. . . |
00000010 20 70 65 70 70 61 0a | peppa.|
00000017
I was able to verify that this occurs for both perl 5.16 and 5.38
Weekly Challenge 312 is here. 312 is the telephone area code in and around Chicago. Once upon a time, when I dressed so fine, threw the bums a dime in my prime, it was my area code, but then we ran out of phone numbers and, like a soccer team falling on hard times, the suburbs were relegated to the far less prestigious 708 (12×59 -- what kind of useless factoring is that?), and then the only slightly better 630 (2×3×5×7 × 3).
Be that as it may, here we are, ticking away the moments that make up a dull day, and so we are going to fritter and waste the hours in an off-hand way solving a couple of programming problems.
You are given a typewriter with lowercase
English letters a to z arranged in a circle.
Typing a character takes 1 sec. You can
move the pointer one character at a time
clockwise or counter-clockwise. The pointer
initially points at 'a'.
Write a script to return the minimum time it
takes to print the given string.
Example 1: Input: $str = "abc"
Output: 5
Example 2: Input: $str = "bza"
Output: 7
Example 3: Input: $str = "zjpc"
Output: 34
Each time we type a letter, that takes one second, so the time will be at least the length of the string.
To that, we need to add the time to move from one letter to the next, starting with the finger poised over 'a'. Going around the circle is modulo arithmetic, but we need to check both directions and pick the shorter.
sub minTime($str)
{
# List of pointer positions, beginning at A
my @ptr = (0, map { ord($_) - ord("a") } split(//, $str));
# Array of closest differences between positions
my @d = slide { min(($a - $b) % 26, ($b-$a) % 26 ) } @ptr;
# One second for each character in str, plus time to move
my $t = length($str) + sum0(@d);
return $t;
}
Notes:
split(//, $str)
Turn the string into a list of charactersmap ord($_) - ord("a") }
Turn the characters into indices between 0 and 25my @ptr = (0, ...)
The hovering finger is initially over 'a', so insert a 0 into the front of the positions.
slide { ... }
From List::MoreUtils
, move across the list a pair at a time. Make a list of differences between character positions.No loops, no index variables, no off-by-one errors.
There are $n balls of mixed colors: red, blue or
green. They are all distributed in 10 boxes labeled 0-9.
You are given a string describing the location of balls.
Write a script to find the number of boxes containing
all three colors. Return 0 if none found.
Example 1 Input: $str = "G0B1R2R0B0"
1
Example 2 Input: $str = "G1R3R6B3G6B1B6R1G3"
3
Example 3 Input: $str = "B3B2G1B3"
0
We'll need to split up the input string and create a representation of balls in boxes. Two ways come to me quickly
Once the balls are categorized by box, then we can check how many boxes contain at least one of G, B, and R. In a string, that can be a regular expression match, or a simple index
function. In the hash, it would be a search for counts greater than zero.
sub ballBox($str)
{
my @box = ("") x 10;
for my ($color, $b) (split(//, $str)) # As of 5.36, multiple values allowed
{
$box[$b] .= $color;
}
return scalar grep { /B/ && /G/ && /R/ } @box;
}
Notes:
my @box = ("") x 10
An array of 10 boxes (0 to 9), each initialized with an empty string.for my ($color, $b) ...
My favorite recent perl addition: processing tuples out of an array.$box[$b] .= $color
Distribute balls into their boxes.grep { /B/ && /G/ && /R/ }
Easiest way to use regular expressions to mean all three must be present.return scalar ...
I only want a zero/non-zero return code. If the function is used in an array context (which it is in a unit test is()
statement), it returns a list instead of a number. No want.sub ballBox_idx($str)
{
my @box = ("") x 10;
for my ($color, $b) (split(//, $str)) # As of 5.36, multiple values allowed
{
$box[$b] .= $color;
}
return scalar grep { index($_, "G") >= 0 && index($_, "B") >= 0 && index($_, "R") >= 0 } @box;
}
This is almost the same, except that the regular expression matches have been replaced by index()
checks. Even though regular expressions are efficient, there's a lot going on under the hood, and I suspect (but need to check) that a simple string scan might be faster.
sub ballBox_hash($str)
{
my @box;
for my ($color, $b) (split(//, $str))
{
$box[$b]{$color}++;
}
return scalar grep { $_->{G} && $_->{B} && $_->{R} } @box;
}
Once again, we split the string in a similar way, but this time we're going to count occurrences.
My intuition for performance is notoriously bad. Let's set up a benchmark test. I'll create a random string that distributes balls randomly, and run 50,000 or so iterations of each variation.
sub runBenchmark($repeat)
{
use Benchmark qw/cmpthese/;
my $str;
foreach my $color ( qw(R G B ) )
{
$str .= $color . int(rand(10)) for 1 .. 25;
}
cmpthese($repeat, {
grep => sub { ballBox($str) },
index => sub { ballBox_idx($str) },
hash => sub { ballBox_hash($str) },
});
}
bash-3.2$ perl ch-2.pl -b 50000
Rate hash grep index
hash 44248/s -- -3% -12%
grep 45455/s 3% -- -9%
index 50000/s 13% 10% --
This time, I'm at least partially right. Using simple string functions slightly beats hash tables and regular expressions, at least for randomly distributed data of a moderate number of balls.
I should also check for other distributions that are most likely in my actual application, like mostly empty boxes, or very large numbers of balls, or combinations like thousands of green balls but only a few red.
However, I'm going to randomly reclaim my time and call it a win.
Published by Boris Orekhov on Thursday 20 March 2025 07:45
I am a philologist and I need to write texts: scientific papers, popularization articles. But sometimes I want to write code. I often treat code as natural language texts. Just as sometimes you want to try your hand at a new genre, you want to leave behind and offer the community code in a programming language that is not your primary language.
I used to write a lot in Perl, it was my second language, but now I've thoroughly forgotten it. However, for sentimental reasons I'd like to have Perl code in my github account, so I had to remember it.
I tried using ChatGPT to accomplish the task I wanted, but never got the results I wanted. I had to write code the old fashioned way and work out the rules of the language.
I plan to write some more applications (useful and just beautiful) in different programming languages in the near future and make them available to the public.
Published on Tuesday 18 March 2025 12:52
From perldoc perlmod
…
An "END" code block is executed as late as possible, that is, after perl
has finished running the program and just before the interpreter is
being exited, even if it is exiting as a result of a die() function.
(But not if it's morphing into another program via "exec", or being
blown out of the water by a signal--you have to trap that yourself (if
you can).) You may have multiple "END" blocks within a file--they will
execute in reverse order of definition; that is: last in, first out
(LIFO). "END" blocks are not executed when you run perl with the "-c"
switch, or if compilation fails....
Perl’s END
blocks are useful inside your script for doing things
like cleaning up after itself, closing files or disconnecting from
databases. In many cases you use an END
block to guarantee certain
behaviors like a commit or rollback of a transaction. You’ll
typically see END
blocks in scripts, but occassionally you might find
one in a Perl module.
Over the last four years I’ve done a lot of maintenance work on legacy Perl applications. I’ve learned more about Perl in these four years than I learned in the previous 20. Digging into bad code is the best way to learn how to write good code. It’s sometimes hard to decide if code is good or bad but to paraphrase a supreme court justice, I can’t always define bad code, but I know it when I see it.
One of the gems I’ve stumbled upon was a module that provided needed
functionality for many scripts that included its own END
block.
Putting an END
block in a Perl module is an anti-pattern and just bad
mojo. A module should never contain an END
block. Here are
some alternatives:
cleanup()
methodDESTROY
) in an object-oriented moduleModules should provide functionality - not take control of your script’s shutdown behavior.
The first and most obvious answer is that they were unaware of how
DESTROY
blocks can be employed. If you know something about the
author and you’re convinced they know better, then why else?
I theorize that the author was trying to create a module that would encapsulate functionality that he would use in EVERY script he wrote for the application. While the faux pas might be forgiven I’m not ready to put my wagging finger back in its holster.
If you want to write a wrapper for all your scripts and you’ve already settled on using a Perl module to do so, then please for all that is good and holy do it right. Here are some potential guidelines for that wrapper:
new()
method that instantiates your wrapperinit()
method that encapsulates the common
startup operations with options to control whether some are executed
or notrun()
method that executes the functionality for the scriptfinalize()
method for executing cleanup proceduresAll of these methods could be overridden if you just use a plain ‘ol Perl
module. For those that prefer composition over inheritance, use a
role with something like Role::Tiny
to provide those universally
required methods. Using Role::Tiny
provides better flexibility
by allowing you to use those methods before or after your
modifications to their behavior.
The particular script I was working on included a module(whose name I
shall not speak) that included such an END
block. My script
should have exited cleanly and quietly. Instead, it produced
mysterious messages during shutdown. Worse yet I feared some
undocumented behaviors and black magic might have been conjured up
during that process! After a bit of debugging, I found the culprit:
END
block baked into itEND
block printed debug messages to STDERR while doing other
cleanup operationsMy initial attempt to suppress the module’s END
block:
END {
use POSIX;
POSIX::_exit(0);
}
This works as long as my script exits normally. But if my
script dies due to an error, the rogue END
block still
executes. Not exactly the behavior I want.
Here’s what I want to happen:
END
block from executing.Ensure my script always exits with a meaningful status code.
A better method for scripts that need an END
block to claw back
control:
use English qw(-no_match_vars);
use POSIX ();
my $retval = eval {
return main();
};
END {
if ($EVAL_ERROR) {
warn "$EVAL_ERROR"; # Preserve exact error message
}
POSIX::_exit( $retval // 1 );
}
END
blocks – Since POSIX::_exit()
terminates
the process immediatelymain()
throws an exception, we
log it without modifying the messagemain()
forgets to return a
status, we default to 1
, ensuring no silent failures.Of course, you should know what behavior you are bypassing if you
decide to wrestle control back from some misbehaving module. In my
case, I knew that the behaviors being executed in the END
block
could safely be ignored. Even if they couldn’t be ignored, I can still
provide those behaviors in my own cleanup procedures.
Isn’t this what future me or the poor wretch tasked with a dumpster dive into a legacy application would want? Explicitly seeing the whole shebang without hours of scratching your head looking for mysterious messages that emanate from the depths is priceless. It’s gold, Jerry! Gold!
Next up…a better wrapper.
Published on Sunday 16 March 2025 01:29
The examples used here are from the weekly challenge problem statement and demonstrate the working solution.
You are given a typewriter with lowercase english letters a to z arranged in a circle. Typing a character takes 1 sec. You can move pointer one character clockwise or anti-clockwise. The pointer initially points at a. Write a script to return minimum time it takes to print the given string.
The complete solution is contained in one file that has a simple structure.
For this problem we do not need to include very much. We’re just specifying to use the current version of Perl, for all the latest features in the language. This fragment is also used in Part 2.
All the work is in one subroutine. We use the ASCII values of each character to compute the new value.
sub minimum_time{
my($s) =
@_;
my
@c = split //, lc($s);
my $time = 0;
my $moves;
my $current = q/a/;
{
my $next = shift
@c;
my($x, $y) = (ord($current) - 96, ord($next) - 96);
$moves = ($x + 26) - $y if $y >= ($x + 13);
$moves = $y - $x if $y <= ($x + 13) && $y >= $x;
$moves = ($y + 26) - $x if $x >= ($y + 13);
$moves = $x - $y if $x <= ($y + 13) && $x >= $y;
$time += $moves;
$time++;
$current = $next;
redo if
@c > 0;
}
return $time;
}
◇
Fragment referenced in 1.
Now all we need are a few lines of code for running some tests.
MAIN:{
say minimum_time q/abc/;
say minimum_time q/bza/;
say minimum_time q/zjpc/;
}
◇
Fragment referenced in 1.
$ perl perl/ch-1.pl 5 7 34
There are $n balls of mixed colors: red, blue or green. They are all distributed in 10 boxes labelled 0-9. You are given a string describing the location of balls. Write a script to find the number of boxes containing all three colors. Return 0 if none found.
We’re going to use Parse::Yapp for this problem. Writing parsers is fun! This problem is providing an excuse to write one. This approach has been used in past weeks, for example TWC 259 from this time last year. For simplicity, to start with, here is all the code that Parse::Yapp will use as it’s input.
"ch-2.yp"
5≡
%token LETTER
%token NUMBER
%{
my %boxes = ();
%}
%%
records: record {\%boxes}
| records record
;
record: LETTER NUMBER {push
@{$boxes{qq/$_[2]/}}, $_[1]}
;
%%
sub lexer{
my($parser) =
@_;
defined($parser->YYData->{INPUT}) or return(’’, undef);
##
# send tokens to parser
##
for($parser->YYData->{INPUT}){
s/^([0-9])// and return (q/NUMBER/, $1);
s/^([A-Z])// and return (q/LETTER/, $1);
}
}
sub error{
exists $_[0]->YYData->{ERRMSG}
and do{
print $_[0]->YYData->{ERRMSG};
return;
};
print "syntax␣error\n";
}
sub parse{
my($self, $input) =
@_;
$input =~ tr/\t/ /s;
$input =~ tr/ //s;
$self->YYData->{INPUT} = $input;
my $result = $self->YYParse(yylex => \&lexer, yyerror => \&error);
return $result;
}
◇
To solve this problem we are going to pass the input string to the parser. The parser is going to return a hash reference which we’ll check to see which boxes contain all the balls, as described in the problem statement.
sub parse_boxes{
my($record) =
@_;
my $parser = Ch2->new();
my $boxes = $parser->parse($record);
my $full = 0;
for my $box (keys %{$boxes}){
$full++ if 1 <= (grep { $_ eq q/R/ }
@{$boxes->{$box}}) &&
1 <= (grep { $_ eq q/G/ }
@{$boxes->{$box}}) &&
1 <= (grep { $_ eq q/B/ }
@{$boxes->{$box}});
}
return $full;
}
◇
Fragment referenced in 6.
Finally, we need to confirm everything is working right.
$ yapp -m Ch2 perl/ch-2.yp; mv Ch2.pm perl $ perl -I perl perl/ch-2.pl G0B1R2R0B0 1 $ perl -I perl perl/ch-2.pl G1R3R6B3G6B1B6R1G3 3 $ perl -I perl perl/ch-2.pl B3B2G1B3 0
Published by Unknown on Sunday 16 March 2025 00:11
Published on Friday 14 March 2025 08:37
In our previous blog post, we detailed a clever external redirect
solution to address the Apache 2.4 regression that broke automatic
directory handling when DirectorySlash Off
was set. We teased the
question: Can we achieve the same behavior with an internal
redirect? Spoiler alert - Nope.
In this follow-up post, we’ll explore why internal rewrites fall short, our failed attempts to make them work, and why the external redirect remains the best and only solution.
/dir
without a trailing slash, Apache
would automatically redirect them to /dir/
.index.html
(or any file
specified by DirectoryIndex
).DirectorySlash Off
is set, Apache stops auto-redirecting
directories./dir
as /dir/
, Apache tries to serve
/dir
as a file, which leads to 403 Forbidden errors.DirectoryIndex
no longer inherits globally from the document
root - each directory must be explicitly configured to serve an
index file.DirectoryIndex
after an internal rewrite.Since Apache wasn’t redirecting directories automatically anymore, we thought we could internally rewrite requests like this:
RewriteEngine On
# If the request is missing a trailing slash and is a directory, rewrite it internally
RewriteCond %{REQUEST_URI} !/$
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} -d
RewriteRule ^(.*)$ /$1/ [L]
Why This Doesn’t Work:
DirectoryIndex
after the rewrite.DirectoryIndex
is not explicitly defined for each
directory, Apache still refuses to serve the file and throws a
403 Forbidden./dir
as a raw file request instead of checking for an index page.To make it work, we tried to manually configure every directory:
<Directory "/var/www/vhosts/treasurersbriefcase/htdocs/setup/">
Require all granted
DirectoryIndex index.roc
</Directory>
DirectoryIndex
after an internal
rewrite. Even though DirectoryIndex index.roc
is explicitly set,
Apache never reaches this directive after rewriting /setup
to /setup/
./setup/
as an empty directory, leading to a 403
Forbidden error.This means that even if we were willing to configure every directory manually, it still wouldn’t work as expected.
We briefly considered whether FallbackResource
could help by
redirecting requests for directories to their respective index files:
<Directory "/var/www/vhosts/treasurersbriefcase/htdocs/setup/">
DirectoryIndex index.roc
Options -Indexes
Require all granted
FallbackResource /setup/index.roc
</Directory>
FallbackResource
is designed to handle 404 Not Found errors, not 403 Forbidden errors./setup/
as a valid directory but
refuses to serve it, FallbackResource
is never triggered.DirectoryIndex
after an internal rewrite.This was a red herring in our troubleshooting FallbackResource
was
never a viable solution.
Another way to handle this issue would be to explicitly rewrite
directory requests to their corresponding index file, bypassing
Apache’s DirectoryIndex
handling entirely:
RewriteEngine On
RewriteCond %{REQUEST_URI} !/$
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} -d
RewriteRule ^(.*)$ /$1/index.roc [L]
DirectoryIndex
handling in Apache 2.4.DirectorySlash Off
, since the request is rewritten directly to a file.index.html
,
index.php
, etc.), additional rules would be required.While this approach technically works, it reinforces our main conclusion: - Apache 2.4 no longer restarts the request cycle after a rewrite, so we need to account for it manually. - The external redirect remains the only scalable solution.
Instead of fighting Apache’s new behavior, we can work with it using an external redirect:
RewriteEngine On
RewriteCond %{REQUEST_URI} !/$
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} -d
RewriteRule ^(.*)$ http://%{HTTP_HOST}/$1/ [R=301,L]
/dir
to /dir/
before Apache even tries to serve it.DirectoryIndex
behavior globally, just like Apache 2.2.So, can we solve with an internal redirect?
DirectoryIndex
after an internal rewrite.DirectoryIndex
settings fail if Apache
has already decided the request is invalid.FallbackResource
never applied, since Apache rejected the request with 403 Forbidden, not 404
Not Found.Does our external redirect solution still hold up?
Yes!!, and in fact, it’s not just the best solution - it’s the only reliable one.
DirectorySlash Off
is set.If you haven’t read our original post yet, check it out here for the full explanation of our external redirect fix.
In part III of this series we’ll beat this dead horse and potentially explain why this was a problem in the first place…
As an online trading company processing millions of transactions daily, we recognise technologies that stand the test of time. For 25 years, Perl has been integral to our operations, and we remain committed to the ecosystem that helped shape our technical foundation.
From our 1999 launch, Perl’s unmatched text processing and CPAN’s modular approach enabled us to evolve into a global platform. Core systems handling complex financial workflows leverage Perl’s stability, with key components still running the same battle-tested code developed in our early years.
Here are some of the activities we’ve done with Perl:
These implementations demonstrate Perl’s capacity to support robust, long-term solutions in demanding technical environments.
Our support of MetaCPAN stems from a clear conviction: foundational tools deserve sustained backing. While our new projects explore different technical approaches, we actively maintain:
“Great technologies create lasting value,” says Chris Horn, Head of Engineering. “Our support for Perl’s ecosystem honours its foundational role in our growth while helping sustain resources that benefit developers worldwide.”
Backing Perl’s ecosystem reflects Deriv’s long-standing belief in collaborative development. We’re proud to continue our MetaCPAN sponsorship through 2025 and support the Perl community as part of our ongoing commitment to open-source.
Published on Thursday 13 March 2025 10:39
I’m currently re-architecting my non-profit accounting SaaS (Treasurer’s Briefcase) to use Docker containers for a portable development environment and eventually for running under Kubernetes. The current architecture designed in 2012 uses an EC2 based environment for both development and run-time execution.
As part of that effort I’m migrating from Apache 2.2 to 2.4. In the
new development environment I’m using my Chromebook to access the
containerized application running on the EC2 dev server. I described
that setup in my previous
blog. In
that setup I’m accessing the application on port 8080 as http://local-dev:8080
.
If, as in the setup describe in my blog, you are running Apache on a
non-standard port (e.g., :8080
) - perhaps in Docker, EC2, or
via an SSH tunnel you may have noticed an annoying issue after
migrating from Apache 2.2 to Apache 2.4…
Previously, when requesting a directory without a trailing slash
(e.g., /setup
), Apache automatically redirected to /setup/
while preserving the port. However, in Apache 2.4, the redirect is
done externally AND drops the port, breaking relative URLs and
form submissions.
For example let’s suppose you have a form under the /setup
directory that
has as its action
“next-step.html”. The expected behavior on that page
would be to post to the page /setup/next-step.html
. But what really
happens is different. You can’t even get to the form in the first
place with the URL http://local-dev:8080/setup
!
http://yourserver:8080/setup
=> http://yourserver:8080/setup/
http://yourserver:8080/setup
=> http://yourserver/setup/
(port 8080
is missing!)This causes problems for some pages in web applications running behind Docker, SSH tunnels, and EC2 environments, where port forwarding is typically used.
If you’re experiencing this problem, you can confirm it by running:
curl -IL http://yourserver:8080/setup
You’ll likely see:
HTTP/1.1 301 Moved Permanently
Location: http://yourserver/setup/
Apache dropped 8080
from the redirect, causing requests to break.
Several workarounds exist, but they don’t work in our example.
DirectorySlash
: Prevents redirects but causes 403 Forbidden
errors when accessing directories.FallbackResource
: Works, but misroutes unrelated requests.Instead, we need a solution that dynamically preserves the port when necessary.
To restore Apache 2.2 behavior, we can use a rewrite rule that only preserves the port if it was in the original request.
<VirtualHost *:8080>
ServerName yourserver
DocumentRoot /var/www/html
<Directory /var/www/html>
Options -Indexes +FollowSymLinks
DirectoryIndex index.html index.php
Require all granted
DirectorySlash On # Keep normal Apache directory behavior
</Directory>
# Fix Apache 2.4 Directory Redirects: Preserve Non-Standard Ports
RewriteEngine On
RewriteCond %{REQUEST_URI} !/$
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} -d
RewriteCond %{SERVER_PORT} !^80$ [OR]
RewriteCond %{SERVER_PORT} !^443$
RewriteRule ^(.*)$ http://%{HTTP_HOST}/$1/ [R=301,L]
UseCanonicalName Off
</VirtualHost>
/setup
=> /setup/
).!=80
, !=443
):8080
, making it flexible for any non-standard port8080
locally to 80
on the jump box./setup
redirected externally without the port, causing failures.mod_rewrite
and a RewriteRule
that ensures that port 8080
is preservedApache 2.4’s port-dropping behavior is an unexpected regression from 2.2, but we can fix it with a simple rewrite rule that restores the expected behavior without breaking anything.
If you’re running Docker, EC2, or SSH tunnels, this is a fix that will prevent you from jumping through hoops by altering the application or changing your networking setup.
Hmmmm…maybe we can use internal redirects instead of an external redirect??? Stay tuned.
Published on Thursday 13 March 2025 09:46
In our previous posts, we explored how Apache 2.4 changed its
handling of directory requests when DirectorySlash Off
is set,
breaking the implicit /dir → /dir/
redirect behavior that worked in
Apache 2.2. We concluded that while an external redirect is the only
reliable fix, this change in behavior led us to an even bigger
question:
Is this a bug or an intentional design change in Apache?
After digging deeper, we’ve uncovered something critically important that is not well-documented:
DirectoryIndex
.This post explores why this happens, whether it’s a feature or a bug, and why Apache’s documentation should explicitly clarify this behavior.
Let’s revisit the problem: we tried using an internal rewrite to append a trailing slash for directory requests:
RewriteEngine On
RewriteCond %{REQUEST_URI} !/$
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} -d
RewriteRule ^(.*)$ /$1/ [L]
Expected Behavior:
- Apache should internally rewrite /setup
to /setup/
.
- Since DirectoryIndex index.roc
is set, Apache should serve index.roc
.
Actual Behavior:
- Apache internally rewrites /setup
to /setup/
, but then
immediately fails with a 403 Forbidden.
- The error log states:
AH01276: Cannot serve directory /var/www/vhosts/treasurersbriefcase/htdocs/setup/: No matching DirectoryIndex (none) found
- Apache is treating /setup/
as an empty directory instead of recognizing index.roc
.
Unlike what many admins assume, Apache does not start over after an internal rewrite.
/setup
).mod_rewrite
.index.html
, index.php
, etc.) exists, DirectoryIndex
resolves it.DirectoryIndex
.DirectoryIndex
after an internal rewrite./setup/
as an empty directory with no default file and denies access with 403 Forbidden.First, let’s discuss why this worked in Apache 2.2.
The key reason internal rewrites worked in Apache 2.2 is that Apache restarted the request processing cycle after a rewrite. This meant that:
index.html
, index.php
, or any configured default file.DirectorySlash
was handled earlier in the request cycle,
Apache 2.2 still applied directory handling rules properly, even after
an internal rewrite.In Apache 2.4, this behavior changed. Instead of restarting the
request cycle, Apache continues processing the request from where it
left off. This means that after an internal rewrite, DirectoryIndex
is
never reprocessed, leading to the 403 Forbidden errors we
encountered. This fundamental change explains why no internal solution
works the way it did in Apache 2.2.
mod_rewrite
or DirectoryIndex
docs.Since Apache won’t reprocess DirectoryIndex, the only way to guarantee correct behavior is to force a new request via an external redirect:
RewriteEngine On
RewriteCond %{REQUEST_URI} !/$
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} -d
RewriteRule ^(.*)$ http://%{HTTP_HOST}/$1/ [R=301,L]
This forces Apache to start a completely new request cycle,
ensuring that DirectoryIndex
is evaluated properly.
We believe this behavior should be explicitly documented in: - mod_rewrite documentation (stating that rewrites do not restart request processing). - DirectoryIndex documentation (noting that it will not be re-evaluated after an internal rewrite).
This would prevent confusion and help developers troubleshoot these issues more efficiently.
Published by Thibault Duponchelle on Wednesday 12 March 2025 22:23
That was a big year for CPANSec.
In case some of the activities this year flew under your radar, please find some of the achievements listed in this retrospective!
In 2024, CPANSec worked to illustrate the importance of the Common Vulnerabilities and Exposures (CVE) process.
Until then, our experience is that very few CVEs were published for Perl modules and tooling.
Beyond that, people and authors were a bit reluctant to deal with those CVEs.
CVEs are not a sign of bad quality or maintenance of a code, but a professional way of tagging and tracking a vulnerability, also indicating the importance of the concerned code.
The start of the year was marked by vulnerabilities reported for Spreadsheet::ParseExcel:
CPANSec continued with CPAN installer cpanminus (a major installer of the Perl ecosystem):
This latest is a bit related to a fix from a CPANSec member earlier in 2023 to the CPAN installer cpan (part of Perl core distribution):
Similarly, a CVE was emitted for the POSIX::2008 module:
Along with CVEs, tooling to monitor, fetch or test for them is very useful. They can be installed in workflows or tooling as a gate keeper so that companies do not ship vulnerable pieces of code.
CPANSec produced and improved a few tools to fetch or test for CVEs:
Note: Not all CVE tooling are managed by CPANSec, I’m thinking in particular CPAN::Audit and its sidecar CPAN::Audit::DB or NIST::NVD.
But CPANSec follows closely and contributes to them when possible.
In 2023 and 2024, if CPANSec helped with or contributed to CVEs for CPAN, the assignment of CVEs remained under control of another CNA, MITRE.
CPANSec members worked throughout the year to give the group the ability to assign CVEs. After all, who knows better than CPANSec the impact of CVEs on Perl modules? (If you know someone, send them our way! :)
By end of the year, the groundwork to become a CNA was completed.
This designation was officially granted in February 2025: CPANSec is now a CVE Numbering Authority (CNA)!
The news of CPANSec becoming CVE Numbering Authority (CNA) was saluted by community luminaries like Greg Kroah-Hartman (Linux kernel) and Daniel Stenberg (cURL).
The CNA administrators are Timothy Legge, Stig Palmquist and Breno G. de Oliveira.
In parallel, CPANSec collectively pushed for authors to publish a Security Policy.
Doing so is considered Open Source Good Practice, especially as security is becoming more and more critical.
This effort resulted in creating a template, providing guidelines and, last but not least, communicating this initiative in various channels.
In order to help authors integrating a Security Policy, new tools Software::Security::Policy and Dist::Zilla::Plugin::SecurityPolicy were created and published.
Generating random numbers can help in a wide variety of tasks. All of them don’t have the same level of criticality. In particular, random generated data used in a security context requires extra care.
CPANSec studied and reviewed CPAN modules for this use, and shared this in Random Data For Security Use.
A vanilla install of Perl (distribution) does not provide HTTPS capabilities, and this is annoying. That’s an important (and difficult) topic that is addressed, across core developers and CPANSec.
Things started to go into motion in 2024 to make it happen.
Discussions, with the Perl Steering Council and core contributors. A plan was created, with some preliminary work happening.
One notable contribution is the creation of the new module Crypt::Bear by LEONT to wrap the TLS library BearSSL.
CPANSec attended many meetings in other security-related communities, and cross-connected with several other organization working on the topic.
One of the outcomes of this effort is available as in the form of an ongoing study on Roles and metadata in open source supply-chains, but it goes well beyond that.
CPANSec volunteers adopted security related modules:
Adopting modules is not always the only option, and CPANSec also reviewed modules for insecure algorithms in order to offer recommendations or propose deprecation.
Through the year, CPANSec volunteers preformed an analysis of the CPAN ecosystem to know exactly how much vulnerable it would be to some common supply chain attacks:
More attacks vectors were also looked at, including starjacking and the topic of stealing namespaces.
CPANSec volunteers reviewed and tested PAUSE with various attempts to break it with nasty modules, steal namespaces or execute remote code.
This was done on a local instance made possible thanks to the hard work of automation from “Table PAUSE” at Perl Toolchain Summit 2024 that was later improved, tweaked (fast indexing, minor fixes…) and containerized by CPANSec.
Outside of pentesting, these deliveries are useful for plenty of tests (on indexing, on PAUSE functionning itself) or as a local development environment of PAUSE.
If CPANSpec is taking care of security aspects of CPAN and Perl, it’s also promoting Perl in general, actively recruiting for open source security.
This is in this scope that the group had a presence in several events. From Perl Toolchain Summit 2024 to London Perl and Raku Workshop 2024, but also FOSDEM 2024 and the OpenSSF summit.
CPANSec also initiated a discussion (with a proposed change) to enable Secure by default sessions in Mojolicious.
CPANSec had a recurring discussion on the topic of module signatures. Reviewing the limitations “by design” of the current options, and thinking about a correct way to implement that feature. Similarly, discussions about CPAN installer enhancements (“Do not install module version with a CVE”, “Patch module on the fly at install”. etc…) were had, but only at an early stage.
At the very end of 2024, CPANSec reviewed the state of the art vulnerability of Perl bcrypt related modules (Crypt::bcrypt, Digest::Bcrypt) on misuse following the Okta reported incident.
I attributed many of previous achievements to “CPANSec”, but who was part of the “CPANSec group” in 2024?
In last name alphabetical order:
Olaf Alders
José Joaquín Atria
H.Merijn Brand
Thibault Duponchelle
Alexander Hartmaier
Alexander Karelas
Peter Krawczyk
Timothy Legge
Tina Müller
Ingy döt Net
Salve J. Nilsen
Breno G. de Oliveira
Stig Palmquist
Nicolas Rochelemagne
Robert Rothenberg
Giuseppe Di Terlizzi
Leon Timmermans
This was a big year; The group really took shape and get full speed with progress in many places.
The group met regularly (18 meetings!), had fun and got outstanding results. This is the year when CPANSec got traction as a recognized supporting organization for securing the Perl/CPAN ecosystem.
With so many visible and impacting outcomes, 2024 confirmed well beyond expectations that CPANSec has a raison d’être.
It was also a very rewarding year for all people involved! Looking forward to a similarly successful 2025 :)
Published on Saturday 08 March 2025 22:30
The examples used here are from the weekly challenge problem statement and demonstrate the working solution.
You are given a string consists of english letters only. Write a script to convert lower case to upper and upper case to lower in the given string.
The complete solution is contained in one file that has a simple structure.
For this problem we do not need to include very much. We’re just specifying to use the current version of Perl, for all the latest features in the language. This fragment is also used in Part 2.
All the work is in one subroutine. We use the ASCII values of each character to compute the new value.
sub upper_lower{
my($s) =
@_;
my
@c = split //, $s;
return join q//, map{
my $x = ord($_);
if($x >= 65 && $x <= 90){
chr($x + 32);
}
elsif($x >= 97 && $x <= 122){
chr($x - 32);
}
}
@c;
}
◇
Fragment referenced in 1.
Now all we need are a few lines of code for running some tests.
MAIN:{
say upper_lower q/pERl/;
say upper_lower q/rakU/;
say upper_lower q/PyThOn/;
}
◇
Fragment referenced in 1.
$ perl perl/ch-1.pl PerL RAKu pYtHoN
You are given a string, $str, made up of digits, and an integer, $int, which is less than the length of the given string. Write a script to divide the given string into consecutive groups of size $int (plus one for leftovers if any). Then sum the digits of each group, and concatenate all group sums to create a new string. If the length of the new string is less than or equal to the given integer then return the new string, otherwise continue the process.
To solve this problem we need to do the following
Let’s look at each of those pieces individually and then combine them together into one subroutine.
my $g = [];
my $groups;
for my $i (0 ..
@{$c} - 1){
my $n = $i % $size;
if($n == 0){
$g = [];
push
@{$g}, $c->[$i];
}
elsif($n == $size - 1){
push
@{$g}, $c->[$i];
push
@{$groups}, $g;
$g = [];
}
else{
push
@{$g}, $c->[$i];
}
}
push
@{$groups}, $g if
@{$g} > 0;
◇
With that work take care of, let’s combine all these pieces into one subroutine.
Finally, here’s a few tests to confirm everything is working right.
MAIN:{
say group_digit_sum q/111122333/, 3;
say group_digit_sum q/1222312/, 2;
say group_digit_sum q/100012121001/, 4;
}
◇
Fragment referenced in 5.
$ perl perl/ch-2.pl 359 76 162
Published by Unknown on Saturday 08 March 2025 23:09
This is the weekly favourites list of CPAN distributions. Votes count: 56
Week's winner: DBI (+2)
Build date: 2025/03/08 22:03:54 GMT
Clicked for first time:
Increasing its reputation:
Published on Friday 07 March 2025 19:21
If you’re doing some development on a remote server that you access via a bastion host (e.g., an EC2 instance), and you want a seamless way to work from a Chromebook, you can set up an SSH tunnel through the bastion host to access your development server.
This guide outlines how to configure a secure and efficient development workflow using Docker, SSH tunnels, and a Chromebook.
Your Chromebook is a great development environment, but truth be told, the cloud is better. Why? Because you can leverage a bucket load of functionality, resources and infrastructure that is powerful yet inexpensive. Did I mention backups? My Chromebook running a version of debian rocks, but in general I use it as a conduit to the cloud.
So here’s the best of both worlds. I can use a kick-butt terminal
(terminator
) on my Chromie and use its networking mojo to access my
web servers running in the cloud.
In this setup:
Here’s what it looks like in ASCII art…
+--------------+ +--------------+ +--------------+
| Chromebook | | Bastion Host | | EC2 |
| | 22 | | 22 | |
| Local SSH |----| Jump Box |----| Development |
| Tunnel:8080 | 80 | (Accessible) | 80 | Server |
+--------------+ +--------------+ +--------------+
To create an SSH tunnel through the bastion host:
ssh -N -L 8080:EC2_PRIVATE_IP:80 user@bastion-host
-N
: Do not execute remote commands, just forward ports.-L 8080:EC2_PRIVATE_IP:80
: Forwards local port 8080 to port 80 on the development server (EC2 instance).user@bastion-host
: SSH into the bastion host as user
.Once connected, any request to localhost:8080
on the Chromebook will
be forwarded to port 80 on the EC2 instance.
To maintain the tunnel connection automatically:
~/.ssh/config
):Host bastion
HostName bastion-host
User your-user
IdentityFile ~/.ssh/id_rsa
LocalForward 8080 EC2_PRIVATE_IP:80
ServerAliveInterval 60
ServerAliveCountMax 3
ssh -fN bastion
curl -I http://localhost:8080
You should see a response from your EC2 instance’s web server.
If your EC2 instance runs a Dockerized web application, expose port 80 from the container:
docker run -d -p 80:80 my-web-app
Now, accessing http://localhost:8080
on your Chromebook browser will
open the web app running inside the Docker container on EC2.
This setup allows you to securely access a remote development environment from a Chromebook, leveraging SSH tunneling through a bastion host.
localhost:8080
) to a remote web app.Now you can develop on remote servers with a Chromebook, as if they were local!
The North American Perl and Raku Conference will soon be upon us, and that means now is a great time to show your support for this very special event. This year there are many available sponsorship tiers and lots of opportunities for your organization to support the conference.
The Perl and Raku Conference 2025 is a community-led gathering of developers, enthusiasts, and industry professionals. Taking place June 27-29, 2025, in Greenville/Spartanburg, South Carolina, the conference features technical talks, training sessions, and networking opportunities that bring together the Perl and Raku communities.
Support our local community by contributing to our charity raffle benefiting a local Greenville/Spartanburg area food bank:
Exclusive naming rights available for:
Proceeds beyond conference expenses support The Perl and Raku Foundation, a non-profit organization dedicated to advancing the Perl and Raku programming languages through open source development, education, and community building.
For more information on to become a sponsor, please contact: olaf@perlfoundation.org
Published on Saturday 01 March 2025 22:17
The examples used here are from the weekly challenge problem statement and demonstrate the working solution.
You are given a list of array of integers. Write a script to return the common elements in all the arrays.
The complete solution is contained in one file that has a simple structure.
For this problem we do not need to include very much. We’re just specifying to use the current version of Perl, for all the latest features in the language. This fragment is also used in Part 2.
We’ll take the arrays in pairs and build up a list of common elements. First we compute the common elements of the first two arrays and then proceed to check these against the remaining arrays. If any of these initial common elements are not found in subsequent arrays they are not included in future checks. Finally the remaining common elements are returned. If there are no common elements we return n/a.
sub array_intersections{
my
@common_elements;
my $x = shift
@_;
my $y = shift
@_;
if($x && $y){
my
@common = map {
my $x = $_;
grep {$x == $_}
@{$y}
}
@{$x};
push
@common_elements,
@common;
}
{
$x = shift
@_;
my
@common = map {
my $x = $_;
grep {$x == $_}
@{$y}
}
@common_elements;
@common_elements =
@common;
redo if
@_ > 1;
}
return (join q/, /,
@common_elements) || q#n/a#;
}
◇
Fragment referenced in 1.
Now all we need are a few lines of code for running some tests.
MAIN:{
say array_intersections [1, 2, 3, 4], [4, 5, 6, 1], [4, 2, 1, 3];
say array_intersections [1, 0, 2, 3], [2, 4, 5];
say array_intersections [1, 2, 3], [4, 5], [6];
}
◇
Fragment referenced in 1.
$ perl perl/ch-1.pl 1, 4 2 n/a
You are given an array of integers. Write a script to sort odd index elements in decreasing order and even index elements in increasing order in the given array.
To solve this problem we need to do the following
Much of this work can be written concisely using map and grep.
sub sort_odd_even{
my
@i =
@_;
my
@odds = map { $i[$_] } grep {$_ % 2 != 0} 0 ..
@_ - 1;
my
@evens = map { $i[$_] } grep {$_ % 2 == 0} 0 ..
@_ - 1;
my
@odds_sorted = sort {$b <=> $a}
@odds;
my
@evens_sorted = sort {$a <=> $b}
@evens;
my
@common_elements;
do {
$common_elements[$_] = shift
@odds_sorted if $_ % 2 != 0;
$common_elements[$_] = shift
@evens_sorted if $_ % 2 == 0;
} for 0 ..
@_ - 1;
return
@common_elements;
}
◇
Fragment referenced in 5.
Finally, here’s a few tests to confirm everything is working right.
MAIN:{
say join q/, /, sort_odd_even 4, 1, 2, 3;
say join q/, /, sort_odd_even 3, 1;
say join q/, /, sort_odd_even 5, 3, 2, 1, 4;
}
◇
Fragment referenced in 5.
$ perl perl/ch-2.pl 2, 3, 4, 1 3, 1 2, 3, 4, 1, 5
Published by Stig Palmquist, Timothy Legge and Breno G. de Oliveira on Tuesday 25 February 2025 21:00
The CPAN Security Group was authorized by the CVE Program as a CVE Numbering Authority (CNA) on Feb 25, 2025. A CNA assigns and manages CVE identifiers for projects in their scope.
Our scope is vulnerabilities in Perl and CPAN Modules (including End-of-Life Perl versions) found at perl.org, cpan.org or metacpan.org, excluding distributions of Perl or CPAN Modules maintained by third-party redistributors.
CVE is an international, community-based effort to identify, define and catalog publicly disclosed software vulnerabilities. To learn more about the CVE program, visit www.cve.org.
Vulnerabilities should be reported according to the security policy of the affected project.
For more details, see our guide on how to Report a Security Issue in Perl and the CPAN ecosystem.
To request a CVE identifier, or to update a CVE we have issued, please send an email to cve-request@security.metacpan.org.
Subscribe to the cve-announce mailing list to be notified of new CVEs published by us.
For questions, disputes or other CNA related queries please use cna@security.metacpan.org. Disputes are handled according to the CNA rules.