Perl Regex

blogs.perl.org

Published by Mohammad Sajid Anwar on Tuesday 25 March 2025 15:51

Special variable ${^LAST_SUCCESSFUL_PATTERN} in Perl v5.38
Please checkout for more information in the post below:
https://theweeklychallenge.org/blog/perl-regex

Random in Perl

blogs.perl.org

Published by Mohammad Sajid Anwar on Tuesday 25 March 2025 15:49

Environment variable PERL_RAND_SEED in Perl v5.38
Please checkout the post for more information:
https://theweeklychallenge.org/blog/random-in-perl

How to Get the Most Out of Your Perlin $PERL Rewards

Perl on Medium

Published by Abigail Rivers on Tuesday 25 March 2025 12:10

Mastering the Art of Maximizing Your $PERL Earnings

I wrote some simple perl script that creates an Net::LDAP::LDIFobject 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 includelines?

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.

Scoping out an even conciser fork idiom

r/perl

Published by /u/briandfoy on Tuesday 25 March 2025 11:31

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.)

How to make temp 2FA QR code in Perl based Web Application

Perl questions on StackOverflow

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.

Perl Integration with 64 Bit Office installs

Perl questions on StackOverflow

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.

perl binary on AIX shows relative paths with ldd

r/perl

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) 
submitted by /u/tseeling
[link] [comments]

Does Anyone Remember This Perl Lightning Talk?

r/perl

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.

submitted by /u/s-ro_mojosa
[link] [comments]

An introduction to App::ModuleBuildTiny part 1: setting things up

r/perl

Published by /u/briandfoy on Monday 24 March 2025 11:31

Perl 🐪 Weekly #713 - Why do companies migrate away from Perl?

dev.to #perl

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.

Articles

CPANSec retrospective 2024

Listing achievements of the CPANSec group all along 2024.

Create a static mirror of your DEV blog

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.

Learning GitHub Actions

GitHub Actions meets Map::Tube

Minimum Viable Rex

Read the article and then comment on Reddit.

END Block Hijacking

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.

Programming as text creation

Generating Perl code using ChatGPT.

Read Large File

Follow the discussion on reddit

An introduction to App::ModuleBuildTiny part 2: authoring

Discussion

2d Term::Animation collision detection issues

Sorting by use% - the diskspace on linux (df -h)

Perl Integration with 64 Bit Office installs

No type library matching "Microsoft Outlook" found at ../Perl/lib/Mail/Outlook.pm line 111

Split on unicode char leaves a trailing REPLACEMENT CHARACTER on split string

Some unicode characters for you: 🐪 🐫 🦙.

Data::Table::Text - why does it contain so much unrelated stuff?

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 - 314

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.

RECAP - The Weekly Challenge - 313

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.

Reverse Broken Keys for Letters

Breakdown analysis is something, I always prefer. It helps understand the flow, great work. Keep it up.

TWC313

Big fan of CPAN. Just love the compact solutions. Very crafty. well done.

Reverse Broken

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.

Perl Weekly Challenge: Week 313

The detailed analysis that you get to see in the post, truly remarkable. There is nothing left for imagination. Everything is covered, super cool.

Broken Down Letters

What an art of regex, incredible. You need to take a deep breath first before you look at it. Smart hacker, I would say.

Perl Weekly Challenge 313

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.

There Is Always a Regular Expression To Solve It

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.

Broken letters

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.

The Weekly Challenge #313

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.

Broken and Reversed

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.

Broken letters

For all Python fans, you must checkout this. You will not disappointed, I promise. Well done and keep it up.

Other

Terraform with Docker

There is no Perl in this article except the logo at the top of the web site.

Docker Volume

Weekly collections

NICEPERL's lists

Great CPAN modules released last week;
MetaCPAN weekly report.

Events

Dave Cross: Still Munging Data with Perl

Virtual Event

Boston.pm monthly meeting

Virtual event

Paris.pm monthly meeting

Paris, France

German Perl/Raku Workshop Conference 2025

Munich, Germany

Paris.pm monthly meeting

Paris, France

Paris.pm monthly meeting

Paris, France

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.

Create a static mirror of your DEV blog

blogs.perl.org

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.

Create a static mirror of your DEV blog

dev.to #perl

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.

RECAP - The Weekly Challenge - 313

The Weekly Challenge

Published on Monday 24 March 2025 00:00

Thank you Team PWC for your continuous support and encouragement.

The Weekly Challenge - 314

The Weekly Challenge

Published on Monday 24 March 2025 00:00

Welcome to the Week #314 of The Weekly Challenge.

Unlock PERL Tokens

Perl on Medium

Published by Brandon Fuller on Sunday 23 March 2025 19:32

Unlock PERL rewards by claiming via DappRadar with this guide.

Unlocking Additional Rewards and Network Security by LePerlinging Your Claiming PERL via DappRadar

The examples used here are from the weekly challenge problem statement and demonstrate the working solution.

Part 1: Broken Keys

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.

loop and compare 1 ⟩≡


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...

"ch-1.pl" 2


preamble 3
loop and compare 1
main 4

preamble 3 ⟩≡


use v5.40;

Fragment referenced in 2, 9.

The rest of the code just runs some simple tests.

main 4 ⟩≡


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.

Sample Run
$ perl perl/ch-1.pl 
1 
1 
0 
1
    

Part 2: Reverse Letters

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.

remove alphabetic characters 5 ⟩≡


my $a = [grep {$_ =~ m/[[:alpha:]]/} @{$s}];

Fragment referenced in 8.

Defines: $a 6, 7.

Uses: $s 8.

reverse the alphabetic characters 6 ⟩≡


$a = [reverse @{$a}];

Fragment referenced in 8.

Uses: $a 5.

combine the sorted alphabetic characters with the non-alphabetic characters 7 ⟩≡


{
my $c = shift @{$s};
push @{$reverse_letters}, $c if $c !~ m/[[:alpha:]]/;
push @{$reverse_letters}, shift @{$a} if $c =~ m/[[:alpha:]]/;
redo if @{$s} > 0;
}

Fragment referenced in 8.

Uses: $a 5, $reverse_letters 8, $s 8.

We’ll put everything together in a single subroutine.

reverse_letters: co-ordinates all the swaps and checks 8 ⟩≡


sub reverse_letters{
my($s) = (@_);
$s = [split //, $s];
my $reverse_letters = [];
remove alphabetic characters 5
reverse the alphabetic characters 6
combine the sorted alphabetic characters with the non-alphabetic characters 7
return join q//, @{$reverse_letters};
}

Fragment referenced in 9.

Defines: $reverse_letters 7, $s 5, 7.

The rest of the code drives some tests.

"ch-2.pl" 9


preamble 3
reverse_letters: co-ordinates all the swaps and checks 8
main 10

main 10 ⟩≡


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.

Sample Run
$ perl perl/ch-2.pl 
l-re?p 
yLk-e!e-w 
_e-!g_nel-la!h_c
    

References

The Weekly Challenge 313
Generated Code

(dxl) 13 great CPAN modules released last week

r/perl

Published by /u/niceperl on Sunday 23 March 2025 17:18

(dxl) 13 great CPAN modules released last week

Niceperl

Published by Unknown on Sunday 23 March 2025 18:17

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::ModuleBuildTiny - A standalone authoring tool for Module::Build::Tiny and Dist::Build
    • Version: 0.048 on 2025-03-20, with 12 votes
    • Previous CPAN version: 0.047 was 8 months, 8 days before
    • Author: LEONT
  2. App::Sqitch - Sensible database change management
    • Version: v1.5.1 on 2025-03-16, with 44 votes
    • Previous CPAN version: v1.5.0 was 2 months, 8 days before
    • Author: DWHEELER
  3. DateTime::Format::Natural - Parse informal natural language date/time strings
    • Version: 1.20 on 2025-03-22, with 18 votes
    • Previous CPAN version: 1.19 was 2 months, 17 days before
    • Author: SCHUBIGER
  4. DBIx::Class::Schema::Loader - Create a DBIx::Class::Schema based on a database
    • Version: 0.07053 on 2025-03-19, with 45 votes
    • Previous CPAN version: 0.07052 was 1 year, 2 months, 13 days before
    • Author: VEESH
  5. Firefox::Marionette - Automate the Firefox browser with the Marionette protocol
    • Version: 1.64 on 2025-03-20, with 16 votes
    • Previous CPAN version: 0.77 was 5 years, 8 months, 13 days before
    • Author: DDICK
  6. JSON::Validator - Validate data against a JSON schema
    • Version: 5.15 on 2025-03-16, with 35 votes
    • Previous CPAN version: 5.14 was 2 years, 10 days before
    • Author: JHTHORSEN
  7. Module::CoreList - what modules shipped with versions of perl
    • Version: 5.20250321 on 2025-03-21, with 44 votes
    • Previous CPAN version: 5.20250220 was 25 days before
    • Author: BINGOS
  8. Mojolicious::Plugin::OpenAPI - OpenAPI / Swagger plugin for Mojolicious
    • Version: 5.11 on 2025-03-18, with 46 votes
    • Previous CPAN version: 5.09 was 2 years, 26 days before
    • Author: JHTHORSEN
  9. OpenGL - Perl bindings to the OpenGL API, GLU, and GLUT/FreeGLUT
    • Version: 0.7004 on 2025-03-19, with 13 votes
    • Previous CPAN version: 0.70 was 8 years, 5 months, 11 days before
    • Author: ETJ
  10. Path::Tiny - File path utility
    • Version: 0.148 on 2025-03-17, with 191 votes
    • Previous CPAN version: 0.146 was 10 months, 9 days before
    • Author: DAGOLDEN
  11. Spreadsheet::Read - Meta-Wrapper for reading spreadsheet data
    • Version: 0.93 on 2025-03-17, with 31 votes
    • Previous CPAN version: 0.91 was 6 months, 21 days before
    • Author: HMBRAND
  12. SPVM - The SPVM Language
    • Version: 0.990049 on 2025-03-20, with 35 votes
    • Previous CPAN version: 0.990048 was 8 days before
    • Author: KIMOTO
  13. Sys::Virt - libvirt Perl API
    • Version: v11.1.0 on 2025-03-19, with 17 votes
    • Previous CPAN version: v11.0.0 was 1 month, 12 days before
    • Author: DANBERR

(dciii) metacpan weekly report

Niceperl

Published by Unknown on Sunday 23 March 2025 18:14

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:

Terraform with Docker

blogs.perl.org

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

Broken letters

dev.to #perl

Published by Simon Green on Sunday 23 March 2025 12:03

Weekly Challenge 313

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.

Challenge, My solutions

Task 1: Broken Keys

Task

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.

My solution

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';
}

Examples

$ ./ch-1.py perl perrrl
True

$ ./ch-1.py raku rrakuuuu
True

$ ./ch-1.py python perl
False

$ ./ch-1.py coffeescript cofffeescccript
True

Task 2: Reverse Letters

Task

You are given a string.

Write a script to reverse only the alphabetic characters in the string.

My solution

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 search
  • g 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.

Examples

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

How to Double Your PerlinX $PERL Rewards

Perl on Medium

Published by Mastering Secure HAPI Staking for Maximum Returns on Sunday 23 March 2025 06:51

Advanced Techniques to Maximize Your PerlinX $PERL Earnings

GitHub Actions meets Map::Tube

blogs.perl.org

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

The Weekly Challenge - Guest Contributions

The Weekly Challenge

Published on Sunday 23 March 2025 00:00

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, Kap, 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.

Terraform with Docker

The Weekly Challenge

Published on Sunday 23 March 2025 00:00

A few days ago, I shared my story about creating a Docker image for The Weekly Challenge website in this blog post.

How To Claim PERL Today

Perl on Medium

Published by Toby Wilson on Saturday 22 March 2025 12:57

Claim your PERL rewards via DappRadar and start earning today.

GitHub Actions

The Weekly Challenge

Published on Saturday 22 March 2025 00:00

I have been planning to learn GitHub Actions for a long time. I attended a talk by Dave Cross in 2023 at the Perl Conference in Toronto but when I came back home, I got distracted. Then came the book, GitHub Actions Essentials by Dave Cross, which reminded me again to get my act together and learn the tool.

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?

small .h trick for faster win32 interp compiles

Perl commits on GitHub

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.
Porting/release_managers_guide.pod: minor adjustments

- After installing, perl shouldn't need any `-Ilib` options.
- Hyperlinks should be clickable.

Prepare Module::Corelist for 5.41.11

Perl commits on GitHub

Published by mauke on Friday 21 March 2025 14:12

Prepare Module::Corelist for 5.41.11

Bump the perl version in various places for 5.41.11

Perl commits on GitHub

Published by mauke on Friday 21 March 2025 13:55

Bump the perl version in various places for 5.41.11

perl \s metacharacter not matching when empty lines exists

Perl questions on StackOverflow

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

PWC 312 Time to be random

dev.to #perl

Published by Bob Lied on Thursday 20 March 2025 14:47

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.

312 Task 1: Minimum Time

Circular typewriter

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

    • The pointer is at 'a' initially.
    • 1 sec - type the letter 'a'
    • 1 sec - move pointer clockwise to 'b'
    • 1 sec - type the letter 'b'
    • 1 sec - move pointer clockwise to 'c'
    • 1 sec - type the letter 'c'
  • Example 2: Input: $str = "bza" Output: 7

    • The pointer is at 'a' initially.
    • 1 sec - move pointer clockwise to 'b'
    • 1 sec - type the letter 'b'
    • 2 sec - move pointer counter-clockwise to 'z'
    • 1 sec - type the letter 'z'
    • 1 sec - move pointer clockwise to 'a'
    • 1 sec - type the letter 'a'
  • Example 3: Input: $str = "zjpc" Output: 34

The plan

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.

The code

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 characters
  • map ord($_) - ord("a") } Turn the characters into indices between 0 and 25
  • my @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.

312 Task 2: Balls and Boxes

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"

    • Output: 1
    • The given string describes there are 5 balls as below:
      • Box 0: Green(G0), Red(R0), Blue(B0) => 3 balls
      • Box 1: Blue(B1) => 1 ball
      • Box 2: Red(R2) => 1 ball
  • Example 2 Input: $str = "G1R3R6B3G6B1B6R1G3"

    • Output: 3
    • The given string describes there are 9 balls as below:
      • Box 1: Red(R1), Blue(B1), Green(G1) => 3 balls
      • Box 3: Red(R3), Blue(B3), Green(G3) => 3 balls
      • Box 6: Red(R6), Blue(B6), Green(G6) => 3 balls
  • Example 3 Input: $str = "B3B2G1B3"

    • Output: 0
    • Box 1: Green(G1) => 1 ball
    • Box 2: Blue(B2) => 1 ball
    • Box 3: Blue(B3) => 2 balls

The plan

We'll need to split up the input string and create a representation of balls in boxes. Two ways come to me quickly

  • an array of 10 strings, one for each box. The G, B, or R from the input is appended onto its box.
  • an array of 10 lookup tables. Each box has a little hash that counts the number of G, B, or R balls from the input.

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.

The code, with regular expressions

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.

The code, without regular expressions

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.

The code, with a hash

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.

The performance

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.

Programming as text creation

dev.to #perl

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.

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:

  • If cleanup is necessary, provide (and document) a cleanup() method
  • Use a destructor (DESTROY) in an object-oriented module

Modules should provide functionality - not take control of your script’s shutdown behavior.

Why Would Someone Put an END Block in a Perl Module?

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:

  • A new() method that instantiates your wrapper
  • An init() method that encapsulates the common startup operations with options to control whether some are executed or not
  • A run() method that executes the functionality for the script
  • A finalize() method for executing cleanup procedures
  • POD that describes the common functionality provided as well as any options for controlling their invocation

All 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.

How Can We Take Back Control?

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:

  • The module had an END block baked into it
  • This END block printed debug messages to STDERR while doing other cleanup operations
  • Worse, it ran unconditionally when my script terminated

The Naive Approach

My 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.

A Better Approach

Here’s what I want to happen:

  • Prevent any rogue END block from executing.
  • Handle errors gracefully.
  • 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 );
}
  • Bypasses all END blocks – Since POSIX::_exit() terminates the process immediately
  • Handles errors cleanly – If main() throws an exception, we log it without modifying the message
  • Forces explicit return values – If main() forgets to return a status, we default to 1, ensuring no silent failures.
  • Future maintainers will see exactly what’s happening

Caveat Emptor

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.

The examples used here are from the weekly challenge problem statement and demonstrate the working solution.

Part 1: Minimum Time

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.

"ch-1.pl" 1


preamble 2
minimum time to type 3
main 4

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.

preamble 2 ⟩≡


use v5.40;

Fragment referenced in 1, 6.

All the work is in one subroutine. We use the ASCII values of each character to compute the new value.

minimum time to type 3 ⟩≡


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 4 ⟩≡


MAIN:{
say minimum_time q/abc/;
say minimum_time q/bza/;
say minimum_time q/zjpc/;
}

Fragment referenced in 1.

Sample Run
$ perl perl/ch-1.pl 
5 
7 
34
    

Part 2: Balls and Boxes

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;
}

"ch-2.pl" 6


preamble 2
use Ch2;
parse the input and check the results 7
main 8

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.

parse the input and check the results 7 ⟩≡


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.

main 8 ⟩≡


MAIN:{
say parse_boxes $ARGV[0];
}

Fragment referenced in 6.

Sample Run
$ 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
    

References

The Weekly Challenge 312
Generated Code

(dxxxix) 9 great CPAN modules released last week

Niceperl

Published by Unknown on Sunday 16 March 2025 00:11

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.424 on 2025-03-09, with 14 votes
    • Previous CPAN version: 2.423 was 1 month, 13 days before
    • Author: KUERBIS
  2. App::Netdisco - An open source web-based network management tool.
    • Version: 2.084001 on 2025-03-09, with 17 votes
    • Previous CPAN version: 2.084000 was 4 days before
    • Author: OLIVER
  3. ExtUtils::MakeMaker - Create a module Makefile
    • Version: 7.72 on 2025-03-14, with 60 votes
    • Previous CPAN version: 7.70 was 1 year, 11 months, 19 days before
    • Author: BINGOS
  4. Firefox::Marionette - Automate the Firefox browser with the Marionette protocol
    • Version: 1.63 on 2025-03-09, with 16 votes
    • Previous CPAN version: 0.77 was 5 years, 8 months, 2 days before
    • Author: DDICK
  5. Image::ExifTool - Read and write meta information
    • Version: 13.25 on 2025-03-11, with 43 votes
    • Previous CPAN version: 13.10 was 2 months, 22 days before
    • Author: EXIFTOOL
  6. OpenGL - Perl bindings to the OpenGL API, GLU, and GLUT/FreeGLUT
    • Version: 0.7002 on 2025-03-10, with 13 votes
    • Previous CPAN version: 0.70 was 8 years, 5 months, 2 days before
    • Author: ETJ
  7. Perl::Tidy - indent and reformat perl scripts
    • Version: 20250311 on 2025-03-11, with 142 votes
    • Previous CPAN version: 20250214 was 26 days before
    • Author: SHANCOCK
  8. Prima - a Perl graphic toolkit
    • Version: 1.76 on 2025-03-12, with 44 votes
    • Previous CPAN version: 1.75 was 2 months, 22 days before
    • Author: KARASIK
  9. SPVM - The SPVM Language
    • Version: 0.990048 on 2025-03-12, with 35 votes
    • Previous CPAN version: 0.990045 was 19 days before
    • Author: KIMOTO

Introduction

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.


The Apache 2.2 vs. 2.4 Behavior Shift

How Apache 2.2 Handled Directory Requests

  • If a user requested /dir without a trailing slash, Apache would automatically redirect them to /dir/.
  • Apache would then serve the directory’s index.html (or any file specified by DirectoryIndex).
  • This behavior was automatic and required no additional configuration.

What Changed in Apache 2.4

  • When DirectorySlash Off is set, Apache stops auto-redirecting directories.
  • Instead of treating /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.
  • Apache does not reprocess DirectoryIndex after an internal rewrite.

The Internal Rewrite Attempt

Our Initial Idea

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:

  • While this internally rewrites the request, Apache does not reprocess DirectoryIndex after the rewrite.
  • If DirectoryIndex is not explicitly defined for each directory, Apache still refuses to serve the file and throws a 403 Forbidden.
  • Unlike Apache 2.2, Apache 2.4 treats /dir as a raw file request instead of checking for an index page.

The Per-Directory Fix (Which Also Fails)

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>

Why This Also Fails:

  • Apache does not reprocess DirectoryIndex after an internal rewrite. Even though DirectoryIndex index.roc is explicitly set, Apache never reaches this directive after rewriting /setup to /setup/.
  • Apache still treats /setup/ as an empty directory, leading to a 403 Forbidden error.
  • The only way to make this work per directory would be to use an external redirect to force a new request cycle.

This means that even if we were willing to configure every directory manually, it still wouldn’t work as expected.

FallbackResource (Why This Was a Dead End)

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>

Why This Makes No Sense

  • FallbackResource is designed to handle 404 Not Found errors, not 403 Forbidden errors.
  • Since Apache already recognizes /setup/ as a valid directory but refuses to serve it, FallbackResource is never triggered.
  • This does not address the fundamental issue that Apache does not reprocess DirectoryIndex after an internal rewrite.

This was a red herring in our troubleshooting FallbackResource was never a viable solution.


Sledge Hammer Approach: Direct Rewrite to the Index File

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]

It works…

  • It completely avoids Apache’s broken DirectoryIndex handling in Apache 2.4.
  • No need for DirectorySlash Off, since the request is rewritten directly to a file.
  • It prevents the 403 Forbidden issue because Apache is no longer serving a bare directory.

…but it’s not ideal

  • Every directory would need an explicit rewrite rule to its corresponding index file.
  • If different directories use different index files (index.html, index.php, etc.), additional rules would be required.
  • This does not scale well without complex conditional logic.

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.

Why the External Redirect is the Best Approach

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]

Why This Works Perfectly

  • Redirects /dir to /dir/ before Apache even tries to serve it.
  • Preserves DirectoryIndex behavior globally, just like Apache 2.2.
  • No need for per-directory configuration.
  • Ensures SEO-friendly canonical URLs with the correct trailing slash.

Conclusion

So, can we solve with an internal redirect?

  • NO! … because Apache does not reprocess DirectoryIndex after an internal rewrite.
  • Even explicit per-directory 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.

Lessons Learned

  • Apache 2.4 fundamentally changed how it handles directory requests when DirectorySlash Off is set.
  • Internal rewrites cannot fully restore Apache 2.2 behavior because Apache does not restart request processing after a rewrite.
  • The only way to ensure correct behavior is to use an external redirect before Apache attempts to serve the request.

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…

Why Deriv Supports the Perl Ecosystem

perl.com

Published on Friday 14 March 2025 06:00

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.

Architecture Built for Scale

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.

Engineering Milestones

Here are some of the activities we’ve done with Perl:

  • Engineered microservices using Myriad’s framework
  • Created real-time trading systems with Net::Async
  • Published open-source integrations for Postgres and Redis
  • Developed proprietary market analysis tools still in daily use

These implementations demonstrate Perl’s capacity to support robust, long-term solutions in demanding technical environments.

Investing in Shared Infrastructure

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:

  • Support for MetaCPAN’s essential developer resources
  • Participation in community-driven knowledge sharing
  • Commitment to CPAN’s maintenance standards

“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.”

Our Open Source Commitment

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.

How to Fix Apache 2.4 Broken Directory Requests

Introduction

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

Apache 2.4 Drops the Port When Redirecting Directories!

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!

  • Expected Redirect (Apache 2.2):\ http://yourserver:8080/setup => http://yourserver:8080/setup/
  • Actual Redirect (Apache 2.4, Broken):\ 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.

Investigating the Issue

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.

Workarounds

Several workarounds exist, but they don’t work in our example.

  • Disabling DirectorySlash: Prevents redirects but causes 403 Forbidden errors when accessing directories.
  • Using FallbackResource: Works, but misroutes unrelated requests.
  • Hardcoding the port in rewrite rules: Not flexible across different environments.

Instead, we need a solution that dynamically preserves the port when necessary.

The Fix

To restore Apache 2.2 behavior, we can use a rewrite rule that only preserves the port if it was in the original request.

Apache 2.4 Fix: Port-Preserving Rewrite Rule

<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>

Explanation

  • Automatically appends a missing trailing slash (/setup => /setup/).
  • Preserves the port only if it’s non-standard (!=80, !=443)
  • Avoids hardcoding :8080, making it flexible for any non-standard port
  • Restores Apache 2.2 behavior while keeping things modern and correct.

Example: Running Apache in Docker on EC2 via SSH Tunnel

The Setup (see previous blog)

  1. Docker container running Apache on port 80 inside an EC2 instance.
  2. Firewall rules allow only my home IP to access the server.
  3. SSH tunnel (jump box) forwards port 80 securely.
  4. Chromebook’s SSH settings forward port 8080 locally to 80 on the jump box.

How the Fix Helps

  • Previously, /setup redirected externally without the port, causing failures.
  • This fix use mod_rewrite and a RewriteRule that ensures that port 8080 is preserved

Conclusion

Apache 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.

Postamble

Hmmmm…maybe we can use internal redirects instead of an external redirect??? Stay tuned.

Introduction

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:

Apache does not restart the request cycle after an internal rewrite, and this can break expected behaviors like 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.


What Happens When Apache Internally Rewrites a Request?

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.


The Key Issue: Apache Does Not Restart Request Processing After an Internal Rewrite

Unlike what many admins assume, Apache does not start over after an internal rewrite.

How Apache Processes Requests (Simplified)

  1. The request arrives (/setup).
  2. Apache processes mod_rewrite.
  3. Apache determines how to serve the request.
  4. If an index file (index.html, index.php, etc.) exists, DirectoryIndex resolves it.

Why Internal Rewrites Don’t Restart Processing

  • Apache processes mod_rewrite before it checks DirectoryIndex.
  • Once a rewrite occurs, Apache continues processing from where it left off.
  • This means it does not re-check DirectoryIndex after an internal rewrite.
  • Instead, it sees /setup/ as an empty directory with no default file and denies access with 403 Forbidden.

Is This a Bug or a Feature?

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:

  • After an internal rewrite, Apache treated the rewritten request as a brand-new request.
  • As a result, it re-evaluated DirectoryIndex and correctly served index.html, index.php, or any configured default file.
  • Since 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.

Why It’s Likely an Intentional Feature

  • In Apache 2.2, some rewrites did restart the request cycle, which was seen as inefficient.
  • In Apache 2.4, request processing was optimized for performance, meaning it does not restart after an internal rewrite.
  • The behavior is consistent across different Apache 2.4 installations.
  • Some discussions in Apache’s mailing lists and bug tracker mention this as “expected behavior.”

Why This is Still a Problem

  • This behavior is not explicitly documented in mod_rewrite or DirectoryIndex docs.
  • Most admins expect Apache to reprocess the request fully after a rewrite.
  • The lack of clarity leads to confusion and wasted debugging time.

Implications for Apache 2.4 Users

1. Mod_Rewrite Behavior is Different From What Many Assume

  • Internal rewrites do not restart request processing.
  • DirectoryIndex is only evaluated once, before the rewrite happens.
  • This is not obvious from Apache’s documentation.

2. The Only Reliable Fix is an External Redirect

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.

3. Apache Should Improve Its Documentation

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.


Conclusion: A Feature, But a Poorly Documented One

  • The fact that Apache does not restart processing after an internal rewrite is likely an intentional design choice.
  • However, this is not well-documented, leading to confusion.
  • The only solution remains an external redirect to force a fresh request cycle.
  • We believe Apache should update its documentation to reflect this behavior more clearly.

CPANSec retrospective 2024

CPAN Security Group

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!

Common Vulnerabilities and Exposures (CVEs)

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.

Vulnerable Spreadsheet Parsing modules

The start of the year was marked by vulnerabilities reported for Spreadsheet::ParseExcel:

Insecure modes of CPAN installers

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):

Other

Similarly, a CVE was emitted for the POSIX::2008 module:

Improving CVE tooling

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.

CPANSec as a CVE Numbering Authority (CNA)

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.

Introduced a SECURITY Policy template

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.

Study on Random Number generation for Security

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.

Working on “TLS in core”

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.

Software Bill Of Materials (SBOM)

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.

Reviewing CPAN for supply chain attacks

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.

Pentesting PAUSE

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.

Outreach

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.

Other

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.

Who we are?

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

Final words

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 :)

The examples used here are from the weekly challenge problem statement and demonstrate the working solution.

Part 1: Upper Lower

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.

"ch-1.pl" 1


preamble 2
upper lower calculations 3
main 4

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.

preamble 2 ⟩≡


use v5.38;

Fragment referenced in 1, 5.

All the work is in one subroutine. We use the ASCII values of each character to compute the new value.

upper lower calculations 3 ⟩≡


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 4 ⟩≡


MAIN:{
say upper_lower q/pERl/;
say upper_lower q/rakU/;
say upper_lower q/PyThOn/;
}

Fragment referenced in 1.

Sample Run
$ perl perl/ch-1.pl 
PerL 
RAKu 
pYtHoN
    

Part 2: Group Digit Sum

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.

"ch-2.pl" 5


preamble 2
group digit sum 9
main 10

To solve this problem we need to do the following

1.
divide the list into groups of the given size
2.
compute the sums
3.
recombine
4.
repeat as needed

Let’s look at each of those pieces individually and then combine them together into one subroutine.

divide the list into groups of the given size 6 ⟩≡


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;

Fragment referenced in 9.

Defines: $groups 7.

Uses: $c 9, $size 9.

compute the sums 7 ⟩≡


my $sums = [];
do{
my $sum = unpack(q/%32I*/, pack(q/I*/, @{$_}));
push @{$sums}, $sum;
} for @{$groups};

Fragment referenced in 9.

Defines: $sums 8.

Uses: $groups 6.

recombine 8 ⟩≡


$s = join q//, @{$sums};
return $s if length $s <= $size;
group_digit_sum($s, $size);

Fragment referenced in 9.

Uses: $size 9, $sums 7.

With that work take care of, let’s combine all these pieces into one subroutine.

group digit sum 9 ⟩≡


sub group_digit_sum{
my($s, $size) = @_;
my $c = [split //, $s];
divide the list into groups of the given size 6
compute the sums 7
recombine 8
}

Fragment referenced in 5.

Defines: $c 6, $size 6, 8.

Finally, here’s a few tests to confirm everything is working right.

main 10 ⟩≡


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.

Sample Run
$ perl perl/ch-2.pl 
359 
76 
162
    

References

The Weekly Challenge 311
Generated Code

(dxxxviii) 9 great CPAN modules released last week

Niceperl

Published by Unknown on Saturday 08 March 2025 23:09

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::Netdisco - An open source web-based network management tool.
    • Version: 2.084000 on 2025-03-05, with 17 votes
    • Previous CPAN version: 2.083001 was 27 days before
    • Author: OLIVER
  2. App::perlimports - Make implicit imports explicit
    • Version: 0.000056 on 2025-03-02, with 19 votes
    • Previous CPAN version: 0.000055 was 7 months, 29 days before
    • Author: OALDERS
  3. Date::Manip - Date manipulation routines
    • Version: 6.97 on 2025-03-02, with 20 votes
    • Previous CPAN version: 6.96 was 2 months, 29 days before
    • Author: SBECK
  4. Graph - graph data structures and algorithms
    • Version: 0.9734 on 2025-03-01, with 27 votes
    • Previous CPAN version: 0.9704 was 9 years, 4 months, 25 days before
    • Author: ETJ
  5. Imager - Perl extension for Generating 24 bit Images
    • Version: 1.027 on 2025-03-02, with 68 votes
    • Previous CPAN version: 1.025 was 3 months, 16 days before
    • Author: TONYC
  6. Math::BigInt - Pure Perl module to test Math::BigInt with scalars
    • Version: 2.004001 on 2025-03-02, with 13 votes
    • Previous CPAN version: 2.003004 was 1 month, 10 days before
    • Author: PJACKLAM
  7. PDL::Stats - a collection of statistics modules in Perl Data Language, with a quick-start guide for non-PDL people.
    • Version: 0.855 on 2025-03-06, with 16 votes
    • Previous CPAN version: 0.854 was 9 days before
    • Author: ETJ
  8. Term::Choose - Choose items from a list interactively.
    • Version: 1.768 on 2025-03-05, with 15 votes
    • Previous CPAN version: 1.767 was 4 months, 8 days before
    • Author: KUERBIS
  9. Text::CSV - comma-separated values manipulator (using XS or PurePerl)
    • Version: 2.06 on 2025-03-02, with 81 votes
    • Previous CPAN version: 2.05 was 1 month, 22 days before
    • Author: ISHIGAKI

(dcii) metacpan weekly report - DBI

Niceperl

Published by Unknown on Saturday 08 March 2025 23:04

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:

Using a Chromebook for Remote Web Development

Introduction

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.

Motivation

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.

Network Setup Overview

In this setup:

  • The Chromebook runs Linux and connects via SSH to the bastion host.
  • The bastion host acts as an intermediary, forwarding requests to the private EC2 development server.
  • The EC2 instance is firewalled and only accessible from the bastion host.
  • Port 80 on the EC2 instance is mapped to port 8080 locally on the Chromebook through the SSH tunnel. You’ll need to set that up on your Chromebook in the Linux development environment settings.

chromebook setup

Network Diagram

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      |
   +--------------+    +--------------+    +--------------+

Setting Up the SSH Tunnel

To create an SSH tunnel through the bastion host:

ssh -N -L 8080:EC2_PRIVATE_IP:80 user@bastion-host

Explanation:

  • -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.

Making It Persistent on Your Chromebook

To maintain the tunnel connection automatically:

  1. Use an SSH config file (~/.ssh/config):
Host bastion
    HostName bastion-host
    User your-user
    IdentityFile ~/.ssh/id_rsa
    LocalForward 8080 EC2_PRIVATE_IP:80
    ServerAliveInterval 60
    ServerAliveCountMax 3
  1. Start the tunnel in the background:
ssh -fN bastion
  1. Verify it is working:
curl -I http://localhost:8080

You should see a response from your EC2 instance’s web server.

Integrating with Docker on EC2

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.

Final Thoughts

This setup allows you to securely access a remote development environment from a Chromebook, leveraging SSH tunneling through a bastion host.

  • Why This Works:
    • Keeps the EC2 instance private while still making it accessible for development.
    • Allows seamless local access (localhost:8080) to a remote web app.
    • Works even when using strict firewall rules.

Now you can develop on remote servers with a Chromebook, as if they were local!

From Code to Community: Sponsoring TPRC 2025

perl.com

Published on Sunday 02 March 2025 17:27

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.

About 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.

Why Sponsor?

  • Connect with talented developers in the Perl and Raku ecosystem
  • Support open source development and community growth
  • Increase your brand visibility in the developer community
  • Contribute to the sustainability of essential programming languages
  • Help foster technological innovation and knowledge sharing

Conference Details

  • 3 days of content including training day
  • 80+ expected attendees
  • Multiple tracks of technical content
  • Professional networking opportunities
  • Community-building events

Sponsorship Tiers

Platinum Sponsor ($6,000)

  • Only 1 sponsorship is available at this level
  • Premium logo placement on conference website
  • This donation qualifies your organization to be a Bronze Level Sponsor of The Perl and Raku Foundation
  • 5-minute speaking slot during opening ceremony
  • 2 complimentary conference passes
  • Priority choice of rollup banner placement
  • Logo prominently displayed on conference badges
  • First choice of major named sponsorship (Conference Dinner, T-shirts, or Swag Bags)
  • Logo on main stage backdrop and conference banners
  • Social media promotion
  • All benefits of lower tiers

Gold Sponsor ($4,000)

  • Logo on all conference materials
  • One complimentary conference pass
  • Rollup banner on display
  • Choice of named sponsorship (Lunch or Snacks)
  • Logo on backdrop and banners
  • Dedicated social media recognition
  • All benefits of lower tiers

Silver Sponsor ($2,000)

  • Logo on conference website
  • Logo on backdrop and banners
  • Choice of smaller named sponsorship (Beverage Bars)
  • Social media mention
  • All benefits of lower tier

Bronze Sponsor ($1,000)

  • Name/logo on conference website
  • Name/logo on backdrop and banners

Additional Sponsorship Opportunities

Technology Sponsor ($2,000 value)

  • Recognition as Official Technology Provider
  • Provide WiFi/AV equipment
  • Special acknowledgment during technical sessions

Community Sponsor ($1,500)

  • Recognition as Open Source Community Supporter
  • Special acknowledgement during community segments
  • Opportunity to present open source initiatives

Charity Raffle Sponsor

Support our local community by contributing to our charity raffle benefiting a local Greenville/Spartanburg area food bank:

  • Donate prizes (or funds for prizes) up to $850 in total value
  • Recognition during raffle drawing
  • Special mention in conference materials

All Sponsors Receive

  • Logo/name in Update::Daily conference newsletter sidebar
  • Opportunity to provide materials for conference swag bags
  • Recognition during opening and closing ceremonies
  • Listed on conference website sponsor page
  • Mentioned in conference social media

Named Sponsorship Opportunities

Exclusive naming rights available for:

  • Conference Dinner ($2,000) - Signage on tables and buffet
  • Conference Swag Bags ($1,500) - Logo on bags
  • Conference T-Shirts ($1,500) - Logo on sleeve
  • Lunches ($1,500) - Signage at pickup and on menu tickets
  • Snacks ($1,000) - Signage at snack bar
  • Beverage Bars ($500) - Signage on beverage stations
  • Conference Dinner Bar ($500) - Signage on bar
  • Update::Daily Printing ($200) - Logo on masthead

About The Perl and Raku Foundation

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.

Contact Information

For more information on to become a sponsor, please contact: olaf@perlfoundation.org

The examples used here are from the weekly challenge problem statement and demonstrate the working solution.

Part 1: Arrays Intersection

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.

"ch-1.pl" 1


preamble 2
compute array intersections. 3
main 4

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.

preamble 2 ⟩≡


use v5.38;

Fragment referenced in 1, 5.

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.

compute array intersections. 3 ⟩≡


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 4 ⟩≡


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.

Sample Run
$ perl perl/ch-1.pl 
1, 4 
2 
n/a
    

Part 2: Sort Odd Even

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.

"ch-2.pl" 5


preamble 2
sort odd/even. All the code for solving the problem is here. 6
main 7

To solve this problem we need to do the following

1.
seperate the odd and even numbers
2.
sort the two lists as directed
3.
combine the results

Much of this work can be written concisely using map and grep.

sort odd/even. All the code for solving the problem is here. 6 ⟩≡


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 7 ⟩≡


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.

Sample Run
$ perl perl/ch-2.pl 
2, 3, 4, 1 
3, 1 
2, 3, 4, 1, 5
    

References

The Weekly Challenge 310
Generated Code

CPANSec is CNA for Perl and the CPAN ecosystem

CPAN Security Group

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.

Report Vulnerability

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.

Contact Us

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.