We have a program written in Perl that since we updated to debian 12 doesn't work.

The program reads a line to translate, sends this information to the server, and returns the string with the translation. But the while goes into an endless loop and the program times out. This is the code:

use Net::SSH2;
use CGI;

//connect db
$query = new CGI;
$lnTesto = $query->param('lnText');
$lnTrad = $query->param('lnTrad');
$testo = "ciao";
//control input to tradution it/eng 
if (length($lnText) == 0) {
    $lnText = "It";
if (length($lnTrad) == 0){
    $lnTrad = "En";

    //connect to server translator debian

    my $ssh2 = Net::SSH2->new();
    $ssh2->connect('IP DEBIAN WITH TRANSLATOR');
    $ssh2->auth(username => 'user', password => 'password');
    my $channel = $ssh2->channel() or $ssh2->die_with_error;
    //send the comand to the server with the string to tradution

    $cmd = "trans $breve" . lc($lnTesto) . ":" . lc($lnTrad) . " " . $vr . $testo. $vr; 
    #$channel->exec("trans it:en '$testo'")
      or $ssh2->die_with_error;
    $traduz = ""; 
    // close connection
    while (<$channel>) {
      $traduz = $traduz . $_ ;

Maintaining Perl (Tony Cook) May 2024

Perl Foundation News

Published by alh on Monday 24 June 2024 08:48

Tony writes:

``` Hours] [Activity] 2024/05/01 Wednesday 0.93 review smoke reports 0.08 check cygwin dll conflict revert results and open PR 22187

2.87 C++ header testing again


2024/05/02 Thursday 2.90 C++ header testing: test code

1.23 more C++ header testing test code


2024/05/06 Monday 0.17 github notifications 0.88 #22195 start prep of test env 1.63 more C++ header testing, actually test perl headers, cross check on win32 and fix 2 issues

0.45 #22195 try to reproduce, comment


2024/05/07 Tuesday 0.70 #22195 follow-up tests on extra info, reproduce, work on reproducing from a source build 1.30 #22195 get more symbols, failed to reproduce with build from source 0.32 c++ header testing: improve failure reports and re-push

for CI


2024/05/08 Wednesday 0.95 c++ header testing: check CI results, more improve error reporting, fix strange cygwin hints, for now fail if no C++ compiler found 0.80 #21877 try to understand the unexpected leak 0.83 #22191 review, research and approve

0.45 #22197 review, research and approve


2024/05/09 Thursday 2.75 c++ header testing: check CI results, tests with unusual compilers, Sun CC doesn’t built a simple C++11 program, get intel oneapi compiler installed on linux and fix minor



2024/05/13 Monday 0.72 github notifications 0.23 #22208 review and comment 0.83 c++ header testing: test even if we don’t find -std values 0.48 look into intel compiler test failures 0.47 gather info and open #22209

0.47 c++ header testing: managed to get classic icc, testing


2024/05/14 Tuesday 0.63 #22155 research and comment 0.22 #22208 review updates and approve 0.47 #22200 review and approve 0.45 #22202 review, research and approve

0.55 #22163 review code and comment


2024/05/15 Wednesday 0.08 #22163 brief followup 0.78 #22211 review discussion, research, comment 3.07 c++ header testing: handle extra flags in cc, and cc being

g++, clang++, push for smoke


2024/05/16 Thursday 1.97 #22211 review discussion, testing, comment

2.77 #22199 testing, research and comment


2024/05/20 Monday 1.62 #21529 review, research and comments 0.23 #22199 review response and close 0.67 C++ header testing: cleanup and polish, push for smoke 0.40 C++ header testing: commit message cleanup, push for smokes/CI

1.10 #22211 interpret very old code


2024/05/21 Tuesday 0.47 github notifications 0.67 #22206 review ticket, testing and comment 1.67 #22207 review ticket, work on a fix and push for CI

0.90 #22209 testing, hints update and make PR #22226


2024/05/22 Wednesday 0.45 #22230 review, research and comment 0.33 #22223 review, research and comment 0.32 #22229 review, research and comment 0.08 #22207 check CI results and make PR #22231 0.23 C++ header testing: check smoke results and open PR #22232 1.48 #22211 research, testing, fixes 0.27 comment on p5p “not constant folding LINE

2.55 #22211 testing, research, balding, fixes, testing


2024/05/23 Thursday 0.27 #22163 read new discussion, consider comment 1.52 #22223 review discussion, research, debugging 1.15 #22223 more debugging, comment 1.33 #22211 testing, minor fixes, more testing and minor fixes

(and need more testing)


2024/05/24 Friday

0.68 #22241 research and comment


2024/05/27 Monday 2.15 #22211 more testing 0.83 debug Win32/MSVC test failure - turned out to be perl- win32/win32#36 0.08 #22211 push for smoke/CI

1.13 #22230 testing and reproduce, code review


2024/05/28 Tuesday 1.18 #22230 more code review, testing

0.80 #22230 research


2024/05/29 Wednesday

0.85 #22230 debugging


2024/05/30 Thursday 1.90 #22230 check for copying, more review

2.90 #22230 debugging


Which I calculate is 63.64 hours. Approximately 21 tickets were reviewed or worked on. ```

Maintaining Perl (Tony Cook) April 2024

Perl Foundation News

Published by alh on Monday 24 June 2024 08:40

Tony writes: ``` [Hours] [Activity] 2024/04/02 Tuesday 0.30 #22115 review and approve 0.75 #22114 review, research (and it be a compile-time constant, hard to tell)

0.40 #22113 review, research, comments


2024/04/03 Wednesday 0.67 #22110 review and approve 1.20 #22116 review, testing, coverage testing and comment 0.32 #22081 review latest changes and approve 0.33 #22113 review updates and approve 0.68 #21877 debugging. find an issue and push for CI 1.88 #21550 testing, failed build with -Dstatic_ext=re, work on



2024/04/04 Thursday 1.10 #22116 review changes, testing, approve 1.28 #22119 review, testing, comments 0.12 #21877 rebase to fix cygwin issue 1.07 #21550 more testing, push for CI 0.72 #21877 clean up, start a cygwin build to check against the original problem

0.15 #21877 performance tests, make PR 22120


2024/04/08 Monday 0.23 #21877 bump XS::APItest version, testing 0.77 #22122 review, try to understand it 0.88 #22121 testing, debugging, long comment 0.43 look into build warnings: HEK_FLAGS array subscript warning 0.68 fix HEK_FLAGS() warning, fix NULL in %s warning, push 202404-warning-cleanup for CI

1.97 perlhacktips: profiler documentation, other tools


2024/04/09 Tuesday 0.08 build warnings: check CI and make PR 22128 0.12 perlhacktips: some clean up, push for CI 1.47 #16607 work on making hwm checks DEBUGGING independent

1.12 #16607 testing, push for CI


2024/04/10 Wednesday 0.13 #16607 check CI results, make #22131 0.55 #22093 testing, review changes, approve 1.00 #21877 try to track down cause of the leak the cow check prevents 0.90 #21877 add some sv_setsv_cow() documentation 0.33 #16607 comment

1.70 #21724 work on a fix, testing, push for CI


2024/04/11 Thursday 0.43 #21724 resolve CI failure 0.93 #22133 review discussion, testing 0.65 look into Configure noise, work up a change and push for CI 0.10 #21724 review new CI results and make PR 22134 0.65 #22132 review discussion, look over freebsd ports, research amdfam10 clang issues (didn’t find anything relevant) 0.30 #22132 and related p5p message, comments 0.08 configure noise: check CI results, open PR 22135 0.43 #12783 testing, appeared to be fixed, mark closable? 0.48 #12782 review, research and mark closable? 0.47 #12744 review discussion and close

0.60 #12717 transfer tickets linked to this meta ticket across


2024/04/15 Monday 0.43 github notifications 0.47 #22131 re-check and apply to blead 1.00 #22142 long comment 0.23 #22129 recheck and apply to blead 0.08 #22128 briefly comment, apply to blead 0.88 #22132 setup to reproduce and reproduce

2.82 #22132 debugging, research, comment


2024/04/16 Tuesday 1.08 #22145 work on a fix, push for CI 0.67 #22132 debugging 1.70 #22132 debugging, try to make a simple reproducer

0.12 #22146 review CI results and make PR 22146


2024/04/17 Wednesday 0.15 #22142 recheck and apply to blead 1.18 #22132 get a simple reproducer, open llvm/llvm- projetct#89008 1.13 look into more build warnings 0.98 hints noise on NetBSD from list, research, testing, fix, make PR 22152

0.92 perldelta updates, push for CI


2024/04/18 Thursday 0.08 perldelta updates: check CI, open PR 22153 0.98 look into build warnings some more, fix the other one and push for CI 1.30 c++ header testing - find a C++ compiler 3.03 c++ header testing - more find a C++ compiler, testing,

next steps...?


2024/04/19 Friday 0.35 #22154 follow-up

0.78 #21611 research, long comment


2024/04/22 Monday

2.43 #22160 test this (with much Windows messing about)


2024/04/23 Tuesday 2.08 #22159 work up a fix, testing, fix the fix, push to PR 22166 3.10 #22159 diag test fix, maybe do the clean up instead of



2024/04/24 Wednesday 1.22 #22159 apply various PRs, perldelta, comment, open #22169 1.17 look into blead smoke failures, looking smoke failure reported in #22125 1.25 #22125 testing, comment, try some fixes, comment again 1.70 more smokes: dfly bsd failures, cannot reproduce, ask for

info, look at win32 failures, can’t reproduce so far


2024/04/25 Thursday 0.67 more smokes, open metaconfig #89 0.37 #22170 research and comment 0.42 #22171 review and approve

1.02 #22121 try changing to UNOP_AUX


2024/04/29 Monday 2.50 dfly bsd failures: setup and try to reproduce on UFS, try to reproduce locale test failures, and reproduce, work out the issue and open PR 22183 1.32 #22125 why does perl itself build, but not the embed_test,

testing, long-ish comment


2024/04/30 Tuesday 0.08 #22183 it’s approved, minor, platform specific and fixes a serious problem, apply to blead 0.90 #22125 research and comment 0.68 #22182 review and approve 0.15 #22173 review and comment 0.38 #22104 check if version bump fixed this, looks like it did, prepare revert commit for CI and push for CI

0.52 #22121 more unop_aux


Which I calculate is 70.77 hours.

Approximately 38 tickets were reviewed or worked on, and 6 patches were applied. ```

Max Maischein dev release of Perl 5.41.7

Kelp version 2 released!


Published by /u/brtastic on Monday 24 June 2024 05:30

Bump version of ExtUtils::ParseXS

Perl commits on GitHub

Published by Leont on Monday 24 June 2024 04:30

Bump version of ExtUtils::ParseXS

Simplify global typemap

Perl commits on GitHub

Published by Leont on Monday 24 June 2024 04:30

Simplify global typemap
Use alert control character as quoting character in INPUT templates

This way, one no longer needs to escape double quotes inside an input

Parsexs has done this for OUTPUT templates since the very beginning, I
can't find any reason for why we weren't also doing it for INPUT

bytes_from_utf8_loc() is no longer experimental

Perl commits on GitHub

Published by khwilliamson on Monday 24 June 2024 03:41

bytes_from_utf8_loc() is no longer experimental

commit 06cd43176585d5d116c8eaea20e1df5ca7105b05 removed this mark from
plain bytes_from_utf8().  This should follow suit.

This Week in PSC (152) | 2024-06-20


Published by Perl Steering Council on Monday 24 June 2024 02:14

Just Graham and Philippe this time.

We talked about HTTPS in core, and some ideas about it, while the CPAN Security Group is preparing some proposals. Today was the deadline for releasing 5.41.1, but we don’t have volunteers yet, so Graham said he would do it sometime soon.

We also noted that we’ll need some volunteers for the next 10 or so development releases.

The Weekly Challenge - Perl & Raku

The Weekly Challenge

Published on Monday 24 June 2024 01:35

The page you are looking for was moved, removed, renamed or might never existed.


The Weekly Challenge

Published on Monday 24 June 2024 01:35

TABLE OF CONTENTS 01. HEADLINES 02. STAR CONTRIBUTORS 03. CONTRIBUTION STATS 04. GUESTS 05. LANGUAGES 06. CENTURION CLUB 07. DAMIAN CONWAY’s CORNER 08. ANDREW SHITOV’s CORNER 09. PERL SOLUTIONS 10. RAKU SOLUTIONS 11. PERL & RAKU SOLUTIONS HEADLINES Thank you Team PWC for your continuous support and encouragement. STAR CONTRIBUTORS Following members shared solutions to both tasks in Perl and Raku as well as blogged about it.


The Weekly Challenge

Published on Monday 24 June 2024 01:35

TABLE OF CONTENTS 01. HEADLINES 02. STAR CONTRIBUTORS 03. CONTRIBUTION STATS 04. GUESTS 05. LANGUAGES 06. CENTURION CLUB 07. DAMIAN CONWAY’s CORNER 08. ANDREW SHITOV’s CORNER 09. PERL SOLUTIONS 10. RAKU SOLUTIONS 11. PERL & RAKU SOLUTIONS HEADLINES Thank you Team PWC for your continuous support and encouragement. STAR CONTRIBUTORS Following members shared solutions to both tasks in Perl and Raku as well as blogged about it.


The Weekly Challenge

Published on Monday 24 June 2024 01:35

TABLE OF CONTENTS 01. HEADLINES 02. STAR CONTRIBUTORS 03. CONTRIBUTION STATS 04. GUESTS 05. LANGUAGES 06. CENTURION CLUB 07. DAMIAN CONWAY’s CORNER 08. ANDREW SHITOV’s CORNER 09. PERL SOLUTIONS 10. RAKU SOLUTIONS 11. PERL & RAKU SOLUTIONS HEADLINES Thank you Team PWC for your continuous support and encouragement. STAR CONTRIBUTORS Following members shared solutions to both tasks in Perl and Raku as well as blogged about it.


The Weekly Challenge

Published on Monday 24 June 2024 01:35

As you know, The Weekly Challenge, primarily focus on Perl and Raku. During the Week #018, we received solutions to The Weekly Challenge - 018 by Orestis Zekai in Python. It was pleasant surprise to receive solutions in something other than Perl and Raku. Ever since regular team members also started contributing in other languages like Ada, APL, Awk, BASIC, Bash, Bc, Befunge-93, Bourne Shell, BQN, Brainfuck, C3, C, CESIL, Chef, COBOL, Coconut, C Shell, C++, Clojure, Crystal, D, Dart, Dc, Elixir, Elm, Emacs Lisp, Erlang, Excel VBA, F#, Factor, Fennel, Fish, Forth, Fortran, Gembase, GNAT, Go, GP, Groovy, Haskell, Haxe, HTML, Hy, Idris, IO, J, Janet, Java, JavaScript, Julia, Korn Shell, Kotlin, Lisp, Logo, Lua, M4, Maxima, Miranda, Modula 3, MMIX, Mumps, Myrddin, Nelua, Nim, Nix, Node.

ActiveState PERL Version 5.36.3 acts different from Version 5.22.1


Published by /u/AvWxA on Monday 24 June 2024 01:26

I have been using version 5.22.1 for years, and it did what I needed to do. After all these years, I need some additional functionality, so I thought installing the latest might help.

Which is when I found that ActiveState has changed the installation process totally. Anyway, I went through the installation of the "recommended" version, and installation seemed to go fine.

I then ran the following simple code through both versions.

use HTTP::Tiny; my $url ='https://www.scrapingcourse.com/ecommerce/' ; my $response = HTTP::Tiny->new->get($url); print $response->{content}; 

Version 5.22.1 runs this fine and gives me the HTML of the page.
Version 5.36.3 gives me the following errors;

IO::Socket::SSL 1.42 must be installed for https support
Net::SSLeay 1.49 must be installed for https support

When I use the old ppm command for Version 5.22.1, it gives me a list of 271 packages installed.

When I used the new "state" command: "state packages", it showed nothing.

So I used "state" to "install" IO-Socket-SSL, and Net-SSLeay, and now those are the only two that show up in the "state packages" list.

But it did not change functionality. The error messages are still there, and no execution.

It doesn't complain about HTTP::Tiny.

I tried installing Strawberry. But it had a problem with a more complex part of my original project, so I went back to ActiveState 5.22.1, which works fine.

Anybody got any ideas about what I need to do to get 5.36.3 actually working?

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

(di) 10 great CPAN modules released last week


Published by /u/niceperl on Sunday 23 June 2024 14:34

(di) 10 great CPAN modules released last week


Published by Unknown on Sunday 23 June 2024 16:34

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

  1. CGI - Handle Common Gateway Interface requests and responses
    • Version: 4.66 on 2024-06-19, with 44 votes
    • Previous CPAN version: 4.65 was 15 days before
    • Author: LEEJO
  2. Dist::Zilla::Plugin::Git - Update your git repository after release
    • Version: 2.051 on 2024-06-16, with 44 votes
    • Previous CPAN version: 2.050 was 1 day before
    • Author: ETHER
  3. Firefox::Marionette - Automate the Firefox browser with the Marionette protocol
    • Version: 1.58 on 2024-06-16, with 16 votes
    • Previous CPAN version: 1.56 was 1 month, 11 days before
    • Author: DDICK
  4. Git::Hooks - Framework for implementing Git (and Gerrit) hooks
    • Version: 4.0.0 on 2024-06-16, with 12 votes
    • Previous CPAN version: 3.6.0 was 7 months before
    • Author: GNUSTAVO
  5. MCE - Many-Core Engine for Perl providing parallel processing capabilities
    • Version: 1.897 on 2024-06-20, with 104 votes
    • Previous CPAN version: 1.889 was 9 months, 7 days before
    • Author: MARIOROY
  6. MCE::Shared - MCE extension for sharing data supporting threads and processes
    • Version: 1.891 on 2024-06-20, with 15 votes
    • Previous CPAN version: 1.886 was 9 months, 7 days before
    • Author: MARIOROY
  7. Sub::Override - Perl extension for easily overriding subroutines
    • Version: 0.12 on 2024-06-18, with 15 votes
    • Previous CPAN version: 0.11 was 1 month, 4 days before
    • Author: MVSJES
  8. Syntax::Construct - Explicitly state which non-feature constructs are used in the code.
    • Version: 1.037 on 2024-06-20, with 13 votes
    • Previous CPAN version: 1.036 was 8 days before
    • Author: CHOROBA
  9. Template::Toolkit - comprehensive template processing system
    • Version: 3.102 on 2024-06-21, with 147 votes
    • Previous CPAN version: 3.101 was 1 year, 10 months, 5 days before
    • Author: TODDR
  10. Text::CSV_XS - Comma-Separated Values manipulation routines
    • Version: 1.55 on 2024-06-18, with 101 votes
    • Previous CPAN version: 1.54 was 2 months before
    • Author: HMBRAND

(dcxiii) stackoverflow perl report


Published by Unknown on Sunday 23 June 2024 16:31

Speaking Goat Latin on the fastest bus to town

dev.to #perl

Published by Simon Green on Sunday 23 June 2024 13:16

Weekly Challenge 274

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. It's a great way for us all to practice some coding.

Challenge, My solutions

Task 1: Goat Latin


You are given a sentence, $sentence.

Write a script to convert the given sentence to Goat Latin, a made up language similar to Pig Latin.

Rules for Goat Latin:

  1. If a word begins with a vowel ("a", "e", "i", "o", "u"), append "ma" to the end of the word.
  2. If a word begins with consonant i.e. not a vowel, remove first letter and append it to the end then add "ma".
  3. Add letter "a" to the end of first word in the sentence, "aa" to the second word, etc etc.

My solution

A few weeks ago I mentioned how my employer - now former employer :( - give us access to GitHub Copilot. It's pretty cool, and practically wrote the code for me.

output from vscode with copilot

I did modify it slightly to make the code a little easier to understand, but I'm super impressed that it came up with a perfectly working solution.

def goat_latin(sentence: str) -> str:
    words = sentence.split(' ')
    for i, word in enumerate(words):
        if word[0].lower() not in ['a', 'e', 'i', 'o', 'u']:
            word = word[1:] + word[0]

        words[i] = word + 'maa' + 'a' * i

    return ' '.join(words)


$ ./ch-1.py "I love Perl"
Imaa ovelmaaa erlPmaaaa

$ ./ch-1.py "Perl and Raku are friends"
erlPmaa andmaaa akuRmaaaa aremaaaaa riendsfmaaaaaa

$ ./ch-1.py "The Weekly Challenge"
heTmaa eeklyWmaaa hallengeCmaaaa

Task 2: Bus Route


Several bus routes start from a bus stop near my home, and go to the same stop in town. They each run to a set timetable, but they take different times to get into town.

Write a script to find the times - if any - I should let one bus leave and catch a strictly later one in order to get into town strictly sooner.

An input timetable consists of the service interval, the offset within the hour, and the duration of the trip.

My solution

I'd love to see more challenges like this one. Yes, they take a longer time to come up with a solution, but they challenge me to turn the task into a working solution. And this is one where Copilot was less than helpful.

For the input from the command line, I take the integers in sets of three for the attribute of each route.

For this task I worked out a solution on my whiteboard before writing a single line of code. There are many different parts to my solution.

The first is a dataclass that has information about each route. This makes it easier to reference the attributes of each route.

from dataclasses import dataclass

class Route:
    freq: int
    offset: int
    length: int

The next part to my solution is a function that takes the route, and finds the fastest bus that leaves at each minute. This is stored as a dict where the key is the departure minute, and the value is the journey time of the quickest bus leaving at that minute.

def calculate_departures(routes):
    departures = {}
    for route in routes:
        start_minute = route.offset % route.freq
        while start_minute < 60:
            if start_minute in departures and departures[start_minute] < route.length:
                # This is a slower bus, so we can ignore it
            departures[start_minute] = route.length
            start_minute += route.freq

    return departures

The next function I have is called next_bus. Given the departures (from the above function) and a minute, it will determine the next bus to depart, which may possibly cross over an hour (eg. 11:59, 12:00, 12:01...). The function returns the start_minute minute and the end_minute minute (start minute + journey length).

def next_bus(departures, minute):
    start_minute = minute
    while True:
        if start_minute in departures:
            return start_minute, start_minute + departures[start_minute]

        start_minute += 1
        if start_minute == 60:
            start_minute = 0

The main function puts this all together. I start by defining departures from the calculate_departures function, and the skip_bus variable as an empty list.

def bus_route(routes: list[Route]) -> list[int]:
    # Get the start time of all bus routes
    departures = calculate_departures(routes)
    skip_bus = []

I then have a double loop. The outer loop uses the variable minute and is loops from zero to 59. I use the next_bus function to determine the start_minute and end_minute of the next bus to arrive.

The inner loop uses the variable second_bus_start and loops from one minute past the start_minute to one less than the end_minute. It checks if there is a bus departing at that minute. If there is and it gets us to the destination quicker, I exit the inner loop and add the start_minute value to the skip_bus list.

    for minute in range(60):
        start_minute, end_minute = next_bus(departures, minute)

        for second_bus_start in range(start_minute + 1, end_minute):
            if second_bus_start % 60 not in departures:
            if second_bus_start + departures[second_bus_start % 60] < end_minute:



$ ./ch-2.py 12 11 41 15 5 35
[36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47]

$ ./ch-2.py 12 3 41 15 9 35 30 5 25
[0, 1, 2, 3, 25, 26, 27, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 55, 56, 57, 58, 59]

Bowing to the inevitable


Published by /u/davorg on Sunday 23 June 2024 11:43

Bowing to the inevitable

Perl Hacks

Published by Dave Cross on Sunday 23 June 2024 11:37

Data Munging with Perl was published in February 2001. That was over 23 years ago. It’s even 10 years since Manning took the book out of print and the rights to the content reverted to me. Over that time, I’ve been to a lot of Perl conferences and met a lot of people who have bought and read the book. Many of them have been kind enough to say nice things about how useful they have found it. And many of those readers have followed up by asking if there would ever be a second edition.

My answer has always been the same. It’s a lot of effort to publish a book. The Perl book market (over the last ten years, at least) is pretty much dead. So I really didn’t think the amount of time I would need to invest in updating the book would be worth it for the number of sales I would get.

But times change.

You may have heard of Perl School. It’s a small publishing brand that I’ve been using to publish Perl ebooks for a few years. You may have even read the interview that brian d foy did with me for perl.com a few years ago about Perl School and the future of Perl publishing. In it, I talk a lot about how much easier (and, therefore, cheaper) it is to publish books when you’re just publishing ebook versions. I end the interview by inviting anyone to come to me with proposals for Perl School books, but brian is one of only two people who have ever taken me up on that invitation.

In fact, I haven’t really written enough Perl School books myself. There are only two – Perl Taster and The Best of Perl Hacks.

A month or so ago, brian was passing through London and we caught up over dinner. Of course, Perl books was one of the things we discussed and brian asked if I was ever going to write a second edition of Data Munging with Perl. I was about to launch into my standard denial when he reminded me that I had already extracted the text from the book into a series of Markdown files which would be an excellent place to start from. He also pointed out that most of the text was still relevant – it was just the Perl that would need to be updated.

I thought about that conversation over the next week or so and I’ve come to the conclusion that he was right. It’s actually not going to be that difficult to get a new edition out.

I think he was a little wrong though. I think there are a few more areas that need some work to bring the book up to date.

  • Perl itself has changed a lot since 2001. Version 5.6.0 was released while I was using the book – so I was mostly targeting 5.005 (that was the point at which the Perl version scheme was changed). I was using “-w” and bareword filehandles. It would be great to have a version that contains “use warnings” and uses lexical filehandles. There are dozens of other new Perl features that have been introduced in the last twenty years.
  • There are many new and better CPAN modules. I feel slightly embarrassed that the current edition contains examples that use Date::Manip and Date::Calc. I’d love to replace those with DateTime and Time::Piece. Similarly, I’d like to expand the section on DBI, so it also covers DBIx::Class. There’s a lot of room for improvement in this area.
  • And then there’s the way that the world of computing has changed. The current edition talks about HTTP “becoming ubiquitous” – which was an accurate prediction, but rather dates the book. There are discussions on things like FTP and NFS – stuff I haven’t used for years. And there are new things that the book doesn’t cover at all – file formats like YAML and JSON, for example.

The more I thought about it, the more I realised that I’d really like to see this book. I think the current version is still useful and contains good advice. But I don’t want to share it with many people because I worry that they would pick up an out-of-date idea of what constitutes best practices in Perl programming.

So that has now become my plan. Over the next couple of months, I’ll be digging through the existing book and changing it into something that I’m still proud to see people reading. I don’t want to predict when it will be ready, but I’d hope to have it released in the autumn.

I’d be interested to hear what you think about this plan. Have you read the book? Are there parts of it that you would like to see updated? What new syntax should I use? What new CPAN modules are essential?

Let me know what you think.

The post Bowing to the inevitable first appeared on Perl Hacks.

Perl Weekly Challenge 274: Goat Latin


Published by laurent_r on Sunday 23 June 2024 02:48

These are some answers to the Week 274, Task 1, of the Perl Weekly Challenge organized by Mohammad S. Anwar.

Spoiler Alert: This weekly challenge deadline is due in a few days from now (on June 23, 2024 at 23:59). This blog post provides some solutions to this challenge. Please don’t read on if you intend to complete the challenge on your own.

Task 1: Goat Latin

You are given a sentence, $sentance.

Write a script to convert the given sentence to Goat Latin, a made up language similar to Pig Latin.

Rules for Goat Latin:

1) If a word begins with a vowel ("a", "e", "i", "o", "u"), append "ma" to the end of the word. 2) If a word begins with consonant i.e. not a vowel, remove first letter and append it to the end then add "ma". 3) Add letter "a" to the end of first word in the sentence, "aa" to the second word, etc etc.

Example 1

Input: $sentence = "I love Perl"
Output: "Imaa ovelmaaa erlPmaaaa"

Example 2

Input: $sentence = "Perl and Raku are friends"
Output: "erlPmaa andmaaa akuRmaaaa aremaaaaa riendsfmaaaaaa"

Example 3

Input: $sentence = "The Weekly Challenge"
Output: "heTmaa eeklyWmaaa hallengeCmaaaa"

Goat Latin in Raku

The first thing is to define consonants: I decided to define it as the set of all upper-case and lower-case letters minus (in the sense of set difference) upper-case and lower-case vowels. The rest is just following the task description: remove the first letter from the beginning if t is a consonant, add "ma" and then add an "a" to the end of first word in the sentence, an "aa" to the second word, etc.*

sub goat-latin ($in) {
    my $consonants = (('a'..'z').Set ∪ ('A'..'Z').Set)
        (-) <a e i o u A E I O U>.Set;
    my @out;
    my $wc = 0;
    for $in.words -> $word {
        my $result = $word;
        if (substr $result, 0, 1)  ∈ $consonants {
            $result = (substr $word, 1) ~ (substr $result, 0, 1);
        $result ~= "ma";
        $result ~= 'a' x  $wc;
        push @out, $result;
    return join " ", @out;
my @tests = "I love Perl", "Perl and Raku are friends",
    "The Weekly Challenge";
for @tests -> $test {
    say "English: $test";
    say "Goat Latin: ", goat-latin $test;
    say "-----";

This program displays the following output:

$ raku ./goat-latin.raku
English: I love Perl
Goat Latin: Imaa ovelmaaa erlPmaaaa
English: Perl and Raku are friends
Goat Latin: erlPmaa andmaaa akuRmaaaa aremaaaaa riendsfmaaaaaa
English: The Weekly Challenge
Goat Latin: heTmaa eeklyWmaaa hallengeCmaaaa

Goat Latin in Perl %vowel

This is a port to Perl of the above Raku program. The most significant difference is that we use a hash (%vowels) to store the vowels.

use strict;
use warnings;
use feature 'say';

sub goat_latin {
    my $in = shift;
    my %vowels = map {$_ => 1} qw<a e i o u A E I O U>;
    my @out;
    my $wc = 0;
    for my $word (split /\s+/, $in) {
        unless (defined $vowels{substr $word, 0, 1}) {
            $word = (substr $word, 1) . (substr $word, 0, 1);
        $word .= "ma";
        $word .= 'a' x  $wc;
        push @out, $word;
    return join " ", @out;
my @tests = ("I love Perl", "Perl and Raku are friends", "The Weekly Challenge");
for my $test (@tests) {
    say "English: $test";
    say "Goat Latin: ", goat_latin $test;
    say "-----";

This program displays the following output:

$ perl ./goat-latin.pl
English: I love Perl
Goat Latin: Imaa ovelmaaa erlPmaaaa
English: Perl and Raku are friends
Goat Latin: erlPmaa andmaaa akuRmaaaa aremaaaaa riendsfmaaaaaa
English: The Weekly Challenge
Goat Latin: heTmaa eeklyWmaaa hallengeCmaaaa

Wrapping up

The next week Perl Weekly Challenge will start soon. If you want to participate in this challenge, please check https://perlweeklychallenge.org/ and make sure you answer the challenge before 23:59 BST (British summer time) on June 30, 2024. And, please, also spread the word about the Perl Weekly Challenge if you can.

Creating Script to Login to website powered by javascript


Published by /u/hsvodka on Sunday 23 June 2024 01:22

Its been a long time since i've had to hack some code together so here just asking for advice as to where to start.

I have a group of printers (all have same web interface) on the corporate network. I would like to make a simple script that can login, and upload a config file (really its a list of users that have can scan documents, it doesn't matter what).

I've tried to google this with limited results, so wanted to reach out here to see if PERL would be the best answer for this.

I guess my question is, what modules should I look at to connect to a webpage in order to login then access a page behind the login and upload a file?

I looked into Mechanize but I do not believe it can handle javascript. Any advice or test scripts that do something similar would be greatly appreciated.

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

perl 5.32.1 on linux

If I do a system call that runs a command in the background, will that background process persist after the perl script ends ? E.g.

system("rm -rf /disk/rm_this_big_dir >& /dev/null &");

Removing "/disk/rm_this_big_dir" needs to keep running, even after the perl script that ran the system call finishes. (That's what the trailing '&' is supposed to do.)

belated review of stuff I bought during lockdown

rjbs forgot what he was saying

Published by Ricardo Signes on Saturday 22 June 2024 12:00

A couple weeks ago, I had to test a printer, and the first text file I found to test-print was this, quazza-purchases.txt:

Mar 27    $ 90      Philips Hue lights
Mar 30    $200      dock (Fastmail paid)

Apr  2    $232      Dual monitor arm

May  7    $ 64      ottoman
May  8    $ 48      bookends
May 11    $ 13      banjo hanger
May 27    $ 16      headphone hanger
May 29    $225      Wall art

Jun  8    $335      Whiteboard
Jun 15    $ 17      magnet-making stuff!
Jun 19    $ 12      Whiteboard erasing cloths

Jul  4    $500      side table
Jul 12    $ 12      furniture feet

Sep  8    $ 36      Label maker

It’s a list of things I bought to improve my work-from-home experience. I don’t know why I kept it, but now that I have it, I can provide a few years of perspective on how those went. Nobody is asking for this, but I’m providing it anyway. If you want more photos than those found in this post, you’re in luck. It turns out that I posted a little Flickr album of some of this decorating. It is just as boring an album as you might expect!

Our last day of work in the office was March 13th, so March 27th was just two weeks into lockdown. That means the Hue lights were pretty early. I didn’t just get these for fun (although I did have fun with them). I got them because I already spent a lot of time on Zoom talking to Australia, and now I was going to spend even more talking to my American coworkers. You can see what a difference it made to my Zoom face in another post about these.

I think these were a decent buy. I was happier with my Zoom calls, and it gave me some code to write for fun, and now I have a few other Hue lights in my house. I put weird colors up at the holidays, or set lights to dim sometimes. Most of the value, though, is in Zoom calls.

Hue lights: ★★★★☆

Around the same time, I ordered that new dock and the monitor arm. These were … fine. The dock is an okay dock, but it was meant to let me have two displays while in clamshell mode on my laptop, and that didn’t work very well. Sometimes it worked. Sometimes it didn’t. Sometimes it worked but all my USB v2 peripherals stopped working. It stank, so I hooked it up to a Raspberry Pi which I never used. Now it’s just an expensive one-display dock.

That means the extra monitor arm also didn’t deliver the value I expected. Eventually, I decided to connect an Apple TV to it, which is sometimes useful. I can put a second desktop on it, or I can just put a movie on it while doing weekend fun work. The down side is that for some reason I’ve never gotten the display’s built-in audio-out to work properly, so I have to use a Bluetooth speaker. That means that weirdly, once in a while, some neighbor is able to pair to it and play noise into my office. Awful.

Dock and monitor arm: ★★★☆☆

May was a month of organizing and making my space nice to sit in day after day. Some of this was decluttering: I got a bunch of books better organized, I got my headphones slung under my desk, and I got my banjo off the floor and onto the wall. I guess this was okay. The bookends let me put all my books in the correct orientation, instead of sideways books holding up vertical books. The banjo hanger made all the people on my Zoom calls think I played banjo. (Usually for only one or two calls, after which they’d say, “Hey, do you play the banjo?” and then I’d say, “No.”) The headphone hanger still gets use, but I don’t love it. The cables dangle in my trash can. I don’t know what I’d like better, but something.

Bookends, hangers: ★★★☆☆

I also bought an ottoman. Just about as soon as I received it, I thought it was going to be the best thing I bought during lockdown. A couple years later, I still think so, at least relative to its price. I started using it for reading. I’d turn my chair away from my desk, put up my feet so I couldn’t turn back to my computer, and just enjoy sitting. I am still doing that, even though I have some other chairs. I keep my cheap but comfy IKEA blanket in it, too. I’ve been thinking about getting an ottoman for work. And maybe one for my balcony. They’re just a good idea.


Ottoman: ★★★★★

And then there’s the art. At the time, my home office was basically a walk-in closet. It wasn’t connected to a bedroom, but it was small and bland, with off-white walls and a window that looked out onto an ugly stucco wall. It felt like putting a little something attractive up on the walls would be a good idea. I went to Society6 and got two canvas prints by local Philly artist Andrew Chalfen. If you look at that page, you can find the Tiled City pieces. One of mine looks like those. The other is much less busy, mostly made up of hexagons. Years later, I still like them and I’m not tired of looking at them.

Hanging art: ★★★★☆

In June came the whiteboard. I really like whiteboarding. I don’t do it every day, but when I realize that I need to use a whiteboard for a problem, it’s a good sign that I’ll save a huge amount of effort by just doing so. At the Fastmail office in Philadelphia, we have really nice whiteboards, and I didn’t want to get a lousy melamine one for home. I splurged and contacted our office furniture vendor. In the end, the $350 was worth it. I’m still using it years later, and it’s still saving me time. Also, sometimes the kid comes in and draws something on it.

When they came to deliver it, they came in a full semi trailer down my one-lane street in Philly. Then the driver needed my help to unload. It was bizarre, but I ended up with a nice whiteboard. It’s “ceramic steel”, whatever that means. It’s magnetic and erases really nicely. The erasing cloths were maybe not a great idea. Paper towels work better, I think.

Steelcase truck

(Note that the truck has a rainbow Steelcase logo. It was delivered in June.)

I also bought “magnet-making stuff”. This was actually some small neodymium magnets and some two-part epoxy. I made some whiteboard magnets by sticking the magnets to some polyhedral dice with epoxy. This was fun, I’d do it again. (It smelled very bad, and I was told that if I ever do it again, I have to do it outside. Okay!)

dice magnets

Whiteboard: ★★★★☆

That whiteboard’s effectiveness was probably hampered by another purchase, which was otherwise pretty good: my sideboard. It’s a nice wood and metal console — Article’s Taiga oak console. It holds a bunch of my cables (in boxes), stationery, some electronics I want to keep easy to find, and sometimes the books I’m reading. It matches my aesthetic and it’s quite convenient. The problem is that both then and now, I have it right under my whiteboard. It’s about a foot deep, so it means I have to stand just a little bit away from the whiteboard, so it’s just a little bit less ergonomic.

In some future dwelling, it may all come together better, but here it’s been slightly imperfect.

Wooden console: ★★★☆☆

Also on the list: feet to go under furniture so it wouldn’t slip. Fine. Beneath discussion, I think. And the label maker… I mean, everybody loves a label maker, right? But what is there to say? I labeled a lot of things, then I put it away, and now I use it a couple times a year. I should’ve bought it earlier in life, but even then, there isn’t so much to say.

But… one more thing!

Earlier, I mentioned that my office had a window onto an ugly wall. Well, I have a photo:

my "view"

Awful. Just awful. Eventually that wall was resurfaced, so it went from dingy, disgusting stucco to merely ugly, typical stucco. It too me far, far too long to do something about this view. I hung some heavy yellow drapes. I’d always had blinds, so their effect on the view was marginal. On the other hand, they gave the bland room a big pop of color that was definitely worth the fifty bucks I spent on the drapes and rod combined.

The whole endeavor did have one lasting bit of value: it made it clear to me that I should spend a little time and money making my home more comfortable even when there is not a global pandemic throwing my day to day life into unheaval. Just this month, I bought a new table and chair for my balcony. Lesson learned.

I need to use Perl to replace an entire line if it has a match to a regular expression.

For example, if I have this file below:

Chicago no
Baltimore no
New York no

And I have a regex that returns matches for "Baltimore"

With a saved string containing "Baltimore yes"

How can I use perl to replace the line containing the match with my new line, Baltimore yes:

Chicago no
Baltimore yes
New York no

The goal is to see the encapsulated data, like I've been doing for the last 26 years.

use 5.040;
use strictures;
use experimental 'class';

class Foo {
    field @member = qw(e r t);

my $foo = Foo->new;

# use Data::Dumper qw(Dumper);
# say Dumper $foo;
# cannot handle ref type 16

# use DDS; DumpLex $foo;
# _dump_rv() can't handle 'OBJECT' objects yet

# use Data::Dx; Dx $foo;
# Can't handle OBJECT data

# use DDP; p $foo;
# Foo  {
#     public methods (1): new
#     private methods (0)
#     internals: (opaque object)
# }
#                ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

PWC 274 Waiting at the Bus Stop

dev.to #perl

Published by Bob Lied on Friday 21 June 2024 00:28

For this week's challenge, we have an interesting problem to ponder while we're Waiting at the Bus Stop.

Task 2: Bus Route

Several bus routes start from a bus stop near my home,
and go to the same stop in town. They each run to a
set timetable, but they take different times to get
into town.

Write a script to find the times - if any - I should
let one bus leave and catch a strictly later one in
order to get into town strictly sooner.

An input timetable consists of the service interval,
the offset within the hour, and the duration of the trip.

Example 1

  • Input: [ [12, 11, 41], [15, 5, 35] ]
  • Output: [36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47]

Route 1 leaves every 12 minutes, starting at 11 minutes past the hour (so 11, 23, ...) and takes 41 minutes. Route 2 leaves every 15 minutes, starting at 5 minutes past (5, 20, ...) and takes 35 minutes.

At 45 minutes past the hour I could take the route 1 bus at 47 past the hour, arriving at 28 minutes past the following hour, but if I wait for the route 2 bus at 50 past I will get to town sooner, at 25 minutes past the next hour.

Example 2

  • Input: [ [12, 3, 41], [15, 9, 35], [30, 5, 25] ]
  • Output: [ 0, 1, 2, 3, 25, 26, 27, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 55, 56, 57, 58, 59 ]


Let's flesh out some implied requirements.

The problem isn't asking us to identify the best choice; it only wants us to find the minutes where the next bus is not the best.

The routes appear to have hourly cycles, so we should only have to look at minutes 0 to 59, and then the situation resets for the following hour.

We'll need to figure out, at minute m, the next arrival of each of the routes. Then we'll take the earliest, unless one of the other routes arrives sooner. We don't need to look ahead any farther than that.

I'm tempted to build a class around a "route", if only to have a more readable way to access the triple of numbers, but let's hold that thought for a minute.

I'm also tempted to pre-compute all the possible bus arrival times and corresponding destination times, and then search for the condition. But it occurs to me that in creating such a table, I will have done most of the work to answer the question.

Into the breach

Let's tackle the problem of figuring out when the next bus of a given route arrives. We are standing at the bus stop at minute m. The route is identified by a tuple of [cycle, offset, duration]. Buses on the route will arrive first at minute offset, and then at times offset+n*cycle. Our problem is figure out which n our minute m is in.

0    offset  1*cycle   2*cycle  3*cycle       

To figure out the block, subtract out offset from m so that it has the same origin as the route cycle. Then divide by cycle and round up to the next integer: n = ceil( (m - offset) / cycle ).
Then the next arrival of the route at or after m will be offset+n*cycle. That bus will arrive at the destination duration minutes later.

So, here's a helpful little function that will determine, for a given route at minute m, when the bus arrives at the stop, and when it reaches its destination. We'll return those two bits of information as a pair in an array reference.

sub nextBusAt($route, $minute)
    my ($cycle, $offset, $duration) = $route->@*;

    my $stop = $offset + $cycle * ceil( ($minute - $offset) / $cycle );
    return [ $stop, $stop + $duration ];

Next step: at minute $minute, we want to know this information for each of the routes. Let's make a list of [bus, finish] pairs, applying nextBusAt as a transformation to each route.

map { nextBusAt($_, $minute) } $timetable->@*;

We need to know which of those is going to be first to arrive, so let's sort the pairs by the first element of each pair. Recall that nextBusAt returns an array reference to a pair, so we're operating on a list of array references from map.

my @next = sort { $a->[0] <=> $b->[0] } map { ...

The @next array is a list of pairs; each pair is an array reference to a bus arrival time, and a destination finish time. The first element in the @next array is the earliest bus to arrive, because of the sort. Let's pull that one aside and use it to compare to the others.

my ( $firstStopTime, $firstFinishTime) = (shift @next)->@*;

Is this the bus we should take? For the current minute, we should skip taking it if any other bus would have an earlier finish time. This can be expressed, using the any function from List::Util, as

my @skipToLater; 
push @skipToLater, $minute
     if any { $_->[1] < $firstFinishTime } @next 

Almost. What if two buses arrive at the stop at the same time? We're not asked to determine which bus to take, only to decide whether we should keep waiting. If two buses pull up at the same time, we're going to jump on the faster bus, so the answer to the "keep waiting?" question is "no." We have to modify our decision to take this into account.

my @skipToLater; 
push @skipToLater, $minute
     if any { $_->[1] < $firstFinishTime 
           && $_->[0] != $firstStopTime } @next 

Let's put the pieces together. We need to make this decision for every minute in the hour, and accumulate the minutes where a bus should be skipped.

sub busRoute($timetable)
    use List::Util qw/any/;
    my @skipToLater;
    for my $minute ( 0 .. 59 )
        my @next = sort { $a->[0] <=> $b->[0] }
                    map { nextBusAt($_, $minute) } $timetable->@*;

        my ( $firstStopTime, $firstFinishTime) = (shift @next)->@*;

        push @skipToLater, $minute
            if any { $_->[1] < $firstFinishTime
                  && $_->[0] != $firstStopTime } @next;

    return \@skipToLater;

It's probably not optimally efficient -- there are blocks of times when the answer is the same; we could probably figure those out based on (hand-wavy rationalization) some math of the common factors of the route cycle times, and therefore skip some loop iterations, but with only 60 iterations, it's not worth the mental gymnastics.

I didn't need to create any classes, or simulate the bus arrivals, or precompute the possibilities after all, fun as that might have been.

Can't locate Spreadsheet/WriteExcel/Big.pm in @INC

Perl questions on StackOverflow

Published by Eric Lommatsch on Thursday 20 June 2024 22:29

I have spent all day chasing this error message that I keep getting when I try and execute a perl script. the full error message is:

Can't locate Spreadsheet/WriteExcel/Big.pm in @INC (you may need to install the Spreadsheet::WriteExcel::Big module) (@INC contains: /loc02/mpdb/share/perl.d /loc02/mpdb/scripts/ /usr/share/perl5/vendor_perl/Spreadsheet/WriteExcel/Big.pm  /usr/share/perl5/vendor_perl/Spreadsheet/WriteExcel/Big.pm /home/oracle/frmhome/perl/lib/site_perl/5.36.0/x86_64-linux-thread-multi /home/oracle/frmhome/perl/lib/site_perl/5.36.0 /home/oracle/frmhome/perl/lib/5.36.0/x86_64-linux-thread-multi /home/oracle/frmhome/perl/lib/5.36.0) at /loc02/mpdb/scripts/veh_summ_write.pl line 1104.

I currently have in the line of the script that I am running the full path to the PM in the script.

#!/home/oracle/frmhome/perl/bin/perl -w -I /usr/share/perl5/vendor_perl/Spreadsheet/WriteExcel/Big.pm

How do I get this to work?

At the request of ikegami,

Output of head -n 1 /home/oracle/frmhome/perl/bin/cpan:


Output of set | grep ^PERL:


Output of /home/oracle/frmhome/perl/bin/perl -V:'inst.*':


Neuigkeiten: OTOBO 11 Veröffentlicht


Published by OTOBO Blog on Monday 17 June 2024 16:33

Wir freuen uns, die Veröffentlichung von OTOBO 11 bekannt zu geben! Die neueste Version der beliebten Open-Source-Ticketsystem-Software bringt zahlreiche Verbesserungen und neue Funktionen mit sich. Erfahren Sie mehr über die neuen Features und Änderungen auf OTOBO

Perl Weekly #673 - One week till the Perl and Raku conference

dev.to #perl

Published by Gabor Szabo on Monday 17 June 2024 09:46

Originally published at Perl Weekly 673


We had our first virtual event a couple of days ago. I was really happy to see that more than 25 people joined. We also have the video recordings of Getting started with Docker for Perl developers. Please watch, click on the thumbs-up and follow the channel!

The next such event will be on 14 July about Continuous Integration (CI): GitHub Actions for Perl Projects. I'd like to encourage you to register to the Code-Mavens group an to the event itself. I would be also happy to get requests for topics to cover.

On the events page of the Perl Weekly you can now see all the Perl-related events we know about. It also features a calendar you can add to Google calendar or whatever other program you use to see the events along with your own events.

The closest of all those events is The Perl and Raku conference that starts a week from today. It is still not too late to register and to use it as an excuse to go to Las Vegas... You could, of course also sponsor the conference...

Another one of the big in-person events is the London Perl and Raku Workshop that will take place in October. There you still have time to submit a talk proposal or to offer your sponsorship.

Enjoy your week!

Your editor: Gabor Szabo.


Continuous Integration (CI): GitHub Actions for Perl Projects (Free Virtual Workshop on July 13)

In this virtual workshop you will learn why and how to use GitHub Actions as a CI system for your Perl projects. The workshop is free of charge thanks to my supporters via Patreon and GitHub. Besides this workshop I am running many more, so make sure you check the Code Mavens meetup group and also register to it.


Chopping UTF-8

Dealing with UTF-8 characters on the command line with Perl

Making time to waste.

An excellent writing a bit about RRULES for recurring events and a lot about time. Something we have plenty of, but never enough.

listening to your friends' jams with last.fm

How can you discover music that your friends like, but you have never heard off?

Building Perl applications for Bioinformatics

An academic paper and some discussion.

GitHub Actions doesn't like the older perl images today

Thanks Fastly!

The Perl NOC is thanking its supporters.


How to remove comments that are not in a quoted string?

No-BS Perl Webhost?

Where can one host a web site running Perl? Several responses. I have been using Linode (now part of Akamai) for ages and I also love and use Digital Ocean. Both will let you rent a small VPS for about $5 / month. That gives you root access to install whatever you like. As I just noticed they might also offer you some credit to get started without actually paying anything.


Maintaining Perl 5 Core (Dave Mitchell): April - May 2024


This week in PSC (151) | 2024-06-13

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

Welcome to a new week with a couple of fun tasks "Goat Latin" and "Bus Route". 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 - 273

Enjoy a quick recap of last week's contributions by Team PWC dealing with the "Percentage of Character" and "B After A" tasks in Perl and Raku. You will find plenty of solutions to keep you busy.

Trying to Be X Percent More Interesting

Impressive blogging style discussing solutions in different languages. You really don't want to skip it, highly recommended.

B of A

Two easy tasks and two easy solutions in Raku with plenty of documentation. Keep it up great work.

Round Here

Dealing with round in Perl is always fun. Here you get clever implementation. Thanks for sharing.

Perl Weekly Challenge: Week 273

One-liner in Raku is very impressive as always. You will find yourself plenty of documentation. Well done and keep it up.

Looking After The Percentage

Pure Perl regex magic is on display. Please take a pause and check out the regex. Keep it up great work.

Perl Weekly Challenge 273: Percentage of Character

Raku first and direct translation into Perl syntax is too much fun not to be missed. Well done and thanks for sharing.

Perl Weekly Challenge 273: B After A

Raku regex is hard to follow to be honest. Having said, enjoy the comparative implementation in Perl.

Perl Weekly Challenge 273

Master of Perl one-liners and use of powerful Perl regex. Keep it up great work.

quite easy!

Two challenges and two one-liners in Raku. Thanks for your contributions.

Percentages and the 'BnoA' Regex

For all Perl fans, please find Perl magics and enjoy. Thanks for sharing knowledge with us.

Time to count B chars

Getting help from POSIX to deal with round is easy way out and clever one. Also checkout the different implementation in Raku and Python.

All about characters

Perl pure regex implementation to deal with both tasks. Don't forget to try DIY tool.

The Weekly Challenge - 273

Nice promotion of CPAN modules to solve the challenges. I must admit, the discussion is very engaging. Well done.

The Weekly Challenge #273

lround() from POSIX? Never knew about this. Thanks for sharing the knowledge with us.

Building Character

As always, Roger took the difficult path to deal with the challenge. Highly recommended.

Finding things

cash rounding vs bankers rounding? Well documented the details, keep it up great work.


Getting started with Docker for Perl developers

This is the video recording of the first (and most recent :-) virtual event for Perl developers. Don't forget to thumb-up the video and to follow the channel to get notifications about new videos!

Weekly collections

NICEPERL's lists

Great CPAN modules released last week.


The Perl and Raku conference

June 24-28, 2024, in Las Vegas, NV, USA

Boston.pm monthly meeting

July 9, 2024, Virtual event

Purdue Perl Mongers

July 10, 2024, Virtual event

Continuous Integration (CI): GitHub Actions for Perl Projects

July 14, 2024, in Zoom

Toronto Perl Mongers monthly meeting

July 25, 2024, Virtual event

London Perl and Raku Workshop

October 26, 2024, in London, UK

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.

Making time to waste.


Published by Saif on Sunday 16 June 2024 13:38

Over the years that I have existed in four dimensions, I have come to accept that time is not a linear concept heading inexorably in one direction at a uniform rate. It didn't take an Einstein or Hawking to convince me either. Time is as malleable as the distortions applied by our consciousness, or imposed by those around us. Consider my youngest daughter's essay due to be handed in on Tuesday, a task assigned 4 months earlier. At 4,000 words, it represented roughly 6 words an hour allowing for eating, sleeping, work, weekend fun, and other essential time-devouring activities. Yet the "I have got plennnnty of time, chill, dad!" of a few months ago, has now turned into cries of despair, as she has to do an all nighter at her desk instead of being at some selfie-rich event critical to her mental well-being and social standing.

The same happens at work when I get hauled over to the management because something I have no control over happened that shouldn't have happened. It seems that the eternal role of some such individuals is to improve efficiency and productivity without actually doing anything efficient or productive themselves. A strategy that some favour is to highlight trivial events, hold someone responsible, persistently bring this up at various encounters and thereby have justification for their existence, rather than allow access to the time machine that would enable correction of this past undesirable event.

One thing that might help these recurring, seemingly totally avoidable, but absolutely inevitable episodes, maybe be a set of rules. I have recently discovered RRULES, EXDATES and RDATES that can be embedded into iCal objects to define repeats of events. Some may be be repeated forever, some being confined to certain days of the week, each represented in a human readable form but parseable by machine. In order to achieve as much flexibility as possible, the rule structure is as complex as it is comprehensive.

One has two options when encountering a novelty such as this. One could look through the extensive experience and expertise of the Perl community who would naturally have some way of parsing these rules; easy, efficient and most likely to work. Work such as iCal-Parser by Cedric Cellier and Data::ICal::DateTime by Flávio Soibelmann Glock. On the other hand, one could try and build one one's self.

RRULES can become complicated,

# every year forever

# every other week forever

# first week every month excluding weekends until                               

#  every three years on the first Tuesday of October that is not the 1st of October

Parsing this kind rule can become rather difficult. Generating them reliably to do what you mean without ambiguity is similarly tricky. Feeding back this rule to the user in plain English is something that can also be challenging. It helps to steal other peoples ideas, but often one is trying to crowbar these rules into a project that has already been started, and a more eye-opening, time-consuming failure-ridden approach is required.

Finding time to do the research is difficult when you have a day job and many other demands on the time. I am sure the reader will have many experiences of temporal field manipulation, or perhaps are experts themselves. Time is infinite, but the time allocated to us is finite. We may choose to rush through life collecting as many experiences as possible, maximising the utilisation of this limited resource to earn, spend, learn, teach, give, take, create or destroy. I am told I waste a lot of time. I write code other people have done better for no return other than the same joy my grandson may have from drawing something unintelligible to show me. Sometimes I do it just so that something else more important can be forgotten, for even a little while. One could (or perhaps should) choose to do nothing other than to savour time that we do have, giving ourselves time to do nothing more than be alive.

Time may be precious but it will not be contained, disappearing from our grasp whatever we choose to do or not do with it. For me whatever you with it, time is never wasted. As one who has someone very dear to his heart going through a serious illness, time spent just being with someone you love is the most precious, irreplaceable time of all. Wishing you all happiness, love and peace.

Finding things

dev.to #perl

Published by Simon Green on Sunday 16 June 2024 10:38

Weekly Challenge 273

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: Percentage of Character


You are given a string, $str and a character $char.

Write a script to return the percentage, nearest whole, of given character in the given string.

My solution

Let's talk about 'nearest integer', and rounding. When you go to supermarket and something costs 45¢, you generally will be charged 50¢ if paying with cash and your currency doesn't have a 5¢ coin. This is called cash rounding, and probably what you were taught at school.

Python uses bankers rounding, where numbers are rounded to the nearest even. Therefore both 35¢ and 45¢ would be rounded to 40¢, while the sum remains the same (80¢).

This task is ambiguous as it does not mention which method to use when the percentage is a half figure. I've used the cash rounding method, as the sixth example supports this.

For this task, I take the number of characters that occur in the length of the string divided by the length of the string multiplied by 100 + 0.5 (for the rounding).

def char_percentage(s: str, char: str) -> int:
    return floor(s.count(char) / len(s) * 100 + 0.5)

The Perl solution is a bit more involved, as I don't believe there is a way to count the number of characters in a string. For this solution, I loop through each character and increase the occurrences value if is char.

my $occurrences = 0;
for my $pos ( 0 .. length($str) - 1 ) {
    if ( substr( $str, $pos, 1 ) eq $char ) {

say int( $occurrences / length($str) * 100 + 0.5 );


$ ./ch-1.py perl e

$ ./ch-1.py java a

$ ./ch-1.py python m

$ ./ch-1.py ada a

$ ./ch-1.py ballerina l

$ ./ch-1.py analitik k

Task 2: B After A


You are given a string, $str.

Write a script to return true if there is at least one b, and no a appears after the first b.

My solution

There are two likely ways to perform this task. One would be to take the position of last a (or -1 if there is no a) and check this is less than the position of the first b.

The second option is to use regular expressions. This is the approach that I took. The regexp I used is ^[^b]*b[^a]*$. This matches zero or characters other than b, a b and then makes sure there are no as after that.


$ ./ch-2.py aabb

$ ./ch-2.py abab

$ ./ch-2.py aaa

$ ./ch-2.py bbb

(d) 11 great CPAN modules released last week


Published by Unknown on Sunday 16 June 2024 08:14

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.414 on 2024-06-13, with 14 votes
    • Previous CPAN version: 2.413 was 21 days before
    • Author: KUERBIS
  2. CPAN::Audit - Audit CPAN distributions for known vulnerabilities
    • Version: 20240615.002 on 2024-06-15, with 14 votes
    • Previous CPAN version: 20240601.001 was 14 days before
    • Author: BDFOY
  3. Devel::Cover - Code coverage metrics for Perl
    • Version: 1.44 on 2024-06-10, with 101 votes
    • Previous CPAN version: 1.43 was 2 days before
    • Author: PJCJ
  4. Dist::Zilla::Plugin::Git - Update your git repository after release
    • Version: 2.050 on 2024-06-15, with 44 votes
    • Previous CPAN version: 2.049 was 5 months, 15 days before
    • Author: ETHER
  5. Getopt::Long - Module to handle parsing command line options
    • Version: 2.58 on 2024-06-11, with 122 votes
    • Previous CPAN version: 2.57 was 7 months before
    • Author: JV
  6. Kelp - A web framework light, yet rich in nutrients.
    • Version: 2.00 on 2024-06-10, with 44 votes
    • Previous CPAN version: 1.07 was 13 days before
    • Author: BRTASTIC
  7. MCE - Many-Core Engine for Perl providing parallel processing capabilities
    • Version: 1.896 on 2024-06-11, with 104 votes
    • Previous CPAN version: 1.891 was 5 days before
    • Author: MARIOROY
  8. MCE::Shared - MCE extension for sharing data supporting threads and processes
    • Version: 1.890 on 2024-06-10, with 15 votes
    • Previous CPAN version: 1.887 was 17 days before
    • Author: MARIOROY
  9. Module::CoreList - what modules shipped with versions of perl
    • Version: 5.20240609 on 2024-06-09, with 43 votes
    • Previous CPAN version: 5.20240420 was 1 month, 12 days before
    • Author: BINGOS
  10. perl-5.40.0 - The Perl 5 language interpreter
    • Version: 5.040000 on 2024-06-09, with 420 votes
    • Previous CPAN version: 5.38.2 was 6 months, 10 days before
    • Author: HAARG
  11. Syntax::Construct - Explicitly state which non-feature constructs are used in the code.
    • Version: 1.036 on 2024-06-12, with 13 votes
    • Previous CPAN version: 1.034 was 6 months, 13 days before
    • Author: CHOROBA

listening to your friends’ jams with last.fm

rjbs forgot what he was saying

Published by Ricardo Signes on Saturday 15 June 2024 12:00

Quite a while ago, I wrote some Spotify code that would find places when my Discover Weekly playlist would intersect with those of my friends and coworkers. This was fun. Every once in a while, I talked about other things that might be fun, along those lines. I tend not to do too much with those ideas, because the Spotify API is often missing exactly the method I want, and I can work around it, but it becomes too much of a pain. Also, I’m a little lazy when the project will need other people to be interested, unless I’m sure they will be. Who wants to launch a flop to their friends?

Anyway, yesterday I was talking to my friend Joe and he mentioned some recent last.fm crossovers. See, Joe still uses last.fm, and seems to be one of the last people I know who does so. But I do so, too, so always interested in the stuff he says about it. Us last.fm users have to stick together. If you don’t know what last.fm is: it tracks the music you listen to and keeps records. You can mine your own history, or the history of most other users, and like… do stuff. Clients to log plays are built into a number of music apps, including Spotify, so why not turn it on today, so I can look over shoulder while you listen? You’ll love it!

Apparently last.fm is now owned by CBS, who probably would be asking themselves why they bought it, if they ever bothered to think about it at all.

One of the ideas that Joe and I talked about was: What if you could get a report of the music that your friends have been listening to, but that you’ve never logged a play for. I really liked this idea, because I like knowing what my friends like, even when they like bad music. The report was actually really easy to write, although the last.fm API definitely felt like a trip back in time to 2002. It feels a lot like the Flickr API, and all the example code uses “http” and not “https” in the URLs. (Michael said “still, better than OAuth!” but I’m not sure I agreed.)

I spent a bunch of time on weird little blind alleys. For example, I showed Joe a report and he said, “This is saying I’ve never heard The Distance by Cake, but I definitely have.” The problem was that his listens and mine had different mbid values. That’s the MusicBrainz id, and you can click that link if you want to be further transported back in time to the early aughts. MusicBrainz, as I understand it, was created to help deal with the proliferation of nonstandard ID3-tagging of peer-to-peer shared music. If a hunk of people said that “Stand” was by “REM” and another hunk said “R.E.M.”, they’d look like two songs. The solution? Give every song a GUID-like identifier.

…except then Joe and I had the same song logging under two different identifiers. I’m not sure what happened, and I’m not sure I’m going to dig. I think if I found the answer, submitting a report would go nowhere, and I’d feel worse than just saying “guess this doesn’t work right”.

In the end, my program is very simple. I’ll probably make it smarter and cooler, but just in case I don’t, I’m posting it now, as is. I’ll probably put it on GitHub, and when I do, I’ll add a link here. Until then…

use v5.36.0;

use Digest::MD5 qw(md5_hex);
use Getopt::Long::Descriptive;
use IO::Async::Loop;
use JSON::XS;
use Net::Async::HTTP;
use Path::Tiny;
use URI;

my ($opt, $usage) = describe_options(
  '%c %o',
  [ 'target=s',   'find songs listened to by target' ],
  [ 'listener=s', 'find songs not yet played by listener' ],

# This should use Password::OnePassword::OPCLI but doesn't yet.
my $api_key = path('api-key.txt')->slurp;
my $secret  = path('secret.txt')->slurp;

my $loop = IO::Async::Loop->new;
my $http = Net::Async::HTTP->new;


# decode a JSON payload from an HTTP::Response object
sub djr ($res) {
  decode_json($res->decoded_content(charset => undef));

sub uri ($param, $sign = 1) {
  state $base = "https://ws.audioscrobbler.com/2.0/";

  my $uri = URI->new($base);
  my $str = q{};

  for my $name (sort keys %$param) {
    $uri->query_param($name => $param->{$name});
    $str .= "$name$param->{$name}";

  # Nothing in this program uses this, but while writing this program, I wrote
  # *other* last.fm-API-using code that did need signed URLs, so I left this
  # here.  It really belongs in rjbs::LastFM::Util or something…
  if ($sign) {
    $str .= $secret;
    my $sig = md5_hex($str);
    $uri->query_param(api_sig => $sig);

  return $uri;

my @tracks;

# This loop is here because the next phase would get the top tracks for all my
# friends and produced a combined output.
for my $user ($opt->target) {
  my $top_tracks_res = $http->do_request(
    uri => uri({
      method  => 'user.getTopTracks',
      api_key => $api_key,
      format  => 'json',
      user    => $user,
      period  => '3month',
    }, 0)

  my $top_tracks = djr($top_tracks_res);

  my %got_artist;

  TRACK: for my $track ($top_tracks->{toptracks}{track}->@*) {
    unless ($track->{mbid}) {
      # say "$track->{name} ($track->{artist}{name}) @ $track->{playcount}";
      # say "^-- no mbid?!\n";
      next TRACK;

    if ($got_artist{$track->{artist}{mbid}}) {
      # Already saw this artist.  I don't need a list of 69,105 Reznor
      # masterpieces.
      next TRACK;

    my $seen = saw_track($track);

    unless ($seen) {
      say "$track->{name} ($track->{artist}{name}) @ $track->{playcount}";

sub saw_track ($track, $debug = 0) {
  my $key = join q{--}, $track->{name}, $track->{artist}{name};

  state %know;
  return $know{$key} //= do {
    my $uri = uri({
      method    => 'track.getInfo',
      api_key   => $api_key,
      format    => 'json',
      username  => $opt->listener,

      # Originally, I used "mbid" instead of these two parameter, but it
      # wasn't reliable enough.
      track     => $track->{name},
      artist    => $track->{artist}{name},
    }, 0);

    my $trackinfo_res = $http->do_request(
      uri => $uri,

    my $info = djr($trackinfo_res);

    if ($debug) {
      print Dumper($info);

    return 0 if $info->{error} && $info->{error} == 6;
    return 0 if $info->{track}{userplaycount} == 0;
    return 1 if $info->{track}{userplaycount} > 0;

    die "!?";

This week in PSC (151) | 2024-06-13


Published by Perl Steering Council on Thursday 13 June 2024 20:45

Graham and Philippe met briefly today.

Now that Perl 5.40 is out, and the nomination process for the next PSC is underway, there wasn’t much to discuss, so we cut the meeting short.

Thanks Fastly!

The Perl NOC

Published by Unknown on Thursday 13 June 2024 13:30

We've fallen out of the habit of regularly thanking the companies that sponsor us.  (We appreciate all of you!)

Today, we're thankful for Fastly, whose CDN helps keep perl.org and cpan.org fast and available no matter where in the world you are.  We've been using them for more years than we can remember, and it's been a great experience since the beginning.  Three years ago, we deprecated the cpan.org mirror network and moved all CPAN module serving to Fastly.  This has been a vast simplification of our infrastructure, and a better experience for users.

Also today, Fastly is announcing a free tier for developers.  (They asked us to let you know.   It's the least we can do to thank them for all they've given us.)  Visit http://fastly.com/pricing for details.

Dave writes:

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

I mostly spent my time working on tickets, smoke reports etc related to getting perl ready for a new release.

SUMMARY: - 9:27 #16627: Null pointer dereference in S_SvREFCNT_dec - 0:30 __LINE__ deparsing - 3:48 fix double free in const state sub - 7:26 process p5p mailbox - 1:06 reduce smoke failures - 3:02 review Coverity reports - 3:03 rework XS documentation

TOTAL: - 28:22 (HH:MM)

Perl v5.40.0 is released

dev.to #perl

Published by Yuki Kimoto - SPVM Author on Tuesday 11 June 2024 04:54

more GitHub Actions: rjbs/dzil-actions

rjbs forgot what he was saying

Published by Ricardo Signes on Sunday 09 June 2024 12:00

I’ll be quick, this is just an update to my last post!

I had complained that I’d had to leave the matrixing of perl versions in my per-repo workflow, so the structure of any given repository’s workflow was something like this:

    - uses: rjbs/dzil-build@v0
        perl-version: $
      image: perldocker/perl-tester:$
    - name: Test distribution
      uses: rjbs/test-perl-dist@v0

I’ve eliminated a lot of content from the above, to keep it short. My complaint was that I wanted to put the matrix stuff out in some abstracted action, but I couldn’t. Actions can’t matrix, jobs can matrix. (It’s something like this. The documentation answers a lot of questions, but it’s not laid out in a way that I find easy to dig through or refer back to.)

While looking at things in the perl-actions/perl-versions repo, I came to realize that there’s a way around this. Instead of using an action, you use a reusable workflow. I started to put one together as rjbs/dzil-test but hit some snags. I no longer remember the details, but it felt like “you can’t call things in such-and-such away outside one repository”. I’m no longer sure that’s what it really was, though. The errors you get are often very bare statements of fact without much context or hinting at what you might have meant. That, along with the docs, have made this project involve a lot more thinking and experimenting than I feel should have been necessary. But that’s life as a programmer, right?

What I ended up doing was creating yet another repository, rjbs/dzil-actions, which contains a bunch of the actions I’d been using, plus two workflows. One workflow tests a tarball against a bunch of perls. The other workflow builds a tarball from a Dist::Zilla-based repository and then calls the first one. It feels pretty reasonable. It’s just the path that got me here that feels a bit unreasonable.

At this point, I think the complete workflow file I’m installing is now about the length I want. Behold, the whole thing:

name: "dzil matrix"
  workflow_dispatch: ~
    branches: "*"
    tags-ignore: "*"
  pull_request: ~

    name: dzil-matrix
    uses: rjbs/dzil-actions/.github/workflows/dzil-matrix.yaml@v0

(cdxcix) 11 great CPAN modules released last week


Published by Unknown on Sunday 09 June 2024 11:46

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

  1. Alien::Build - Build external dependencies for use in CPAN
    • Version: 2.83 on 2024-06-05, with 22 votes
    • Previous CPAN version: 2.80 was 1 year, 25 days before
    • Author: PLICEASE
  2. CGI - Handle Common Gateway Interface requests and responses
    • Version: 4.65 on 2024-06-04, with 44 votes
    • Previous CPAN version: 4.64 was 2 months, 17 days before
    • Author: LEEJO
  3. DBD::mysql - A MySQL driver for the Perl5 Database Interface (DBI)
    • Version: 5.006 on 2024-06-04, with 55 votes
    • Previous CPAN version: 5.005 was 1 month, 3 days before
    • Author: DVEEDEN
  4. Devel::Cover - Code coverage metrics for Perl
    • Version: 1.43 on 2024-06-08, with 101 votes
    • Previous CPAN version: 1.42 was 1 month, 12 days before
    • Author: PJCJ
  5. Google::ProtocolBuffers::Dynamic - fast and complete protocol buffer implementation
    • Version: 0.43 on 2024-06-04, with 12 votes
    • Previous CPAN version: 0.42 was 1 year, 12 days before
    • Author: MBARBON
  6. Kelp - A web framework light, yet rich in nutrients.
    • Version: 1.07 on 2024-06-02, with 44 votes
    • Previous CPAN version: 1.06 was 2 years, 30 days before
    • Author: BRTASTIC
  7. MCE - Many-Core Engine for Perl providing parallel processing capabilities
    • Version: 1.893 on 2024-06-08, with 104 votes
    • Previous CPAN version: 1.890 was 15 days before
    • Author: MARIOROY
  8. MCE::Shared - MCE extension for sharing data supporting threads and processes
    • Version: 1.888 on 2024-06-06, with 15 votes
    • Previous CPAN version: 1.887 was 13 days before
    • Author: MARIOROY
  9. Minion - Job queue
    • Version: 10.30 on 2024-06-05, with 106 votes
    • Previous CPAN version: 10.29 was 2 months, 17 days before
    • Author: SRI
  10. Number::Phone - base class for Number::Phone::* modules
    • Version: 4.0003 on 2024-06-07, with 17 votes
    • Previous CPAN version: 4.0002 was 2 months, 30 days before
    • Author: DCANTRELL
  11. Test2::Suite - Distribution with a rich set of tools built upon the Test2 framework.
    • Version: 0.000163 on 2024-06-05, with 47 votes
    • Previous CPAN version: 0.000162 was 1 month, 10 days before
    • Author: EXODIST

(dcxii) stackoverflow perl report


Published by Unknown on Sunday 09 June 2024 11:44

These are the five most rated questions at Stack Overflow last week.
Between brackets: [question score / answers count]
Build date: 2024-06-09 09:44:07 GMT

  1. Why does PerlCritic think my prototype is string interpolation? - [2/2]
  2. Passing parameters to parent constructor using Perl's new class syntax - [2/2]
  3. Pod: should the section part in a Pod link include formatting codes? - [1/1]
  4. third param for ioctl in Perl - [1/1]
  5. cpan install Sodium::FFI fails - [1/0]

GitHub Actions for testing Dist::Zilla dists

rjbs forgot what he was saying

Published by Ricardo Signes on Saturday 08 June 2024 12:00

In my last post, I wrote about how I made dzil workflower to install GitHub Actions into my Dist::Zilla-based dists’ repositories for automated testing. I also said I’d been reading O’Reilly’s Learning GitHub Actions. This week, I applied some more of what I learned from the book, and it was good.

I created reusable actions for parts of my common workflow. It was easy, and now I’ll explain.

Here’s a really commonly-seen bit of GitHub Actions workflow code:

- name: Check out repo
  uses: actions/checkout@v4

This clones the repository being tested onto the “runner” where your action is running. Since very often actions are going to compile and run the code, this is a really useful step to be able to call easily. It’s got a bunch of parameters, too, but the defaults are probably what you want. You get a shallow clone, without Git-LFS files, without submodules, and lots of other reasonable defaults. I hadn’t really thought about how this worked, but as with many things in GitHub Actions, it turns out to be pretty straightforward, even if the amount of YAML makes me a little exasperated.

The uses line points at a commit in a GitHub repo. Here, it’s v4 (a tag) in the checkout repository owned by actions. That owner is a user owned by GitHub where they put their “official” actions, but anybody can write their own actions, and generally speaking, anybody can use anybody else’s actions. An action definition looks a lot like a “job” definition, but with inputs (parameters) and outputs (return values) and branding (weird).

The actions/checkout action is written in JavaScript. The actual program that gets run is nearly 40,000 lines of code. I guess this is because it has all of its prereqs packed into it, but it means it’s a bit daunting to approach if you don’t understand the webpack system. Fortunately, I didn’t need to understand how to write a JavaScript action. You can write them in anything, but even better, you can just write them in YAML. (I can’t believe I just wrote that.) I mean that instead of writing an executable program to run, you can provide a list of standard GitHub Actions steps that will be run to execute your action.

I decided I would be happier by breaking down my big 93 lines of YAML workflow into smaller reusable actions. Even if I didn’t use them in any context other than the workflower-generated workflow, it would mean that I could update the action definition in one place, and all my workflows would get the new version on their next run. Right now, I have to rebuild the workflow for each repo individually.

I won’t embed the whole hundred lines of workflow, but you can read an old-style workflower workflow on GitHub in my repos’ history. It’s fine, and easy enough to understand, if you know how to read a workflow definition. Basically, it says this:

  • in the build-tarball job:
    • check out the repo
    • install prereqs for dzil
    • install prereqs for building the dist
    • build the dist
    • upload it as a build artifact so that the next job can use it
  • in the multiperl-tests job:
    • on every major perl release supported by the dist, in a container:
      • download the build artifact
      • extract it
      • install its prereqs
      • configure and build the dist
      • run the tests
      • publish a report

It’s not complicated, but writing this stuff in YAML is a bit fiddly, so it’s not great to read, and it’s too long.

My initial plan was to make the whole thing into an action called rjbs/dzil-multitest or something. Two things prevented that. First, I realized that a standalone action for “just build the tarball” might prove useful to somebody else some day. The second thing was more complicated.

The “on every major perl release” step uses something called the matrix strategy. In your workflow, you provide permutations of testing, and then the runner runs them all. Here’s the example from GitHub’s docs:

        version: [10, 12, 14]
        os: [ubuntu-latest, windows-latest]

This will run on every combination of version and OS. My workflow only had one parameter: which version of perl. (This is the only thing currently computed by the dzil workflower program, actually. Everything else in the workflow is static.) The problem is that you can’t put a matrix strategy in a reusable action, you can only put it in a workflow definition. At least, I’m pretty sure that’s right!

So, my goal was to make my workflow definition look like this:

  • in the build-tarball job:
    • build and upload the tarball
  • in the multiperl-tests job:
    • on every major perl release supported by the dist, in a container:
      • test the tarball

That seemed like the least complexity I could produce, for now. And I achieved it!

    runs-on: ubuntu-latest
    - name: Build archive
      uses: rjbs/dzil-build@v0

    needs: build-tarball
    runs-on: ubuntu-latest

      fail-fast: false
        perl-version: [ "devel", "5.38", "5.36", ... ]

      image: perldocker/perl-tester:$

    - name: Test distribution
      uses: rjbs/test-perl-dist@v0

The actions themselves are pretty straightforward, too.

The dzil-build action is a good fifty lines, but it does more or less exactly one thing, and I bet it could be used by other people for other purposes. I think it could also be a good place to put some little improvements like the caching of the installed prereqs. I only gave it one parameter, dist-name, which is used to create the tarball. Generally, you don’t need to supply this, because the action will use your repository name. This is a little improvement on the previous workflow, which always created Dist-To-Test.tar.gz.

The test-perl-dist action is the other fifty lines. I’m less certain that this action would be useful in other contexts, but it still might be! Even if not, it means that upgrades to the action will upgrade all my workflows that use it by name, which is a big deal.

Maybe I’ll never make many changes to these actions, and so there won’t be a lot of benefit in that sense, but going through the process was pretty helpful for my ongoing learning of how to use GitHub Actions. I’m glad I did it.

❗️ Update 1: a few hours later…

After posting this, I mentioned it on the #distzilla IRC channel, saying:

I think next is having the dzil-build action also create something storing the perl version range to test, which would mean the workflow would very rarely need a rebuild.

Graham Knop replied with only a URL, pointing me at the perl-actions/perl-versions action. This action takes a minimum version as an input and spits out a range of actions, suitable for passing to the matrix strategy.

With that, I knew it would easy to let the actions compute the required perl, instead of having to rebuild it. This is a nice win! Until today, when a new perl is release, or when I change the required perl for a distribution, I’d had to rebuild the workflow to get the new version range in place. Now, it’ll just work. Any new run, for any reason, like a new pull request, will run against the latest perl. If somebody submits a perl request that bumps the minimum perl, it won’t test on the dropped versions. Great!

Once again, this required weird stuff, because programming in GitHub Actions is often programming in a rich melange of YAML and bash. For example, here’s some of the newly-added code:

- name: Get minimum perl version
id: minimum-perl
shell: bash
run: |
    jq --raw-output 'if (.prereqs.runtime.requires.perl == null) then "v5.8" else .prereqs.runtime.requires.perl end' $/META.json
  echo "minimum-perl $PERL_MINIMUM"
  PERL_MINIMUM_NORMAL=$(perl -Mversion -E "say version->parse(q{$PERL_MINIMUM})->normal")
  echo "minimum-perl-normal $PERL_MINIMUM_NORMAL"
  echo "minimum-perl=$PERL_MINIMUM_NORMAL" >> $GITHUB_OUTPUT
- name: Get testable perl versions
id: perl-versions
uses: perl-actions/perl-versions@v1
  since-perl: $
  with-devel: true

Oh, right: YAML, bash, and jq. Yow.

❗️ Update 2: the next day…

I spent a bunch of time reading more about how to compose workflows and actions and overhauled things some more. See my next entry for more.

Having done that, the rjbs/dzil-build and rjbs/test-perl-dist actions were no longer relevant, so I will be deleting them. I removed links to them from this post.

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

File Index

"ch-1.pl" Defined by 1.

"ch-2.pl" Defined by 5.

Part 1: Defang IP Address

You are given a valid IPv4 address. Write a script to return the defanged version of the given IP address. A defanged IP address replaces every period “.” with “[.]".

The complete solution is contained in one file that has a simple structure.

"ch-1.pl" 1

preamble 2
defang recursively 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.

First, let’s consider how we know to make string substitutions. Regular Expressions are an obvious choice. Maybe a little too obvious to be fun. We could also convert the string to a list of characters and then loop over the list making adjustments as necessary. That sounds nicer. Instead of some ordinary loop though let’s add a little recursive spice!

defang recursively 3 ⟩≡

sub defang{
my($c, $defanged) = @_;
$defanged = [] if !$defanged;
return $defanged if @{$c} == 0;
my $x = shift @{$c};
if($x eq q/./){
push @{$defanged}, q/[.]/;
push @{$defanged}, $x;
defang($c, $defanged);

Fragment referenced in 1.

Defines: $defanged Never used.

Now all we need are a few lines of code for running some tests.

main 4 ⟩≡

say join(q//, @{defang([split //, q/])});
say join(q//, @{defang([split //, q/])});

Fragment referenced in 1.

Sample Run
$ perl perl/ch-1.pl 

Part 2: String Score

You are given a string, $str. Write a script to return the score of the given string. The score of a string is defined as the sum of the absolute difference between the ASCII values of adjacent characters.

We’ll contain the solution in a single function. The completed solution will just have that function plus a few tests. Instead of recursion this time we’ll use a redo block.

"ch-2.pl" 5

preamble 2
string score 6
main 7

This is our principal function. As can be seen, it’s very short! The logic here is simple: peel off characters until there’s just one left. Calculate the string score each time through. Well, to simplify things we’ll first actually convert the characters to their ascii values. That’s what the map at the start of the function does.

string score 6 ⟩≡

sub string_score{
my($s) = shift;
my $score = 0;
my @s = map {ord $_} split //, $s;
my $x = shift @s;
my $y = shift @s;
$score += abs($x - $y) if $x && $y;
unshift @s, $y;
redo if @s > 1;
return $score;

Fragment referenced in 5.

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

main 7 ⟩≡

say string_score q/hello/;
say string_score q/perl/;
say string_score q/raku/;

Fragment referenced in 5.

Sample Run
$ perl ch-2.pl 


The Weekly Challenge 272
Generated Code

TL;DR — Go down to the UPDATE for a toy example. The following was my original question before I was able to reproduce the issue in a…

Grant Applications Results of Voting May 24

Perl Foundation News

Published by Saif Ahmed on Tuesday 04 June 2024 16:08

An unusually busy period for the grants Committee, we have had 4 grants to discuss this round, including two critical Raku Grants, one Dancer2 project, and one on an LLM-based code quality assist. The Grants Committee is lacking in Raku representation and we have had to recruit a temporary member to help us.

### RakuAST This project on the syntax tree that underpins the new routines and commands and their parameters are handled during parsing, syntax checking and interpretting.

Results: Success.

Raku Ecosystem

This project was resubmitted with a new grant amount to allow to fall within the terms of Grants Applications. This complex tool was difficult to understand for the committee so we had additional insights derived from Raku board members.

Results: Success.

### Dancer2 Documentation Jason Crome, a past Grants Committee member and secretary, proposed this project. Good, upto date documentation is always critical, in any ecosystem, and Dancer2 is a particularly important one for Perl. The grant amount requested was not large, making this an easy application to approve.

Results: Success.

### Perl GPT A modern language without some involvement with AI is unheard of and Perl is no exception. PerlGPT is an interesting project aiming to improve code quality using an LLM. This project had been submitted previously, and narrowly failed to sufficently convince the grants committee. It was deemed worthy of a revisit and a small amount of preliminary work on the project was approved, to allow an opportunity for the grants comittee to get more clarity on the perceived merit of the project.

Results: Unsuccessful

Chopping UTF-8

domm (Perl and other tech)

Published on Tuesday 04 June 2024 08:00

While researching a very weird bug0 in Koha I had to figure out a way chop a string to a specific maximum length. In bytes and not in characters, because in that case the horrible format USMARC is used, whose spec starts with two red flags: It's from January 2000, and it's an "implementation of the American national standard", so you can bet that it only works (well) with ASCII and will be ... interesting when handling Unicode. But it's generally broken for longer strings1.

Bytes vs. Characters

I assume you know the difference between bytes and characters (or code points). If not: read this!

As you've probably haven't read the link, here's a very short summary:

  • UTF8 uses variable length to store letters in zeros and ones. Older formats (like ASCII) used a fixed length (eg one byte = 8 bit), but could therefore only represent a limited amount of letters.
  • "Regular" letters (if you're talking about English) take 1 byte.
  • But we can handle letters besides English. And we have "letters" like 🚲. 🚲 takes 4 bytes. See a lot of details here.
  • Usually, if a regular person talks about the length of a string, they count letters: "Hello" has 5 letters. "Hello🚲" has 6 letters.
  • Unfortunately, computers sometimes need to know the number of bytes (eg to store the data somewhere). "Hello" takes 5 bytes. "Hello🚲" takes 9 bytes.

How long is my string?

So let's compare "I love to ride my bicycle" with "I ♥ to ride my 🚲".

~$ perl -C -Mutf8 -MEncode -E 'say q{"I love to ride my bicycle" vs. "I ♥ to ride my 🚲"}'
   "I love to ride my bicycle" vs. "I ♥ to ride my 🚲"

The maybe weird command line flags are explained in this footnote2.

Per default, Perl counts characters, using length():

~$ perl -C -Mutf8 -MEncode -E 'say length("I love to ride my bicycle")'

So 25 characters.

~$ perl -C -Mutf8 -MEncode -E 'say length("I ♥ to ride my 🚲")'

And now only 16.

If we want to count bytes (which is something you should not usually do, because the computers should handle it for you), we need to use bytes::length():

~$ perl -C -Mutf8 -MEncode -E 'say bytes::length("I love to ride my bicycle")'

Also 25 bytes, because each of the basic English letters takes one byte.

~$ perl -C -Mutf8 -MEncode -E 'say bytes::length("I ♥ to ride my 🚲")'

But the fancy Unicode version now takes 21 bytes, because ♥ takes 3 bytes and 🚲 4, so 3 + 4 - 2 = 5 bytes more than characters.

Stuff it into limited space

Now say we only have 20 bytes to store this string. So we need to chop of some of the text, using substr():

~$ perl -C -Mutf8 -MEncode -E 'say substr("I love to ride my bicycle", 0, 20)'
   I love to ride my bi


If we do that on the fancy Unicode version:

~$ perl -C -Mutf8 -MEncode -E 'say substr("I ♥ to ride my 🚲", 0, 20)'
   I ♥ to ride my 🚲

We get the same string back! Because, by default, Perl counts characters. And the string only has 16 characters. But 21 bytes. Which is 1 byte too much. So we need to use bytes::substr():

~$ perl -C -Mutf8 -MEncode -E 'say bytes::substr("I ♥ to ride my 🚲", 0, 20)'
   I ⥠to ride my ð

What's that garbage?

As we're leaving the safe and padded space of regular Perl string handling and calling bytes, we unfortunately have to be a bit more careful and know about some Perl internals (which I will handwave a bit): Perl tracks if a string contains UTF-8. If you call bytes, it sort of forgets that the string contains the UTF-8 and now outputs raw bytes. But we want Perl to interpret that string returned from bytes::substr as UTF-8, so we explicitly have to tell it via decode_utf8 (imported from Encode). I find the name decode_utf8 a bit confusing, but it helps (me) to think about it like this: Decode this string of bytes (or octets as the docs say) which we know to contain UTF-8 into a Perl string of characters. So:

~$ perl -C -Mutf8 -MEncode -E 'say decode_utf8(bytes::substr("I ♥ to ride my 🚲", 0, 20))'
   I ♥ to ride my �

Yay, we have the ♥ back!

Another way to do this (so we don't have to use bytes) is to pass substr the byte representation of the strings, which we can generate using encode_utf8. Which is again a bit confusing, unless you think about it like this: Take this Perl string and encode it into a bunch of bytes using UTF-8:

perl -C -Mutf8 -MEncode -E 'say decode_utf8(substr(encode_utf8("I ♥ to ride my 🚲"), 0, 20))'
   I ♥ to ride my �

Same, but a tiny bit nicer!

Anyway, we have the ♥ back. But the resulting string is bit ugly, because it ends with "�". As we've chopped a few bytes of the 🚲, we do indeed end up with an invalid symbol, which is rendered as �.

But how long is this mangled string?

~$ perl -C -Mutf8 -MEncode -E 'say bytes::length(bytes::substr("I ♥ to ride my 🚲", 0, 20))'

Yay, 20 bytes, now it fits!

Stuff it into limited space, but without trailing garbage

Now maybe we don't like that � at the end. There's a nice flag you can pass to decode_utf8() that I've learned about while working with/against the original bug: Encode::FB_QUIET.

perl -C -Mutf8 -MEncode -E 'say decode_utf8(substr(encode_utf8("I ♥ to ride my 🚲"),0,20),Encode::FB_QUIET)'
   I ♥ to ride my 

No more �! Because FB_QUIET tells decode_utf8 to ignore invalid bytes.

And how long is it?

perl -C -Mutf8 -MEncode -E 'say bytes::length(decode_utf8(substr(encode_utf8("I ♥ to ride my 🚲"),0,20),Encode::FB_QUIET))'

Even shorter, because now the string does not contain any bicycle parts :-)

All the strings

For fun, here are all the substrings from 1 to original string, without any "half" / invalid characters. You can see quite nicely that 🚲 takes a few steps before it can be completely rendered:

perl -C -Mutf8 -MEncode -E 'my $s= "I ♥ to ride my 🚲"; for my $l (1 .. bytes::length($s)) { say decode_utf8(substr(encode_utf8($s),0,$l),Encode::FB_QUIET)}'
I ♥
I ♥ 
I ♥ t
I ♥ to
I ♥ to 
I ♥ to r
I ♥ to ri
I ♥ to rid
I ♥ to ride
I ♥ to ride 
I ♥ to ride m
I ♥ to ride my
I ♥ to ride my 
I ♥ to ride my 
I ♥ to ride my 
I ♥ to ride my 
I ♥ to ride my 🚲



0 When searching for one specific word, the request crashed with a 500 error. This was / is caused (I think) by Koha storing a rather long string in a byte-limited field and chopping of some data. And one document that could by found by that specific word happened to have an Umlaut (which needs two bytes to store) in place where those two bytes would be chopped in half so the long string fits into the bytes. Resulting in a broken utf-8 character. Which caused the site to explode when it tried to render the search result. The quick fix was to add one space to the data, so the Umlaut was completely outside the shortened string. Very ugly, but worked. Not sure if I should be proud or ashamed of this "fix".

1 See this Koha bug. The real problem is that USMARC uses an int with 4 digits to store the size of a field, followed by 5 digits for the offset. So the max size for one record is 99999 bytes and the max size for one field in that record is 9999 bytes. But MARC::Record does not check the actual size, so if you store data in a field that's 10009 bytes long starting at offset 00100, the matching part of the metadata/header will be 1000900100. If you later try to parse this record, the first 4 digits will be used to indicate the length to read, i.e. 1000 bytes (instead of 10009 bytes), and the offset will be 90019 instead of 00100, thus reading in completely crap (or nothing, if the whole record is smaller).

2 Command line flags explained:

  • -C is short for -CESL which turns on UTF-8 for various input and output streams (STDOUT etc). See perldoc perlrun.
  • -Mutf8 loads the module utf8 and is the same as calling use utf8; in the source code. This tells Perl that the source code itself contains UTF-8 characters. Like 🚲...
  • -MEncode loads Encode.

Revisiting old code (and more)

Perl on Medium

Published by Michael Eaton on Monday 03 June 2024 20:15

I’m a packrat. I always have been and my family can confirm.

workflower, for my dzil testing workflows

rjbs forgot what he was saying

Published by Ricardo Signes on Sunday 02 June 2024 12:00

Starting ages ago, once in a while somebody would show up and offer me a commit that would add some automated testing system to my open source repositories. I liked the idea, but it always felt like a free puppy. I didn’t know how it worked, I didn’t know how the YAML file (always YAML!) was put together, and I didn’t know what I was supposed to do when something went wrong.

Usually, I politely declined. Sometimes, I’d add it and ignore whatever happened. This is one of those places where I knew I could do better by learning the thing, but I also knew that it was going to require a lot more effort from me than I’d end up saving. I try not to get worked up about what I “should” do when it comes to the software I write for myself and give away.

Over time, I’ve gotten a better handle on how these systems work. We use one at work, which helped. Also, GitHub Actions is so integrated with GitHub that it’s been easy to sort of peek into that world while doing my “normal” GitHub things.

Eventually, I realized the huge value I’d get out of an automated testing system: testing on multiple perls!

It was never interesting, to me, to have some server run my test suite. I was going to run it anyway, and I try to make sure my test suites are fast. So, sure, I could push up changes and see them pass on the server, but I wasn’t going to push until I knew they did pass! (Usually.) The thing is: I run my tests on perl v5.38 or v5.39 these days. For years, I’ve been running a very recent perl for day-to-day use, but I release that code to be run on older perls. There are ways to do that multi-perl testing locally, but they’re mostly a drag.

When I found out about the perldocker/perl-tester Docker images, I realized I could use those to have GitHub Actions test my code against many perls in one go, and I’d only have to think about it one time. This was going to be useful!

As with most things, I started by looking for people already doing this, and then I stripped out all the variables and shoved it into a Dist::Zilla plugin. I’m afraid I no longer remember what my sources were, but the outcome was pretty simple. I wrote a dzil workflower command that installs a GitHub Action workflow file into your checkout. The workflow does this:

  • install Dist::Zilla and the plugins needed by the repo’s dist.ini
  • builds a new tarball of the dist and stores it as a build artifact
  • tests that tarball under every perl supported by the dist

“Every perl supported” is basically every (major) version of perl from v5.8 to v5.38 plus blead, but then pruned down based on the dist’s minimum perl. It won’t bother testing on v5.22 if the minimum perl is v5.24. For each perl, it uses the perl-tester Docker image, retrieves the build artifact, extracts it, and does the normal “install prereqs and run tests” you’d expect.

For fun, I use yath and Test2::Harness::Renderer::JUnit so I can feed them to mikepenz/action-junit-report and get nice little summaries of test failures. In the future, I might upload the test event archive for failing tests. For now, it hasn’t come up.

It’s been a big help in avoiding stupid mistakes, mostly related to things like adding postfix deref to code meant to run on older perl. Everybody knows that my preferred solution is to bump my minimum required perl to v5.20 or later, but I don’t always do what I prefer.

This week, I’ve been reading O’Reilly’s Learning GitHub Actions, which has been helpful. Today, after reading a few chapters, I got to puttering about with workflower and wondering whether I could speed things up. It turns out that there wasn’t much GitHub-related for me to do, but I did notice that even though I was installing Dist::Zilla from apt, it was later being reinstalled! This cost valuable time!

There were two things at play. One is that I’m installing things with cpanm, and when you run cpanm Some::Module, it will interpret it as a request to install-or-upgrade, rather than only install. There’s no switch to say “do not upgrade if already installed”, as far as I know. That wouldn’t have been a problem, I think, but also, running dzil authordeps --missing was spitting out Dist::Zilla::Plugin::CPANFile even though it was installed. It had to be installed, because it comes with Dist::Zilla itself!

I banged on this mystery for a little while, but finally decided to try a tactic that didn’t solve the mystery, but did render it irrelevant. I switched to cpm. cpm is an alternative to cpanm, and it’s focused on speed. I happened to be at the YAPC::Asia where it got its first big announcement, and its speed was no joke. I’m not usually in a rush, so I mostly still use cpanm. I’m a creature of habit. Here, though, it looked like it would be a double win: not only was it fast, but it won’t reinstall things already present. Some testing showed off that this was going to be a nice little win.

I just uploaded the new version of workflower. It’s part of the @RJBS bundle, and really I don’t make any promises about its continued functioning, or any promises that I won’t radically change how it works. It’s for me, part of my tools. But it might work for you. I’d be happy to hear sounds of delight, but I’m not super into hearing complaints about it.

Anyway, rebuilding Dist::Zilla’s own workflow takes its full test run down from about 3.5 minutes to about 2.5. Email::MIME’s went down from around 2.5 minutes to around 1.5. They’re going from fast to slightly faster, but it’s still satisfying. Depending on when you read this, you may be able to see workflow results on GitHub.

I do expect that in the future I’ll make the whole thing better, but not until I have some code I’m working on a lot more. We’ll see when that happens…

Time is dwindling to book your trip to TPRC!

Perl Foundation News

Published by Amber Krawczyk on Saturday 01 June 2024 21:26

List of new CPAN distributions – May 2024


Published by perlancar on Saturday 01 June 2024 01:37

dist author abstract date
Alien-NLopt DJERIUS Build and Install the NLopt library 2024-05-01T05:00:12
Alien-cue PLICEASE Find or download the cue configuration language tool 2024-05-07T11:34:32
Alien-libversion GDT Alien wrapper for libversion 2024-05-01T20:53:07
Alien-poetry OLIVER Download and install poetry 2024-05-11T11:33:08
Amon2-Plugin-Web-Flash YOSHIMASA Ruby on Rails flash for Amon2 2024-05-26T03:25:23
App-Codit HANJE IDE for and in Perl 2024-05-20T08:51:39
App-NutrientUtils PERLANCAR Utilities related to nutrients 2024-05-26T00:06:02
App-htidx GBROWN generate static HTML directory listings. 2024-05-29T11:03:56
App-rdapper GBROWN a simple console-based RDAP client. 2024-05-29T23:00:49
Archive-SCS NAUTOFON SCS archive controller 2024-05-21T18:27:52
Authorization-AccessControl TYRRMINAL Hybrid RBAC/ABAC access control 2024-05-16T03:53:26
Bencher-ScenarioBundle-Accessors PERLANCAR Scenarios to benchmark class accessors 2024-05-13T00:05:21
Bencher-ScenarioBundle-Algorithm-Diff PERLANCAR Scenarios to benchmark Algorithm::Diff 2024-05-11T00:06:17
Bencher-ScenarioBundle-Graphics-ColorNames PERLANCAR Scenarios to benchmark Graphics::ColorNames and related modules 2024-05-12T00:05:13
Bencher-ScenarioBundle-Log-Any PERLANCAR Scenarios for benchmarking Log::Any 2024-05-20T00:06:19
Bencher-ScenarioBundle-Log-ger PERLANCAR Scenarios for benchmarking Log::ger 2024-05-21T00:05:46
Complete-Nutrient PERLANCAR Completion routines related to nutrients 2024-05-31T00:05:25
Couch-DB MARKOV thick CouchDB interface 2024-05-29T16:37:08
Data-HTML-Footer SKIM Data object for HTML footer. 2024-05-31T09:32:54
Data-Message-Board SKIM Data objects for message board. 2024-05-27T18:30:24
Data-Person SKIM Data objects for person. 2024-05-27T08:46:48
Dist-Zilla-Plugin-Sorter PERLANCAR Plugin to use when building Sorter::* distribution 2024-05-07T00:05:19
Dist-Zilla-Stash-OnePasswordLogin RJBS get login credentials from 1Password 2024-05-25T16:30:09
Feed-Data-AlJazeera LNATION The great new Feed::Data::AlJazeera! 2024-05-09T05:50:01
Feed-Data-BBC LNATION Waiting for comedians to present the news 2024-05-02T08:38:34
Feed-Data-CNN LNATION The rest of the world will follow. 2024-05-02T10:11:29
FreeDesktop-Icons HANJE Use icon libraries quick & easy 2024-05-31T17:26:09
Game-Cribbage LNATION The great new Game::Cribbage! 2024-05-15T00:15:17
Graphics-ColorNamesCMYK PERLANCAR Define CMYK values for common color names 2024-05-10T00:05:12
Graphics-ColorNamesCMYK-BannersCom PERLANCAR Basic CMYK colors from banners.com 2024-05-17T00:05:09
Graphics-ColorNamesCMYK-JohnDecemberCom PERLANCAR CMYK color names from johndecember.com 2024-05-19T00:05:21
Graphics-ColorNamesCMYK-Pantone PERLANCAR Pantone colors 2024-05-14T00:05:54
Graphics-ColorNamesCMYK-ToutesLesCouleursCom PERLANCAR CMYK colors from http://toutes-les-couleurs.com/ (red) 2024-05-16T00:06:24
Graphics-ColorNamesLite PERLANCAR Define RGB values for common color names (lite version) 2024-05-09T00:05:39
Hades-Realm-Rope LNATION Hades realm for Moose 2024-05-20T13:39:42
HashData-Color-CMYK-JohnDecemberCom PERLANCAR CMYK color names (from johndecember.com) 2024-05-18T00:05:57
HashData-Color-CMYK-ToutesLesCouleursCom PERLANCAR CMYK color names (from ToutesLesCouleursCom) 2024-05-15T00:06:01
HashData-Color-PantoneToCMYK PERLANCAR Mapping of Pantone color names to CMYK values 2024-05-08T00:05:41
HashData-ColorCode-CMYK-JohnDecemberCom PERLANCAR CMYK color names (from johndecember.com) 2024-05-22T00:06:06
HashData-ColorCode-CMYK-Pantone PERLANCAR Mapping of Pantone color names to CMYK values 2024-05-23T00:05:32
HashData-ColorCode-CMYK-ToutesLesCouleursCom PERLANCAR CMYK color names (from ToutesLesCouleursCom) 2024-05-24T00:06:00
Linux-Landlock MBALLARIN An interface to the Landlock sandboxing facility of Linux 2024-05-09T20:12:52
Locale-Unicode JDEGUEST Unicode Locale Identifier compliant with BCP47 and CLDR 2024-05-17T08:05:23
Log-Log4perl-Config-YamlConfigurator SVW Reads Log4perl YAML configurations 2024-05-29T07:51:19
Math-NLopt DJERIUS Math::NLopt – Perl interface to the NLopt optimization library 2024-05-01T07:53:48
Mojolicious-Plugin-Authorization-AccessControl TYRRMINAL Integrate Authorization::AccessControl into Mojolicious 2024-05-16T23:23:55
Mojolicious-Plugin-Config-Structured-Bootstrap TYRRMINAL Autoconfigure Mojolicious application and plugins 2024-05-20T13:39:53
Mojolicious-Plugin-Data-Transfigure TYRRMINAL Mojolicious adapter for Data::Transfigure 2024-05-18T03:42:37
Net-EPP-MITMProxy GBROWN A generic EPP proxy server framework. 2024-05-02T11:56:41
Ogma LNATION Command Line Applications via Rope 2024-05-07T08:27:11
OpenSearch LHRST It's new $module 2024-05-15T15:22:31
Password-OnePassword-OPCLI RJBS get items out of 1Password with the "op" CLI 2024-05-25T15:24:06
PerlIO-win32console TONYC Win32 console output layer 2024-05-26T13:03:53
Plack-Middleware-Zstandard PLICEASE Compress response body with Zstandard 2024-05-10T18:08:23
QRCode-Any PERLANCAR Common interface to QRCode functions 2024-05-06T00:06:19
RT-Extension-Import-CSV BPS RT-Extension-Import-CSV Extension 2024-05-15T18:16:51
Sah-SchemaBundle-Business-ID-NIK PERLANCAR Sah schemas related to Indonesian citizenship registration numbers (NIK) 2024-05-01T00:05:13
Sah-SchemaBundle-Business-ID-NKK PERLANCAR Sah schemas related to Indonesian family card number (NKK) 2024-05-02T00:05:52
Sah-SchemaBundle-Business-ID-NOPPBB PERLANCAR Sah schemas related to Indonesian property tax numbers (NOP PBB) 2024-05-03T00:05:32
Sah-SchemaBundle-Business-ID-NPWP PERLANCAR Sah schemas related to Indonesian taxpayer registration number (NPWP) 2024-05-04T00:05:59
Sah-SchemaBundle-Business-ID-SIM PERLANCAR Sah schemas related to Indonesian driving license number (nomor SIM) 2024-05-05T00:06:14
Salus LNATION The great new Salus! 2024-05-09T20:06:13
SortKey-Num-similarity_jaccard PERLANCAR Jaccard coefficient of a string to a reference string, as sort key 2024-05-30T00:05:29
Super-Powers LNATION The hiddden truth 2024-05-02T04:21:41
TableData-Business-ID-BPOM-NutritionLabelRef PERLANCAR Nutrients 2024-05-27T00:05:19
TableData-Health-Nutrient PERLANCAR Nutrients 2024-05-25T00:05:57
TableDataRole-Source-DBI PERLANCAR Role to access table data from DBI 2024-05-28T00:05:38
TableDataRole-Source-SQLite PERLANCAR Role to access table data from SQLite database table/query 2024-05-29T00:05:31
Tags-HTML-DefinitionList SKIM Tags helper for definition list. 2024-05-17T16:54:28
Tags-HTML-Navigation-Grid SKIM Tags helper for navigation grid. 2024-05-10T18:53:42
Tags-HTML-Tree SKIM Tags helper for Tree. 2024-05-01T16:50:02
Tk-DynaMouseWheelBind HANJE Wheel scroll panes filled with widgets 2024-05-20T18:53:11
URI-Shorten TEODESIAN Shorten URIs so that you don't have to rely on external services 2024-05-07T08:50:48
URI-Shortener TEODESIAN Shorten URIs so that you don't have to rely on external services 2024-05-07T15:53:48
Version-libversion-XS GDT Perl binding for libversion 2024-05-01T20:09:03
XDR-Parse EHUELS Parse XDR (eXternal Data Representation) definitions into an AST (Abstract Syntax Tree) 2024-05-17T13:01:54
e TIMKA The great new e! 2024-05-08T15:09:45
optional EXODIST Pragma to optionally load a module (or pick from a list of modules) and provide a constant and some tools for taking action depending on if it loaded or not. 2024-05-14T21:33:17
perl-libssh QGARNIER Support for the SSH protocol via libssh. 2024-05-28T08:35:27


Number of new CPAN distributions this period: 79

Number of authors releasing new CPAN distributions this period: 25

Authors by number of new CPAN distributions this period:

No Author Distributions
3 SKIM 6
9 RJBS 2
11 GDT 2
12 BPS 1
17 TONYC 1
18 LHRST 1
20 TIMKA 1
21 SVW 1