(dxxxix) 9 great CPAN modules released last week

r/perl

Published by /u/niceperl on Saturday 15 March 2025 23:12

(dxxxix) 9 great CPAN modules released last week

Niceperl

Published by Unknown on Sunday 16 March 2025 00:11

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

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

perldelta for year of ExtUtils::ParseXS changes

Perl commits on GitHub

Published by iabyn on Saturday 15 March 2025 14:49

perldelta for year of ExtUtils::ParseXS changes

Add a perldelta entry mentioning that ParseXS has been heavily
refactored over the last year.

I haven't been adding entries for each monthly release as it was a work
in progress, and most changes weren't externally visible.

It's still a work in progress, but I'm intending to defer any further
changes until after the 5.42.0 release, so now seems good time for the
perldelta entry.

Scientist in Perl

blogs.perl.org

Published by Mohammad Sajid Anwar on Saturday 15 March 2025 13:43

Have you heard of CPAN module Scientist?
Please find below a gentle introduction.
https://theweeklychallenge.org/blog/scientist-in-perl

Seeking advice: scheduled data acquisition

r/perl

Published by /u/Patentsmatter on Saturday 15 March 2025 09:19

Something that comes up in my work is keeping track of certain web pages that provide relevant data without providing an api. Think of it as a "recent news" page, where the text of some older news may change (e.g. replacement of attached files, added information, corrections, whatever). Each news item contains some core information (e.g. the date) and also some items that may or may not be present (e.g. attached files, keywords, etc.). Unfortunately there is no standard of optional items, so these have to be treated as an open-ended list.

I want to read the news page daily and the old news items every 6 months or so.

What would be a good way to compose a scheduler app, and what would be a recommended way to store such data?

My idea was to create an SQLite database table to keep track of the tasks to do:

  • reading the news page
  • reading individual news items

I'd also envisage a set of database tables for the news items:

  • Table "item" contains the information that is guaranteed to be present, in particular an item_id
  • Table "field" contains the additional information for each item, linked to the news item by the item_id

Would you create an object that handles both in-memory storage of news items and the methods to store the item in the database or read an item therefrom? Or would you rather separate storage methods from data structures?

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

remove indirect calls to import() method

Perl commits on GitHub

Published by mauke on Saturday 15 March 2025 08:49

remove indirect calls to import() method

... i.e. turn `import Foo "bar"` into `Foo->import("bar")`.
release_schedule: add Lukas Mai for dev release 5.41.10

    <mauke> hydahy, LeoNerd: I'd be interested in doing the 5.41.10
            release. (I might need some assistance as I've never
            released a perl before.) can I jump in?
    <LeoNerd> mauke: Ohyeah sure.. I can assist on that then

Why Deriv Supports the Perl Ecosystem

r/perl

Published by /u/oalders on Friday 14 March 2025 18:30

release_schedule: remove Zefram from release engineer backup list

RIP Zefram.
Rename the 'any' and 'all' features and experimental warnings to 'keyword_any' and 'keyword_all'

This avoids confusion with the `use feature ':all'` ability

(As requested by https://github.com/Perl/perl5/issues/23104)

Text Extraction in Perl

blogs.perl.org

Published by Mohammad Sajid Anwar on Friday 14 March 2025 15:37

Ever wanted to extract text from an image in Perl?
Here is my story to do the same.
Enjoy !!!

https://theweeklychallenge.org/blog/extraction-in-perl

I haven't asked a question here in a long time, but I need some Perl expert opinions on the matter. I am working on a 2FA system for our ancient Perl based web application.

If you need a "minimal reproducible example", just skip this question and don't waste our time.

The login web page has an AJAX JSON "POST" JS script calling our API.pm script /api/userLogin

The original Userlogin sub is passed the login form credentials, checks the password hash and username, then returns successfully. The return hash is checked and handed off to the Perl CGI module, where the header is fed application/json. $self->header_add(-Content_Type => 'application/json');

Well my 2FA process simply uses this sub to check if a user has 2FA enabled, and returns a QR code, the 2FA type, and a secure session token if they have it.

After the user enters the authentication code on the front end, it calls the login sub again via ajax, except with our secret key instead of a password.

The key gets validated server side via our generated and saved secret code, our login "token" is spent, and we officially pass login.

However, upon return, it just prints out a hash and redirects to https://localhost/testapp/api/userLogin

I can't for the life of me can't find out why my standard AJAX login call returns fine, but the 2FA call returns a sharted out hash and the raw api file path. To add insult to injury, the 2FA process technically works, logs me in, and creates a valid login session via my browser. I can simply go to my correct testapp url, and it's golden. It seems to strictly be redirect related.

I have debugged and printed out the ENTIRE CGI object. You can see that in the second script I posted below. That postrun script essentially constructs and returns the CGI object to the browser. However, both the login AND 2FA header type seem to know its application/json. Also, there is nothing in the original login process that calls any kind of "redirect", it simply returns the hash and the js ajax success handles that home redirect. So how it even directs to a raw hash and raw file path is beyond me.

sub api_userLogin($)
{
  #here
   print STDERR "[-----------------------]\n";
   print STDERR "api.pm userLogin hit\n";
   print STDERR "[-----------------------]\n";
  my $self = shift;
  my %qparams = $self->get_matched_query_params(qw/_resume authonly pwd u CSRFToken key/);
  my $data = {};
  print STDERR Dumper(\%qparams);
  print STDERR "[-----------------------]\n";

  my $protocol = $ENV{'HTTPS'} ? 'https' : 'http';  # Check for HTTPS protocol
  my $host = $ENV{'HTTP_HOST'} || '';  # Get the host (domain:por
  print STDERR "Here is the host: $host \n";
  my $request_uri = $ENV{'REQUEST_URI'} // '';
  print STDERR "Here is the uri upon calling userLogin: $request_uri \n";

  # Get the User.
  my $user = eval{ User::find_user('any', $qparams{'u'}) };
  if ( $self->catch_exception() ) {
    $data->{'error'} = User::LOGIN_ERROR();
  }
  my ($type, $keyGen);
  if ( !$data->{'error'} ) {
    # If we have the user, test the password.
    # However, let's check for 2FA first.
    if(defined($qparams{'key'}) && $qparams{'key'} ne ''){
      print STDERR "api.pm key login triggered\n";
      eval{$user->login($qparams{'pwd'}, {'2FA_key' => $qparams{'key'}});}
      #set return to 
    }
    else {
      eval {($type, $keyGen) = $user->login($qparams{'pwd'}); };
    }
    if ($self->catch_exception()) {
      $data->{'error'} = User::LOGIN_ERROR() unless ($user && $user->logged_in());
      $self->logout();
      $self->dbh()->commit(); # Required to preserve login lock and eventlog.
      die($data->{'error'});
    }
    #check if passed back 2fa and keygrn
    if($type eq '2FA') { 
      $self->session_recreate();
      $self->send_session_cookie();
      print STDERR "2FA returning login key to AJAX...\n";
       #$data = {'success' => 1, 'twofactor' => '2FA', 'keyGen' => $keyGen, , 'CSRFToken'=>$qparams{'CSRFToken'}, $user->vars_hash([ qw/userid name abbr email companyid/ ])} unless ($data->{'error'});
        $data = {'success' => 1, 'twofactor' => '2FA', 'keyGen' => $keyGen, , 'CSRFToken'=>$qparams{'CSRFToken'}} unless ($data->{'error'});
        
       return $data;
    }
  }
  $data = {'success' => 1, $user->vars_hash([ qw/userid name abbr email companyid/ ])} unless ($data->{'error'});

  unless ( $qparams{'authonly'} || $data->{'error'} ) {
    # Set the session cookie.
    print STDERR "setting session cookie\n";
    $self->session_recreate();
    $self->session->param('userid' => $user->_id());
    $self->session->param('uid' => $user->_id());
    $self->session->param('abbr' => $user->{'abbr'});
    $self->session->param('disclaimer', $user->{'companyabbr'});
    if ( $qparams{'_resume'} ) {
      print STDERR "qparams _resume triggered in api userlogin process\n";
      $data->{'_resume'} = scalar $qparams{'_resume'};
    }
    else {
      if(defined($qparams{'key'}) && $qparams{'key'} ne ''){ 
      print STDERR "[-------------------------------------------------------]\n";
      print STDERR "KEY CREDENTIAL DEFINED. Token passed. Returning session...\n";
      print STDERR "[-------------------------------------------------------]\n";
      $self->send_session_cookie();
      # Temp solution was to manually redirect to the origin url. 
      #$self->header_add(-nph => 1);
      #my $tempcgi = CGI::referer();
      #return $self->redirect($tempcgi);
      return $data;
      }
    }

    $self->send_session_cookie();
  }

  # Return the JSON data.
  print STDERR "returning JSON data\n";
  return $data;
}

Here is our cgi_postrun sub that constructs and returns the page to the browser.

sub cgiapp_postrun {
  print STDERR "cgiapp_postrun called. \n";
  print STDERR "The calling function is: ", (caller 1)[3], "\n";
  my ($self,$output_ref) = @_;
  my $q = $self->query();
  #the output ref is what is getting dumped out here. 
  #print STDERR "-----------------------------OUTPUT_CGI_DEBUG----------------------------\n";
  #print STDERR Dumper($output_ref);
  #my $tempcgi = CGI::referer();
  #print STDERR Dumper($tempcgi);
  #print STDERR "-----------------------------DUMPING HEADER----------------------------\n";
  #print STDERR Dumper($self->header());
  #print STDERR "-----------------------------DONE DUMPING POSTRUN--------------------------------\n";

  eval {
    Class::fulfill_all_promises();
  };
  Class::clear_cache();
  if($@) {
    $$output_ref = $self->error_handler();
  } else {
    commit();
  }

  my $headers = $self->header();
  my $content_type = $headers->type() // 'text/html';
  my $header_status = defined($headers->status())? pos_integer(substr($headers->status(),0,3)) : 200;
  my $header_type = ($header_status == 304)? 'cache' : $self->header_type() // 'none';

  #print STDERR "Post run headertype: $header_type \n";
  print STDERR "Post run content_type: $content_type \n";

  # No body for redirect or cache responses
  $$output_ref = '' if in_array($header_type, [qw/cache redirect/]);

  if( !$ENV{CGI_APP_RETURN_ONLY} && $header_type ne 'none') {
    if($$output_ref && $header_type eq 'header') {
      # Set, or unset inactivity monitoring cookies.
      if ( $self->get_user() ) {
        print STDERR "cgiapp_postrun getuser called. \n";
        my $cookie = new CGI::Cookie({ -name=>'jobtracker_isactive', -secure=>1, -value=>1, -samesite=>"Strict" });
        $self->header_add( -cookie => [ $cookie ] );
      } else {
        my $exp = '-10d';
        my $cookie1 = new CGI::Cookie({ -name=>'jobtracker_blankscreen', -secure=>1, -value=>'', -expires=>$exp, -samesite=>"Strict" });
        my $cookie2 = new CGI::Cookie({ -name=>'jobtracker_endsession', -secure=>1, -value=>'', -expires=>$exp, -samesite=>"Strict" });
        my $cookie3 = new CGI::Cookie({ -name=>'jobtracker_isactive', -secure=>1, -value=>'', -expires=>$exp, -samesite=>"Strict" });
        my $cookie4 = new CGI::Cookie({ -name=>'jobtracker_timeout', -secure=>1, -value=>'', -expires=>$exp, -samesite=>"Strict" });
        my $cookie5 = new CGI::Cookie({ -name=>'jobtracker_scanmode', -secure=>1, -value=>'', -expires=>$exp });
        my $cookie6 = new CGI::Cookie({ -name=>'jobtracker_scan_timeout', -secure=>1, -value=>'', -expires=>$exp });

        $self->header_add( -cookie => [ $cookie1, $cookie2, $cookie3, $cookie4, $cookie5, $cookie6 ] );
      }

      # Add header and footer to HTML
      if(!$self->param('no-html-header') && $content_type =~ qr'^text/html') {
        print STDERR "add header hit. \n";
        $$output_ref = $self->get_header().$$output_ref.$self->get_footer();

      } elsif(ref $$output_ref) {
        # Force refs to string
        print STDERR "just shit out output as string. \n";
        $$output_ref = $$output_ref.'';
      }
      #print STDERR "This is the output_ref in cgi post run:\n";
      #print STDERR Dumper($$output_ref);
      #print STDERR "---------------------------------------\n";
      # Compress response, if allowed
      if(!$headers->exists('-content-encoding') && !$headers->exists('-content-length') && in_string('gzip', $q->http('ACCEPT_ENCODING')) ) {
        $$output_ref = Compress::Zlib::memGzip($$output_ref);
        $self->header_add( -Content_Encoding => 'gzip' );
      }

      # Send Content-Length
      if(!$headers->exists('-content-length') && !$headers->exists('-transfer-encoding')) {
        $self->header_add( -Content_Length => length $$output_ref );
      }

      # Browser Etag caching
      if(!$self->http_method('post') && !in_string('no-cache', $headers->get('CACHE_CONTROL')) ) {
        unless($headers->exists('-last-modified') || $headers->exists('-etag')) {
          my $etag = md5_base64($$output_ref);
          if($self->cached_via_etag($etag)) {
            $$output_ref = '';
            $headers->delete('Content-Length');
          }
        }
      }
    }
    if($self->http_method('head'))
    {
      print STDERR "No body for HEAD requests. \n";
    }

    

    $self->send_session_cookie() if $self->session_loaded();
  }
  $self->session()->flush();
  $$output_ref = '' if $self->http_method('head');  # No body for HEAD requests
}

I need a Perl veteran for this one, especially someone who has delt with the ancient knowledge of Perl CGI. I am in unknown territory, and I'm missing something here. I'm missing some step, some call, something that I just can't seem to find.

I will continue debugging and running traces on these sub function calls, but I am at a loss. I feel like I should be asking what causes the browser to spit out a raw api file path and hash. If I can find out why a browser does that, maybe I can work backwards.

Oh and the Javascript AJAX call, just to be thorough.

$('#login_form').on('submit', function(event) {
    event.preventDefault();
    $.ajax({
      url: 'api/userLogin',
      method: 'post',
      data: $(this).serialize(),
      dataType: 'json',
      error: function(event) {
        alert(event.responseJSON.error);
      },
      success: function(data) {
         console.log("normal success hit");
         console.log("This is the data", data);
        if (data.twofactor === '2FA') {
          //show 2fa popup div with qr code. 
          var username = $('input[name="u"]').val();  // Directly grab the value from the username input field
          TwoFactorPopUp(username, data.keyGen, data.CSRFToken);
          return true;
        }
        if ( data._resume ) {
          var resume = JSON.parse(data._resume);
          window.location.replace(resume.url);
        } else {
          console.log("no resume, replacing window...");
          window.location.replace(BASE_URL);
        }
      }
    });

    return false;
  });

Introduction

In our previous blog post, we detailed a clever external redirect solution to address the Apache 2.4 regression that broke automatic directory handling when DirectorySlash Off was set. We teased the question: Can we achieve the same behavior with an internal redirect? Spoiler alert - Nope.

In this follow-up post, we’ll explore why internal rewrites fall short, our failed attempts to make them work, and why the external redirect remains the best and only solution.


The Apache 2.2 vs. 2.4 Behavior Shift

How Apache 2.2 Handled Directory Requests

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

What Changed in Apache 2.4

  • When DirectorySlash Off is set, Apache stops auto-redirecting directories.
  • Instead of treating /dir as /dir/, Apache tries to serve /dir as a file, which leads to 403 Forbidden errors.
  • DirectoryIndex no longer inherits globally from the document root - each directory must be explicitly configured to serve an index file.
  • Apache does not reprocess DirectoryIndex after an internal rewrite.

The Internal Rewrite Attempt

Our Initial Idea

Since Apache wasn’t redirecting directories automatically anymore, we thought we could internally rewrite requests like this:

 RewriteEngine On

 # If the request is missing a trailing slash and is a directory, rewrite it internally
 RewriteCond %{REQUEST_URI} !/$
 RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} -d
 RewriteRule ^(.*)$ /$1/ [L]

Why This Doesn’t Work:

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

The Per-Directory Fix (Which Also Fails)

To make it work, we tried to manually configure every directory:

<Directory "/var/www/vhosts/treasurersbriefcase/htdocs/setup/">
    Require all granted
    DirectoryIndex index.roc
</Directory>

Why This Also Fails:

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

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

FallbackResource (Why This Was a Dead End)

We briefly considered whether FallbackResource could help by redirecting requests for directories to their respective index files:

<Directory "/var/www/vhosts/treasurersbriefcase/htdocs/setup/">
    DirectoryIndex index.roc
    Options -Indexes
    Require all granted
    FallbackResource /setup/index.roc
</Directory>

Why This Makes No Sense

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

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


Sledge Hammer Approach: Direct Rewrite to the Index File

Another way to handle this issue would be to explicitly rewrite directory requests to their corresponding index file, bypassing Apache’s DirectoryIndex handling entirely:

RewriteEngine On
RewriteCond %{REQUEST_URI} !/$
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} -d
RewriteRule ^(.*)$ /$1/index.roc [L]

It works…

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

…but it’s not ideal

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

While this approach technically works, it reinforces our main conclusion: - Apache 2.4 no longer restarts the request cycle after a rewrite, so we need to account for it manually. - The external redirect remains the only scalable solution.

Why the External Redirect is the Best Approach

Instead of fighting Apache’s new behavior, we can work with it using an external redirect:

RewriteEngine On
RewriteCond %{REQUEST_URI} !/$
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} -d
RewriteRule ^(.*)$ http://%{HTTP_HOST}/$1/ [R=301,L]

Why This Works Perfectly

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

Conclusion

So, can we solve with an internal redirect?

  • NO! … because Apache does not reprocess DirectoryIndex after an internal rewrite.
  • Even explicit per-directory DirectoryIndex settings fail if Apache has already decided the request is invalid.
  • FallbackResource never applied, since Apache rejected the request with 403 Forbidden, not 404 Not Found.

Does our external redirect solution still hold up?

Yes!!, and in fact, it’s not just the best solution - it’s the only reliable one.

Lessons Learned

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

If you haven’t read our original post yet, check it out here for the full explanation of our external redirect fix.

In part III of this series we’ll beat this dead horse and potentially explain why this was a problem in the first place…

Perl has long been a powerhouse in the programming world, known for its text-processing capabilities and versatility in scripting. While…

Why Deriv Supports the Perl Ecosystem

perl.com

Published on Friday 14 March 2025 06:00

As an online trading company processing millions of transactions daily, we recognise technologies that stand the test of time. For 25 years, Perl has been integral to our operations, and we remain committed to the ecosystem that helped shape our technical foundation.

Architecture Built for Scale

From our 1999 launch, Perl’s unmatched text processing and CPAN’s modular approach enabled us to evolve into a global platform. Core systems handling complex financial workflows leverage Perl’s stability, with key components still running the same battle-tested code developed in our early years.

Engineering Milestones

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

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

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

Investing in Shared Infrastructure

Our support of MetaCPAN stems from a clear conviction: foundational tools deserve sustained backing. While our new projects explore different technical approaches, we actively maintain:

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

“Great technologies create lasting value,” says Chris Horn, Head of Engineering. “Our support for Perl’s ecosystem honours its foundational role in our growth while helping sustain resources that benefit developers worldwide.”

Our Open Source Commitment

Backing Perl’s ecosystem reflects Deriv’s long-standing belief in collaborative development. We’re proud to continue our MetaCPAN sponsorship through 2025 and support the Perl community as part of our ongoing commitment to open-source.

obfuscating Perl for fun and profit

blogs.perl.org

Published by Scott Lanning on Thursday 13 March 2025 19:54

(apologies for "promoting"(?) Perl obfuscation...)

Today I won a gift card at an in-office meeting with the following code. Challenge: print the numbers 1-100 in the most incomprehensible, inefficient way. My entry, edited for brevity:

#!/usr/bin/env perl
use v5.16;
splice @_, @_, -1, ++$_;
splice @_, @_, -1, ++$_;
splice @_, @_, -1, ++$_;
splice @_, @_, -1, ++$_;
splice @_, @_, -1, ++$_;
# plus 95 more of this
say join $/, @_;

Thinking about it more this evening, I came up with

$SIG {__DIE__} = sub { $_ = (pop)+0; chomp; $_%6?say:exit};
{ select undef,undef,undef,1; eval { die time-$^T }; redo; }

(where 6 instead of 101 so I don't have to wait 100 seconds (and to be honest I'm not sure if there'll be rounding errors)).

Wonder if any obfuscators could come up with better (the less inefficient, incomprehensible the better).

How to Fix Apache 2.4 Broken Directory Requests

Introduction

I’m currently re-architecting my non-profit accounting SaaS (Treasurer’s Briefcase) to use Docker containers for a portable development environment and eventually for running under Kubernetes. The current architecture designed in 2012 uses an EC2 based environment for both development and run-time execution.

As part of that effort I’m migrating from Apache 2.2 to 2.4. In the new development environment I’m using my Chromebook to access the containerized application running on the EC2 dev server. I described that setup in my previous blog. In that setup I’m accessing the application on port 8080 as http://local-dev:8080.

If, as in the setup describe in my blog, you are running Apache on a non-standard port (e.g., :8080) - perhaps in Docker, EC2, or via an SSH tunnel you may have noticed an annoying issue after migrating from Apache 2.2 to Apache 2.4

Apache 2.4 Drops the Port When Redirecting Directories!

Previously, when requesting a directory without a trailing slash (e.g., /setup), Apache automatically redirected to /setup/ while preserving the port. However, in Apache 2.4, the redirect is done externally AND drops the port, breaking relative URLs and form submissions.

For example let’s suppose you have a form under the /setup directory that has as its action “next-step.html”. The expected behavior on that page would be to post to the page /setup/next-step.html. But what really happens is different. You can’t even get to the form in the first place with the URL http://local-dev:8080/setup!

  • Expected Redirect (Apache 2.2):\ http://yourserver:8080/setup => http://yourserver:8080/setup/
  • Actual Redirect (Apache 2.4, Broken):\ http://yourserver:8080/setup => http://yourserver/setup/ (port 8080 is missing!)

This causes problems for some pages in web applications running behind Docker, SSH tunnels, and EC2 environments, where port forwarding is typically used.

Investigating the Issue

If you’re experiencing this problem, you can confirm it by running:

curl -IL http://yourserver:8080/setup

You’ll likely see:

HTTP/1.1 301 Moved Permanently
Location: http://yourserver/setup/

Apache dropped 8080 from the redirect, causing requests to break.

Workarounds

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

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

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

The Fix

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

Apache 2.4 Fix: Port-Preserving Rewrite Rule

<VirtualHost *:8080>
    ServerName yourserver
    DocumentRoot /var/www/html

    <Directory /var/www/html>
        Options -Indexes +FollowSymLinks
        DirectoryIndex index.html index.php
        Require all granted
        DirectorySlash On  # Keep normal Apache directory behavior
    </Directory>

    # Fix Apache 2.4 Directory Redirects: Preserve Non-Standard Ports
    RewriteEngine On
    RewriteCond %{REQUEST_URI} !/$
    RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} -d
    RewriteCond %{SERVER_PORT} !^80$ [OR]
    RewriteCond %{SERVER_PORT} !^443$
    RewriteRule ^(.*)$ http://%{HTTP_HOST}/$1/ [R=301,L]

    UseCanonicalName Off
</VirtualHost>

Explanation

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

Example: Running Apache in Docker on EC2 via SSH Tunnel

The Setup (see previous blog)

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

How the Fix Helps

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

Conclusion

Apache 2.4’s port-dropping behavior is an unexpected regression from 2.2, but we can fix it with a simple rewrite rule that restores the expected behavior without breaking anything.

If you’re running Docker, EC2, or SSH tunnels, this is a fix that will prevent you from jumping through hoops by altering the application or changing your networking setup.

Postamble

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

Introduction

In our previous posts, we explored how Apache 2.4 changed its handling of directory requests when DirectorySlash Off is set, breaking the implicit /dir → /dir/ redirect behavior that worked in Apache 2.2. We concluded that while an external redirect is the only reliable fix, this change in behavior led us to an even bigger question:

Is this a bug or an intentional design change in Apache?

After digging deeper, we’ve uncovered something critically important that is not well-documented:

Apache does not restart the request cycle after an internal rewrite, and this can break expected behaviors like DirectoryIndex.

This post explores why this happens, whether it’s a feature or a bug, and why Apache’s documentation should explicitly clarify this behavior.


What Happens When Apache Internally Rewrites a Request?

Let’s revisit the problem: we tried using an internal rewrite to append a trailing slash for directory requests:

RewriteEngine On
RewriteCond %{REQUEST_URI} !/$
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} -d
RewriteRule ^(.*)$ /$1/ [L]

Expected Behavior: - Apache should internally rewrite /setup to /setup/. - Since DirectoryIndex index.roc is set, Apache should serve index.roc.

Actual Behavior: - Apache internally rewrites /setup to /setup/, but then immediately fails with a 403 Forbidden. - The error log states: AH01276: Cannot serve directory /var/www/vhosts/treasurersbriefcase/htdocs/setup/: No matching DirectoryIndex (none) found - Apache is treating /setup/ as an empty directory instead of recognizing index.roc.


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

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

How Apache Processes Requests (Simplified)

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

Why Internal Rewrites Don’t Restart Processing

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

Is This a Bug or a Feature?

First, let’s discuss why this worked in Apache 2.2.

The key reason internal rewrites worked in Apache 2.2 is that Apache restarted the request processing cycle after a rewrite. This meant that:

  • After an internal rewrite, Apache treated the rewritten request as a brand-new request.
  • As a result, it re-evaluated DirectoryIndex and correctly served index.html, index.php, or any configured default file.
  • Since DirectorySlash was handled earlier in the request cycle, Apache 2.2 still applied directory handling rules properly, even after an internal rewrite.

In Apache 2.4, this behavior changed. Instead of restarting the request cycle, Apache continues processing the request from where it left off. This means that after an internal rewrite, DirectoryIndex is never reprocessed, leading to the 403 Forbidden errors we encountered. This fundamental change explains why no internal solution works the way it did in Apache 2.2.

Why It’s Likely an Intentional Feature

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

Why This is Still a Problem

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

Implications for Apache 2.4 Users

1. Mod_Rewrite Behavior is Different From What Many Assume

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

2. The Only Reliable Fix is an External Redirect

Since Apache won’t reprocess DirectoryIndex, the only way to guarantee correct behavior is to force a new request via an external redirect:

RewriteEngine On
RewriteCond %{REQUEST_URI} !/$
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} -d
RewriteRule ^(.*)$ http://%{HTTP_HOST}/$1/ [R=301,L]

This forces Apache to start a completely new request cycle, ensuring that DirectoryIndex is evaluated properly.

3. Apache Should Improve Its Documentation

We believe this behavior should be explicitly documented in: - mod_rewrite documentation (stating that rewrites do not restart request processing). - DirectoryIndex documentation (noting that it will not be re-evaluated after an internal rewrite).

This would prevent confusion and help developers troubleshoot these issues more efficiently.


Conclusion: A Feature, But a Poorly Documented One

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

Future in Perl

r/perl

Published by /u/briandfoy on Thursday 13 March 2025 11:31

perl term animation collision detection not working

Perl questions on StackOverflow

Published by Sam Dorfman on Wednesday 12 March 2025 19:37

I'm trying to make a perl terminal animation where an enitity reverses direction when it collides with another object. Here is the code I have so far:

use Term::Animation 2.0;
use Term::Animation::Entity;
use Time::HiRes qw(time);
use Data::Dumper;
use Curses;
use strict;
use warnings;


main();

sub add_animal {
    my ($anim, $y) = @_;

    # Add the animal to the animation
    my $animal = $anim->new_entity(
        type => 'animal',
        position => [3, $y, 1],
        shape => '*',              
        color => 'r',
        callback_args => [1, 0, 0, 0],
        die_offscreen => 0,
        coll_handler => \&animal_collision, 
    );
}

sub animal_collision {
  my ($animal, $anim) = @_;
  my $collisions = $animal->collisions();
  #return unless defined $collisions;

  foreach my $col_obj (@{$collisions}) {
    # Get the current x direction from the callback_args
    my $x_dir = $animal->callback_args->[0];

    # Reverse the direction
    $animal->callback_args->[0] = -$x_dir;
  }
}



sub add_background {
    my ($anim, $screen_width, $screen_height) = @_;
    my $half_width = int($screen_width / 2);
    my $ground_level = int($screen_height * 0.7);

    for my $y (0..($screen_height)) {
      $anim->new_entity(
            shape => ['|'],
            position => [$half_width, $y, 21],
            color => ['w'], 
        );
    }
}

sub main {

  my $anim = Term::Animation->new();
  $anim->color(1);

  halfdelay(1);
  my $paused = 0;


  while(1) {
      my $screen_width = $anim->width();
      my $screen_height = $anim->height();
      my $half_width = int($screen_width / 2);
      my $ground_level = int($screen_height * 0.7);

      add_background($anim, $screen_width, $screen_height);
      add_animal($anim, ($ground_level - 1));

      # animation loop
      while(1) {
          my $current_time = time();

          # run and display a single animation frame
          $anim->animate() unless($paused);

          # use getch to control the frame rate, and get input at the same time.
          my $input = getch();
          if($input eq 'q') { quit(); }
          if($input eq 'r' || $input eq KEY_RESIZE()) { last; }
          if($input eq 'p') { $paused = !$paused; }
      }
      $anim->update_term_size();
      $anim->remove_all_entities();
  }

  $anim->end();
}

As of now, the animal object passes through the other object without any change of direction. Please let me know what is wrong with the collision detector or any other issues.

Future in Perl

blogs.perl.org

Published by Mohammad Sajid Anwar on Wednesday 12 March 2025 16:27


Have you worked with asynchronous task? If yes then this is one way of doing it in Perl.
Please checkout this post for more information.

https://theweeklychallenge.org/blog/future-in-perl

The scope for `my` var in the non C-style for loop

Perl questions on StackOverflow

Published by An5Drama on Wednesday 12 March 2025 08:29

While recently trying to get one algorithm for "Getting indices of matching parentheses". I can get what that algorithm means although with some problems with perl language.

The perl syntax is not obscure and can be got much with man perl... doc.

But I am a bit confused about my behavior with for loop. man perlsyn says:

If the variable is preceded with the keyword "my", then it is lexically scoped, and is therefore visible only within the loop. Otherwise, the variable is implicitly local to the loop and regains its former value upon exiting the loop. If the variable was previously declared with "my", it uses that variable instead of the global one, but it's still localized to the loop. This implicit localization occurs only for non C-style loops.

I know that "non C-style loops" mean those not like for (...;...;...){...}.

The 1st sentence can be shown by this which is similar to the example shown in the doc:

$i = 'samba';
# If the variable is preceded with the keyword "my", then it is lexically scoped, and is therefore visible only within the loop.
for (my $i = 1; $i <= 4; $i++) {
  print "$i\n";
}
print "$i\n";
# 1
# 2
# 3
# 4
# samba

But I can't understand what the 2nd means:

$inner = 'samba';
for ($i = 1; $i <= 4; $i++) {
  $inner = $i + 1;
}
print "inner: $inner\n";
# inner: 5

Here the alleged "local" var $inner seems to modify the outside var, and the "former value" 'samba' can't be "regain"ed.

For the 3rd, we can do some small tweaks for the above example:

$inner = 'samba';
for ($i = 1; $i <= 4; $i++) {
  my $inner = $i + 1;
}
print "inner: $inner\n";
# inner: samba

This works expectedly for "instead of the global one".

How to understand my behavior in for loop, especially for the above 2nd sentence in the quote?


Follow-up clarification with choroba's answer hints: When using the correct "non C-style loop" the 1st and 2nd sentence seem to mean that whether my is used for var has the same effect. But actually it is not that case.

sub foo { print "foo: $x\n"; }

$x = 7;
for $x (1 .. 3) {  # Implicit localisation happens here.
  print "$x\n";
  print "global $::x\n";  # Prints 1 .. 3 correspondingly.
  foo(); # Prints 1 .. 3 correspondingly.
}
print $x;  # Prints 7.

$x = 7;
for my $x (1 .. 3) {  # Implicit localisation happens here.
  print "$x\n";
  print "global $::x\n";  # Always prints 7.
  foo(); # Always prints 7.
}
print $x;  # Prints 7.

This is just the difference between local and my which just means dynamic scope vs lexical scope as the top answer there shows which is also said in the doc.

A local just gives temporary values to global (meaning package) variables. It does not create a local variable. This is known as dynamic scoping. Lexical scoping is done with my ...

The 3rd sentence example can be updated based on this QA. Here sub uses global package variable for $x which won't be influenced by my $x = 7; and also the latter assignments, i.e. $x = 7; and $x (1 .. 3), for that new lexical.

sub foo { print "foo: $x\n"; }

my $x = 7;

# code block2
$x = 7;
for $x (1 .. 3) {  # Implicit localisation happens here.
  print "$x\n";
  ## difference 1
  print "global $::x\n";  # Prints nothing for $::x.
  # > it uses that variable instead of the global one
  foo(); # Prints nothing for $x.
}
# > but it's still localized to the loop.
print $x;  # Prints 7.

follow-up question for ikegami's answer:

If we prepend:

my $x = 7;
for $x (1 .. 3) {  # Implicit localisation happens here.
  print "$x\n";
  print "global $::x\n"; # Prints nothing for $::x.
  foo(); # Prints nothing for $x.
}
print $x;  # Prints 7.

to the above sub foo { print "foo: $x\n"; } ... example, then the latter $::x also can't access the latter defined global var $x = 7;. IMHO my creates one new var which should not influence that global var.

But if we define the latter defined var as our $x = 7; which is one "lexical alias to a package (i.e. global) variable" as the doc says. Then all works as before. What is the reason for that?

Web Scraping in Perl: Step-by-Step Guide

Perl on Medium

Published by Data Journal on Tuesday 11 March 2025 11:47

In this guide, I will cover everything you need to know to start web scraping in Perl, including the tools you’ll use, how to extract data…

Modify Batch %0 variable backslashes

Perl questions on StackOverflow

Published by George Hunda on Monday 10 March 2025 23:17

I'm trying to use my batch script's file path as part of a Perl find and replace using the %0 variable, but since Windows uses backslashes this doesn't work as I'd hope. The string expands from s/^%~dp//gi into "s/^C:\Users\user\Desktop\scripts\//gi" with unescaped backslashes.

Custom delimiters like "m\\\gi" wont do anything here. All I can think of is to echo the %0 into a file and find/replace it into my desired format there, but this feels like a terrible workaround.

Ideally, the format would be C:\\Users\\user\\Desktop\\scripts\\script.bat in order for it to work plainly within the perl script.

I suppose I have two questions, can I somehow change the backslashes in the %0 batch variable to \\ or is there anything within Perl to workaround this?

How to use perl script for multiple files

Perl questions on StackOverflow

Published by k_a_r_o_l on Monday 10 March 2025 18:07

I have a perl script.

I can use it in linux command-line be executing on a single file by specifying the input file and the name of an output.

perl removesmalls.pl 500 1.fasta > 1_500.fasta

In this example 500 stands for specified cutoff number.

How to use it for multiple fasta files in one folder.

I would like still to have an option to specify the cutoff number.

The script:

## removesmalls.pl
#!/usr/bin/perl
use strict;
use warnings;

my $minlen = shift or die "Error: `minlen` parameter not provided\n";
{
    local $/=">";
    while(<>) {
        chomp;
        next unless /\w/;
        s/>$//gs;
        my @chunk = split /\n/;
        my $header = shift @chunk;
        my $seqlen = length join "", @chunk;
        print ">$_" if($seqlen >= $minlen);
    }
    local $/="\n";
}

So let say I have a folder "test_A" full of fasta files.

1.fasta 2.fasta 3.fasta ect.

I would like to specify cutoff number as 500

I would like to have an output in the same test_A catalog named as:

1_500.fasta 2_500.fasta 3_500.fasta ect.

Perl 🐪 Weekly #711 - Obfuscating Perl

dev.to #perl

Published by Gabor Szabo on Monday 10 March 2025 06:57

Originally published at Perl Weekly 711

Hi there!

As you might know I used to teach Perl and helped companies using Perl. Unfortunately, in the last couple of years only a few companies asked for my help with Perl and in most cases in areas I am not that familiar with. So I referred them to other, well known consultants.

Instead of Perl most of my clients are asking for help with Python and Rust. Especially because of the latter I felt the need to know more about C and C++. At least to the level where I understand the questions C/C++ programmers might have about Rust. So I dusted off my copy of "The C programming language" and started to learn again.

This time it will be especially fun as my son - who has been a professional programmer for more than 6 years now - decided to get a degree in Computer Sciences so he is also taking classes about C.

The way I learn is by trying to implement things and trying to explain them. So I am going to post about my new journey with C on the C Maven web site. You have been warned.

In other news we are celebrating Purim this week, when everyone dresses up as someone else. I wonder if I should dress up as a C programmer?

Enjoy your week!

--
Your editor: Gabor Szabo.

Articles

obfuscating Perl for fun and profit

Oh Oh

Class data for cheapskates

A one-liner

Once more unto the Wide character (U+XXXX) in substitution (s///)

As brian d foy puts it: Fake loading locale to get around a wide character warning

Discussion

Seeking Advice on Improving My Code

Probably the best way to learn any programming language is to try writing some code and then get feedback from more experienced programmers.

Perl import modules for all classes in file

Explicit is better than implicit? Automatic imports can cause hard-to-debug problems?

Perl

This week in PSC (182) | 2025-03-06

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

Welcome to a new week with a couple of fun tasks "Minimum Time" and "Balls and Boxes". 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 - 311

Enjoy a quick recap of last week's contributions by Team PWC dealing with the "Upper Lower" and "Group Digit Sum" tasks in Perl and Raku. You will find plenty of solutions to keep you busy.

Lower the Upper Sums!

Use of pack() and unpack(), very brave attempt. I still find it hard to get my head around. Thanks for making it look so easy.

TWC311

My all time favourite, never miss the opportunity to surprise me. I love the clean and easy to read solution. Highly recommended.

Upper Group

Don't you love the method chaining of Raku? It allows you to create cute little one-liner. You must checkout to see it yourself.

Perl Weekly Challenge: Week 311

A very special regex one-liner in Perl is my personal favourite. With it, we have detailed breakdown analysis and that is very handy. Great work, keep it up.

Flip Groups

Once again, we have a very special contributions. Regex with the power of Unicode properties can be deadly combination. Plenty to learn every week, well done and keep it up.

Switch Case?

Welcome back after a long break and what a comeback, I must admit. I am really impressed by story telling skill. Ofcourse the contribution is pretty too. Keep it up great work.

two lines

Unlike most weeks, this time we just have Raku one-liner magics for both task. Incredible, powerful Raku magics. Keep sharing knowledge with us.

Perl Weekly Challenge 311

Master of Perl one-liner is never going to miss the train and show the power of Perl regex. Well done and keep it up.

Up and Down and Round and Round

Plenty of Perl's regex magic every where. You really don't want to miss it. Great work, well done.

gROUP dIGIT sUM

Our latest champion back with yet another gem of a solution. Don't forget to try DIY tool, impressive work. Keep it up.

The Weekly Challenge #311

Thanks for reminding us about the y operator as normally we see the use of tr// for such case. Keep sharing knowledge.

Lower the Sum

I was hoping Postscript to make a comeback in the post this week and I got my wish fulfilled. Thank you for your contribution as always.

Weekly collections

NICEPERL's lists

Great CPAN modules released last week;
MetaCPAN weekly report.

Events

Boston.pm monthly meeting

Virtual event

Paris.pm monthly meeting

Paris, France

Dave Cross: Still Munging Data with Perl

Virtual Event

Boston.pm monthly meeting

Virtual event

German Perl/Raku Workshop Conference 2025

Munich, Germany

The Perl and Raku Conference 2025

Greenville, South Carolina, USA

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

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

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

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

PWC 311 Why do you build me up just to let me down?

dev.to #perl

Published by Bob Lied on Monday 10 March 2025 02:22

Another Perl Weekly Challenge, number 311 in a series of, as far as I can tell, infinity. We're gonna change some cases; we're gonna build some groups and tear them down. While we do it, we'll be singing badly out of key to Build Me Up, Buttercup, a Billboard Hot 100 hit from 1969, when I was a mere lad and none of the languages in the Weekly Challenge had yet been invented. Fun fact: the Foundations were the first multi-racial group to have a number one hit in the UK (Sri Lanka -- wasn't expecting that).

311 Task 1: Upper Lower

You are given a string that consists of English
letters only. Write a script to convert lower
case to upper and upper case to lower in the
given string.
  • Example 1: Input: $str = "pERl" Output: "PerL"
  • Example 2: Input: $str = "rakU" Output: "RAKu"
  • Example 3: Input: $str = "PyThOn" Output: "pYtHoN"

This is too easy if, by "English letters" we mean "stick to ASCII." It's considerably harder if we try to include anything that remotely smells of Unicode. But the cardinal virtue of Perl programming is laziness, so we'll stick to ASCII for a one-line program that transliterates as requested.

perl -E 'say tr/a-zA-Z/A-Za-z/r for @ARGV' pERL rakU PyThOn

Possibly notable: the trailing r on the tr/// function returns a copy of the modified string. The default behavior is to return a count of substitutions made, which is perhaps unintuitive but certainly has its uses.

311 Task 2: Group Digit Sum

You are given a string, $str, made up of
digits,and an integer, $int, which is less
than the length of the given string.
Write a script to divide the given string
into consecutive groups of size $int (plus
one for leftovers if any). Then sum the
digits of each group, and concatenate all
group sums to create a new string. If the
length of the new string is less than or
equal to the given integer then return the
new string, otherwise continue the process.
  • Example 1
    • Input: $str = "111122333", $int = 3
    • Output: "359"
    • Step 1: "111", "122", "333" => "359"
  • Example 2
    • Input: $str = "1222312", $int = 2
    • Output: "76"
    • Step 1: "12", "22", "31", "2" => "3442"
    • Step 2: "34", "42" => "76"
  • Example 3
    • Input: $str = "100012121001", $int = 4
    • Output: "162"
    • Step 1: "1000", "1212", "1001" => "162"

The Plan

The task has a basic recursive nature: do something to the string, then do the same thing to the string that results. I take a moment to convince myself that every time I apply the group-sum steps, the resulting string is going to get smaller, and eventually we really will get a string shorter than $n, and not a hike to an infinite loop.

Recursion has an ick factor greater than one. By "ick" I mean that I get confused when debugging. I'm instead going to use an overall structure that looks like

sub groupSum($str, $n)
{
   while ( length($str) > $n )
   {
        $str = mangle($str, $n);
   }
   return $str;
}

Now we have some sub-problems to implement mangle(). The first is how to group digits. The substr function seems like an obvious choice, or we could exploit regular-expression matching. If we put matching in an array context and use the g flag, it will return an array of matches:

my @group = ($str =~ m/.{1,$n}/g);
  • .{1,$n} -- match any character 1 to n times. $n is interpolated into the expression; the range doesn't have to be constant.
  • This works for the leftover that might be less than n long. Matching is greedy, so it will take n characters as long as it can, but when it can't, it will match the leftover bit.
  • Because of the leftover problem, /.{$n}/ would not work. That would need to match n characters every time, so the shorter bit at the end would be left out.

There's another way to do it which is more unique to Perl. The unpack function is designed to deal with data that is in fixed formats (and with binary formats, but that's a whole different subject). With unpack, you give it a format for the string. In our case, the format is n ASCII characters, repeated indefinitely.

my @group = unpack("(a$n)*", $str);

Once again, Perl does that do-what-I-mean thing, and this format also picks up the trailing characters that may be less than n long.

Okay, so we have a way to turn the string into an array of the appropriate-size groups. Each member of the group now needs to be separated into digits and added up. That could be a loop, but I choose map.

use List::Util qw/sum/;
my @sums = map { sum( split(//, $_) ) } @group 

And then those sums need to be combined into a new string.

return join("", @sums); 

All those bits can be turned into concise code without intermediate variables that Perl haters like to disdain, but that connoisseurs of punctuation and fine Perl can appreciate.

sub mangle($str, $n)
{
    return join "", map { sum( split(//, $_) ) } ($str =~ m/(.{1,$n})/g);
}

Well, now our mangle function has been reduced to one line. We may as well re-factor it into our original loop:

sub groupDigitSum($str, $n)
{
    while ( length($str) > $n )
    {
        $str = join "", map { sum( split("", $_) ) } unpack("(a$n)*", $str);
    }
    return $str;
}

Ta-da.

A digression

While I was putting this together, I was annoyed that the mangle function, which would only be used inside of groupDigitSum, was being defined at the same level and therefore entering (dare I say polluting) the global name space.

sub groupDigitSum { ... }
sub mangle { ... }

I grumbled that even Pascal allowed nested function definition. Surely Perl, the overflowing receptacle of the cast-off bits of so many languages that came before, could allow nested subs? Yes! Perl syntax allows the declaration of one sub inside another:

sub groupDigitSum { ...
   sub mangle { ... }
}

Wouldn't that be a nice way to encapsulate the utility function? Alas, no. Subroutines don't localize the same way that variables do. Even though it looks like mangle is inside the scope of groupDigitSum, it goes into the global name space and is still accessible from outside.

One way to make it truly local is to assign an anonymous sub to a scalar variable and use function de-referencing.

sub groupDigitSum { ...
  my $mangle = sub { ... };
  $mangle->($str, $n)
}

That solves the localization, but looks unnecessarily obfuscated, and makes it impossible to unit-test the mangle function.

Another way to hide it is to put these functions inside a package (or class), exporting one and not the other, but that's one step up and one step back -- we hide the mangle name, but we introduce a package/class name.

The Weekly Challenge - 312

The Weekly Challenge

Published on Monday 10 March 2025 00:00

Welcome to the Week #312 of The Weekly Challenge.

RECAP - The Weekly Challenge - 311

The Weekly Challenge

Published on Monday 10 March 2025 00:00

Thank you Team PWC for your continuous support and encouragement.

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

Part 1: Upper Lower

You are given a string consists of english letters only. Write a script to convert lower case to upper and upper case to lower in the given string.

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

"ch-1.pl" 1


preamble 2
upper lower calculations 3
main 4

For this problem we do not need to include very much. We’re just specifying to use the current version of Perl, for all the latest features in the language. This fragment is also used in Part 2.

preamble 2 ⟩≡


use v5.38;

Fragment referenced in 1, 5.

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

upper lower calculations 3 ⟩≡


sub upper_lower{
my($s) = @_;
my @c = split //, $s;
return join q//, map{
my $x = ord($_);
if($x >= 65 && $x <= 90){
chr($x + 32);
}
elsif($x >= 97 && $x <= 122){
chr($x - 32);
}
} @c;
}

Fragment referenced in 1.

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

main 4 ⟩≡


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

Fragment referenced in 1.

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

Part 2: Group Digit Sum

You are given a string, $str, made up of digits, and an integer, $int, which is less than the length of the given string. Write a script to divide the given string into consecutive groups of size $int (plus one for leftovers if any). Then sum the digits of each group, and concatenate all group sums to create a new string. If the length of the new string is less than or equal to the given integer then return the new string, otherwise continue the process.

"ch-2.pl" 5


preamble 2
group digit sum 9
main 10

To solve this problem we need to do the following

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

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

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


my $g = [];
my $groups;
for my $i (0 .. @{$c} - 1){
my $n = $i % $size;

if($n == 0){
$g = [];
push @{$g}, $c->[$i];
}
elsif($n == $size - 1){
push @{$g}, $c->[$i];
push @{$groups}, $g;
$g = [];
}
else{
push @{$g}, $c->[$i];
}
}
push @{$groups}, $g if @{$g} > 0;

Fragment referenced in 9.

Defines: $groups 7.

Uses: $c 9, $size 9.

compute the sums 7 ⟩≡


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

Fragment referenced in 9.

Defines: $sums 8.

Uses: $groups 6.

recombine 8 ⟩≡


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

Fragment referenced in 9.

Uses: $size 9, $sums 7.

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

group digit sum 9 ⟩≡


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

Fragment referenced in 5.

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

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

main 10 ⟩≡


MAIN:{
say group_digit_sum q/111122333/, 3;
say group_digit_sum q/1222312/, 2;
say group_digit_sum q/100012121001/, 4;
}

Fragment referenced in 5.

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

References

The Weekly Challenge 311
Generated Code

The Weekly Challenge - Guest Contributions

The Weekly Challenge

Published on Sunday 09 March 2025 00:00

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

(dxxxviii) 9 great CPAN modules released last week

Niceperl

Published by Unknown on Saturday 08 March 2025 23:09

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

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

(dcii) metacpan weekly report - DBI

Niceperl

Published by Unknown on Saturday 08 March 2025 23:04

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

Week's winner: DBI (+2)

Build date: 2025/03/08 22:03:54 GMT


Clicked for first time:


Increasing its reputation:

Using a Chromebook for Remote Web Development

Introduction

If you’re doing some development on a remote server that you access via a bastion host (e.g., an EC2 instance), and you want a seamless way to work from a Chromebook, you can set up an SSH tunnel through the bastion host to access your development server.

This guide outlines how to configure a secure and efficient development workflow using Docker, SSH tunnels, and a Chromebook.

Motivation

Your Chromebook is a great development environment, but truth be told, the cloud is better. Why? Because you can leverage a bucket load of functionality, resources and infrastructure that is powerful yet inexpensive. Did I mention backups? My Chromebook running a version of debian rocks, but in general I use it as a conduit to the cloud.

So here’s the best of both worlds. I can use a kick-butt terminal (terminator) on my Chromie and use its networking mojo to access my web servers running in the cloud.

Network Setup Overview

In this setup:

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

chromebook setup

Network Diagram

Here’s what it looks like in ASCII art…

   +--------------+    +--------------+    +--------------+
   | Chromebook   |    | Bastion Host |    |     EC2      |
   |              | 22 |              | 22 |              |
   |  Local SSH   |----|   Jump Box   |----| Development  |
   |  Tunnel:8080 | 80 | (Accessible) | 80 |  Server      |
   +--------------+    +--------------+    +--------------+

Setting Up the SSH Tunnel

To create an SSH tunnel through the bastion host:

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

Explanation:

  • -N: Do not execute remote commands, just forward ports.
  • -L 8080:EC2_PRIVATE_IP:80: Forwards local port 8080 to port 80 on the development server (EC2 instance).
  • user@bastion-host: SSH into the bastion host as user.

Once connected, any request to localhost:8080 on the Chromebook will be forwarded to port 80 on the EC2 instance.

Making It Persistent on Your Chromebook

To maintain the tunnel connection automatically:

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

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

Integrating with Docker on EC2

If your EC2 instance runs a Dockerized web application, expose port 80 from the container:

docker run -d -p 80:80 my-web-app

Now, accessing http://localhost:8080 on your Chromebook browser will open the web app running inside the Docker container on EC2.

Final Thoughts

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

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

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

One of the most important abilities of the programmers is ETL (Extract Transform and Load) file. In the old days like 2018 or something we…

This week in PSC (182) | 2025-03-06

blogs.perl.org

Published by Perl Steering Council on Thursday 06 March 2025 21:45

All three of us attended, but none of us had the time for significant discussion, so we decided to reclaim the time and make some progress on our various to-do list items.

[P5P posting of this summary]

Supercharging Your DevOps Workflow with bssh: A Guide to Bulk SSH and SCP

Perl on Medium

Published by Meir Michanie on Tuesday 04 March 2025 21:18

If you’re juggling multiple remote servers and you often find yourself running the same commands or transferring files across all of them…

Perl 🐪 Weekly #710 - PPC - Perl Proposed Changes

dev.to #perl

Published by Gabor Szabo on Monday 03 March 2025 09:20

Originally published at Perl Weekly 710

Hi there,

Do you remember, the weekly newsletter where I mentioned about the work carried out for PPC web portal?

Well, it is now fully functional and operative: PPC. It has everything that you need to know about the future plan of Perl. Not only that, you can also involve in the new feature request. It made the process smooth and easy to understand. You can also take part in the discussion as well. This is your opportunity to share your view on the work being carried out. Or if you have any suggestion, you can use the template to submit your ideas. Isn't it simple? The best part for me is the ability to join the discussion in the work being done before it becomes the part of future release.

In the last edition of newsletter, there was an announcement about German Perl/Raku Workshop and Perl Toolchain Summit. I encourage every community members to come forward and help the organisers to make it reach wider audiences. There is another announcement about The North American Perl and Raku Conference. Please do share the details with your colleagues and friends.

Are you new to Perl and want to learn in 2025 then checkout this post. Here is another: Step-by-Step Guide to Learning PERL Programming: From Novice to Expert.

Today is the Day 3 of Ramadan in England. May ALLAH s.w.t bless you with peace, happiness and prosperity.

Enjoy rest of the newsletter.

--
Your editor: Mohammad Sajid Anwar.

Announcements

From Code to Community: Sponsoring TPRC 2025

The North American Perl and Raku Conference will soon be upon us, and that means now is a great time to show your support for this very special event. This year there are many available sponsorship tiers and lots of opportunities for your organization to support the conference.

Announce Perl.Wiki.html V 1.24

For Perl Wiki fan, this is for you.

This week in PSC (181) | 2025-02-26

This week in PSC (179) | 2025-02-14

Looks like a busy meet, nice to see things are moving quickly.

Learning Perl in 2025

Nice collections, new to Perl then this is for you.

Step-by-Step Guide to Learning PERL Programming: From Novice to Expert

Worth reading even if you already know the language.

Articles

Hosting a Secure Static Website with S3 and CloudFront: Part I

Nice blog series sharing behind the scene secrets. If you are into cloud tech then you must checkout.

Hosting a Secure Static Website with S3 and CloudFront: Part IIa

Part II of the series carried forward.

Hosting a Secure Static Website with S3 and CloudFront: Part IIb

Third installment of the series for you.

Hosting a Secure Static Website with S3 and CloundFront: Part III

Time for the final word on the series. Highly recommended.

Slurp in Perl

Refresh the newly added command line flag '-g' in Perl v5.36.

MCE - How to?

A gentle introduction to MCE (Many-Core Engine) about parallel processing.

3D Object Scripting using OpenSCAD and Perl

Fun story telling skill with plenty of tech talk in between. I also liked the use of Object::Pad.

Mid-life upgrade for the MailBox suite

Are you a user of MailBox? If yes then please hekp Mark during the test phase of the rework.

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

Welcome to a new week with a couple of fun tasks "Upper Lower" and "Group Digit Sum". 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 - 310

Enjoy a quick recap of last week's contributions by Team PWC dealing with the "Arrays Intersection" and "Sort Odd Even" tasks in Perl and Raku. You will find plenty of solutions to keep you busy.

Arrays Intersect in Odd Ways

Love the use of v5.38 but surprised not to see method signature in action. Thanks for sharing knowledge.

TWC310

Good use of CPAN modules. As always we have a compact and cute solutions. Keep it up great work.

Intersection Sort

Raku one-liner by the master himself. Good to see Raku flexing muscles.

Perl Weekly Challenge: Week 310

Perl and Raku side by side as always. You will clearly see the similarities. Great work.

Odd Sets

I am a big fan of PDL. I just love the final product. Keep sharing the magic.

Perl Weekly Challenge 310

Here you have another fan of CPAN modules. Checkout the use of CPAN in one-liner. Keep it up great work.

Make it even

Love the story around the solution. It makes it fun reading, well done and keep it up.

Arrays and arrays

As the title suggests, plenty of loops. Why not? Go for it and don't forget to use DIY tool.

The Weekly Challenge #310

Smart use of 'mesh' from CPAN module List::SomeUtils. Clever move, well done.

Odd Arrays

Nice demo of Scalar solution. You get to learn something new every week by just reading the post. Highly recommended.

Rakudo

2025.08 Starting An Avalanche

Weekly collections

NICEPERL's lists

Great CPAN modules released last week.

Events

Boston.pm monthly meeting

Virtual event

Paris.pm monthly meeting

Paris, France

Dave Cross: Still Munging Data with Perl

Virtual Event

Boston.pm monthly meeting

Virtual event

German Perl/Raku Workshop Conference 2025

Munich, Germany

The Perl and Raku Conference 2025

Greenville, South Carolina, USA

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

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

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

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

RECAP - The Weekly Challenge - 310

The Weekly Challenge

Published on Monday 03 March 2025 00:00

Thank you Team PWC for your continuous support and encouragement.

From Code to Community: Sponsoring TPRC 2025

perl.com

Published on Sunday 02 March 2025 17:27

The North American Perl and Raku Conference will soon be upon us, and that means now is a great time to show your support for this very special event. This year there are many available sponsorship tiers and lots of opportunities for your organization to support the conference.

About the Conference

The Perl and Raku Conference 2025 is a community-led gathering of developers, enthusiasts, and industry professionals. Taking place June 27-29, 2025, in Greenville/Spartanburg, South Carolina, the conference features technical talks, training sessions, and networking opportunities that bring together the Perl and Raku communities.

Why Sponsor?

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

Conference Details

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

Sponsorship Tiers

Platinum Sponsor ($6,000)

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

Gold Sponsor ($4,000)

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

Silver Sponsor ($2,000)

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

Bronze Sponsor ($1,000)

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

Additional Sponsorship Opportunities

Technology Sponsor ($2,000 value)

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

Community Sponsor ($1,500)

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

Charity Raffle Sponsor

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

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

All Sponsors Receive

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

Named Sponsorship Opportunities

Exclusive naming rights available for:

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

About The Perl and Raku Foundation

Proceeds beyond conference expenses support The Perl and Raku Foundation, a non-profit organization dedicated to advancing the Perl and Raku programming languages through open source development, education, and community building.

Contact Information

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

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

Part 1: Arrays Intersection

You are given a list of array of integers. Write a script to return the common elements in all the arrays.

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

"ch-1.pl" 1


preamble 2
compute array intersections. 3
main 4

For this problem we do not need to include very much. We’re just specifying to use the current version of Perl, for all the latest features in the language. This fragment is also used in Part 2.

preamble 2 ⟩≡


use v5.38;

Fragment referenced in 1, 5.

We’ll take the arrays in pairs and build up a list of common elements. First we compute the common elements of the first two arrays and then proceed to check these against the remaining arrays. If any of these initial common elements are not found in subsequent arrays they are not included in future checks. Finally the remaining common elements are returned. If there are no common elements we return n/a.

compute array intersections. 3 ⟩≡


sub array_intersections{
my @common_elements;
my $x = shift @_;
my $y = shift @_;
if($x && $y){
my @common = map {
my $x = $_;
grep {$x == $_} @{$y}
} @{$x};
push @common_elements, @common;
}
{
$x = shift @_;
my @common = map {
my $x = $_;
grep {$x == $_} @{$y}
} @common_elements;
@common_elements = @common;
redo if @_ > 1;
}
return (join q/, /, @common_elements) || q#n/a#;
}

Fragment referenced in 1.

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

main 4 ⟩≡


MAIN:{
say array_intersections [1, 2, 3, 4], [4, 5, 6, 1], [4, 2, 1, 3];
say array_intersections [1, 0, 2, 3], [2, 4, 5];
say array_intersections [1, 2, 3], [4, 5], [6];
}

Fragment referenced in 1.

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

Part 2: Sort Odd Even

You are given an array of integers. Write a script to sort odd index elements in decreasing order and even index elements in increasing order in the given array.

"ch-2.pl" 5


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

To solve this problem we need to do the following

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

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

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


sub sort_odd_even{
my @i = @_;
my @odds = map { $i[$_] } grep {$_ % 2 != 0} 0 .. @_ - 1;
my @evens = map { $i[$_] } grep {$_ % 2 == 0} 0 .. @_ - 1;
my @odds_sorted = sort {$b <=> $a} @odds;
my @evens_sorted = sort {$a <=> $b} @evens;
my @common_elements;
do {
$common_elements[$_] = shift @odds_sorted if $_ % 2 != 0;
$common_elements[$_] = shift @evens_sorted if $_ % 2 == 0;
} for 0 .. @_ - 1;
return @common_elements;
}

Fragment referenced in 5.

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

main 7 ⟩≡


MAIN:{
say join q/, /, sort_odd_even 4, 1, 2, 3;
say join q/, /, sort_odd_even 3, 1;
say join q/, /, sort_odd_even 5, 3, 2, 1, 4;
}

Fragment referenced in 5.

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

References

The Weekly Challenge 310
Generated Code

MCE - How to?

The Weekly Challenge

Published on Sunday 02 March 2025 00:00

MCE, Many-Core Engine provides parallel processing capabilities in Perl.

(dxxxvii) 5 great CPAN modules released last week

Niceperl

Published by Unknown on Saturday 01 March 2025 22: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. Archive::Tar - Manipulates TAR archives
    • Version: 3.04 on 2025-02-25, with 16 votes
    • Previous CPAN version: 3.02 was 1 year, 10 months, 13 days before
    • Author: BINGOS
  2. Module::CoreList - what modules shipped with versions of perl
    • Version: 5.20250220 on 2025-02-24, with 43 votes
    • Previous CPAN version: 5.20250120 was 1 month, 4 days before
    • Author: BINGOS
  3. Object::Pad - a simple syntax for lexical field-based objects
    • Version: 0.820 on 2025-02-26, with 45 votes
    • Previous CPAN version: 0.819 was 1 month, 16 days before
    • Author: PEVANS
  4. PDL::Stats - a collection of statistics modules in Perl Data Language, with a quick-start guide for non-PDL people.
    • Version: 0.854 on 2025-02-25, with 16 votes
    • Previous CPAN version: 0.74 was 9 years, 2 months, 20 days before
    • Author: ETJ
  5. Text::ANSITable - Create nice formatted tables using extended ASCII and ANSI colors
    • Version: 0.610 on 2025-02-24, with 21 votes
    • Previous CPAN version: 0.609 was 1 year, 7 months, 11 days before
    • Author: PERLANCAR

PWC 310 Task 1 Arrays Intersection

dev.to #perl

Published by Bob Lied on Thursday 27 February 2025 14:46

The Task

PWC 310 Task 1, Arrays Intersection asks us to implement set intersection from lists of numbers. For musical accompaniment, I suggest Everywhere by Fleetwood Mac.

You are given a list of array of integers.
Write a script to return the common elements 
in all the arrays.
  • Example 1

    • Input: $list = ( [1, 2, 3, 4], [4, 5, 6, 1], [4, 2, 1, 3] )
    • Output: (1, 4)
  • Example 2

    • Input: $list = ( [1, 0, 2, 3], [2, 4, 5] )
    • Output: (2)
  • Example 3

    • Input: $list = ( [1, 2, 3], [4, 5], [6] )
    • Output: ()

The Plan

Use a hash as a set. If we knew that all the lists have only distinct elements, then we could just check that an element occurs the right number of times. But if a number can repeat in a list, then counting is not enough.

In the hash, map the number to a bit map. If the number occurs in list i, then bit i will be set. At the end, if the number of bits set is equal to the number of lists, then that number must occur in every list.

A possible limitation of using a bit map is that it limits us to 64 lists, which seems like an acceptable compromise. Perl also has the vec function for bit vectors, but that would require an hour of review and experimentation. Maybe I'll come back to it.

The Code

sub asect(@list)
{
    my %common;
    my $allBits = 2 ** scalar(@list) - 1;
    for ( 0 .. $#list )
    {
        my $bit = 1 << $_;
        $common{$_} |= $bit for $list[$_]->@*;
    }
    return [ grep { $common{$_} == $allBits } sort { $a <=> $b } keys %common ];
}
  • my %common -- the keys of this hash are the numbers from the lists.

  • my $allBits = 2 ** scalar(@list) - 1 -- This creates a mask of 1s for the number of lists. For instance, if there are 3 lists, '2**3-1` is 7, which is 111 in binary.

  • for ( 0 .. $#list ) the indexes of the lists.

  • my $bit = 1 << $_ An integer where exactly one bit is set: the one corresponding to the list number

  • $common{$_} |= $bit for $list[$_]->@*

    • Loop over the words in the _i_th list.
    • A little confusing here, because $_ has two different contexts. In for $list[$_]->@*, $_ is the list index from the top-level for loop, but in $common{$_} it refers to the number taken from the list.
    • The |= operator sets bit i if it occurs in list i, even if it occurs more than once.

At exit of the loop, every number from all the lists is present as a key in %common. That key maps to a value which has bits set corresponding to the lists in which it occurred. We want to return the numbers that have all the bits set. Breaking down the last statement from right to left:

  • sort { $a <=> $b } keys %common I'm adding a sort to create a predictable output order, which is useful in unit test.
  • grep { $common{$_} == $allBits } Selecting only the numbers that have all the bits set.
  • [ ... ] enclosing the result in square brackets returns an array reference. I prefer returning references for three reasons:
    • (1) It avoids an array copy, which could be inefficient.
    • (2) it means we always return a scalar, which resolves ambiguities if the function is called in an array context (for instance, as an argument to say or in a unit-test is() test).
    • (3) Because of reason (2), it's easier to write a unit test, and therefore I am more likely to write good unit tests.

I’m excited to announce the release of OrePAN2::S3, a new Perl distribution designed to streamline the creation and management of private CPAN (DarkPAN) repositories using Amazon S3 and CloudFront. This tool simplifies the deployment of your own Perl module repository, ensuring efficient distribution and scaling capabilities.

This effort is the terminal event (I hope) in my adventure in Perl packaging that led me down the rabbit hole of CloudFront distributions?

My adventure in packaging started many years ago when it seemed like a good idea to use RPMs. No really, it was!

The distribtions embraced Perl and life was good…until of course it wasn’t. Slowly but surely, those modules we wanted weren’t available in any of the repos. Well, here we are in 2025 and you can’t even grovel enough to get AWS to include Perl in its images? Sheesh, really? I have to yum install perl-core? Seems like someone has specifically put Perl on the shit list.

I’ve been swimming upstream for years using cpanspec and learning how to create my own yum repos with all of the stuff Amazon just didn’t want to package. I’ve finally given up. CPAN forever! cpanm is awesome! Okay, yeah, but I’m still not all in with carton. Maybe some day?

Key Features of OrePAN2::S3

  • Seamless Integration with AWS: OrePAN2::S3 leverages Amazon S3 for storage and CloudFront for content delivery, providing a highly available, scalable solution for hosting your private CPAN repository.

  • User-Friendly Setup: The distribution offers straightforward scripts and configurations, enabling you to set up your DarkPAN with minimal effort…I hope. If you find some points of friction, log an issue.

  • Flexible Deployment Options: Whether you prefer a simple S3-backed website or a full-fledged CloudFront distribution, OrePAN2::S3 accommodates both setups to suit your specific needs. If you really just want a website enable S3 bucket to serve as your DarkPAN we got your back. But be careful…

Getting Started:

To begin using OrePAN2::S3, ensure you have the following prerequisites:

  1. AWS Account: An active Amazon Web Services account.

  2. S3 Bucket: A designated S3 bucket to store your CPAN modules.

  3. CloudFront Distribution (optional): For enhanced content delivery and caching.

Detailed instructions for setting up your S3 bucket and CloudFront distribution are available in the project’s repository.

Why Choose OrePAN2::S3?

Managing a private CPAN repository can be complex, but with OrePAN2::S3, the process becomes efficient and scalable. By harnessing the power of AWS services, this distribution ensures your Perl modules are readily accessible and securely stored.

Oh, and let’s give credit where credit is due. This is all based on OrePAN2.

For more information and to access the repository, visit: https://github.com/rlauer6/OrePAN2-S3

We look forward to your feedback and contributions to make OrePAN2::S3 even more robust and user-friendly.

CPANSec is CNA for Perl and the CPAN ecosystem

CPAN Security Group

Published by Stig Palmquist, Timothy Legge and Breno G. de Oliveira on Tuesday 25 February 2025 21:00

The CPAN Security Group was authorized by the CVE Program as a CVE Numbering Authority (CNA) on Feb 25, 2025. A CNA assigns and manages CVE identifiers for projects in their scope.

Our scope is vulnerabilities in Perl and CPAN Modules (including End-of-Life Perl versions) found at perl.org, cpan.org or metacpan.org, excluding distributions of Perl or CPAN Modules maintained by third-party redistributors.

CVE is an international, community-based effort to identify, define and catalog publicly disclosed software vulnerabilities. To learn more about the CVE program, visit www.cve.org.

Report Vulnerability

Vulnerabilities should be reported according to the security policy of the affected project.

For more details, see our guide on how to Report a Security Issue in Perl and the CPAN ecosystem.

Contact Us

To request a CVE identifier, or to update a CVE we have issued, please send an email to cve-request@security.metacpan.org.

Subscribe to the cve-announce mailing list to be notified of new CVEs published by us.

For questions, disputes or other CNA related queries please use cna@security.metacpan.org. Disputes are handled according to the CNA rules.

Perl 🐪 Weekly #709 - GPRW and Perl Toolchain Summit

dev.to #perl

Published by Gabor Szabo on Monday 24 February 2025 06:49

Originally published at Perl Weekly 709

A reminder: The 27th German Perl/Raku Workshop will take place between May 12-14, 2025, in Munich, Germany with "ticketing systems" as the main theme. The focus will be on building ticketing software, addressing real-world challenges, and exploring practical solutions. In addition to this deep dive, attendees can look forward to a variety of cutting-edge and exciting topics presented by renowned speakers. Whether you're a seasoned developer or just curious about the latest in Perl and Raku, this event promises insights and inspiration for everyone!. See official website for more info.

Philippe Bruhat sent me a message: The Perl Toolchain Summit is happening again in 2025. This year, we're going to be in Leipzig, hosted by Daniel Böhmer and Tina Müller, from May 1st to May 4th, 2025. This year again, we're going to need the support of sponsors to be able to bring our 30+ attendees in the same place at the same time to work on the Perl and CPAN toolchain. Download our sponsor prospectus. See the announcement

After several weeks in Hungary I am now back to Israel. We are having in-person events in the other language communities. Unfortunately not Perl.

However, I still offer help to companies that would like to reduce their bugs in their programming environment in Perl, Python, or Rust or that would like help introducing either of those languages.

Have a nice week!

--
Your editor: Gabor Szabo.

Announcements

Announcing the Perl Toolchain Summit 2025!

The 15th Perl Toolchain Summit will be held in Leipzig, Germany, from Thursday May 1st till Sunday May 4th, 2025.

Articles

PEL - Part of a Emacs-specific project

Perl topics in PDF

zeroperl: Sandboxing Perl with WebAssembly

Get in loser. We're rewinding the stack. Sandboxing Perl with WebAssembly - Part 2.

Isn't it super-exciting that perl can be run in a browser these days?

Polishing the T-urtle

Cellgraph 0.7 is out. (App::GUI::Cellgraph - draw pattern by cellular automata)

Programmable Parametric 3D Modelling Using Perl and OpenSCAD

CPAN

What's new on CPAN - January 2025

A curated look at last month’s new CPAN uploads for your reading and programming pleasure.

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

Welcome to a new week with a couple of fun tasks "Arrays Intersection" and "Sort Odd Even". 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 - 309

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

TWC309

Another cute and compact solutions. Keep it up great work.

Min or Min

Reduction Operator of Raku showing off the power. Raku Rocks !!!

Substracting Pairs

New to PDL? PDL is the talk of the town. Thanks for promoting PDL.

Perl and Raku mainly

Back to complete solutions in multiple languages. Great work, keep it up.

Perl Weekly Challenge 309

Schwartzian transform? Yes, you can do it in one-liner, incredible. Thanks for sharing knowledge.

Mini Mini

Line by line narration is my favourite. It makes it so fun, getting the idea behind. Highly recommended.

Mind the gap

A complete solution that anyone can understand and follow. Bonus, you get DIY tool to try as well.

The Weekly Challenge #309

Loops is the key to solve the task this week. Cleverly used, well done.

All You Minima

Crystal is pick this week? Nice to see about new language being discussed in a blog post. Keep it up great work.

Weekly collections

NICEPERL's lists

Great CPAN modules released last week;
MetaCPAN weekly report.

Events

Boston.pm monthly meeting

Virtual event

Paris.pm monthly meeting

Paris, France

Boston.pm monthly meeting

Virtual event

German Perl/Raku Workshop Conference 2025

Munich, Germany

The Perl and Raku Conference 2025

Greenville, South Carolina, USA

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

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

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

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

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

Part 1: Min Gap

You are given an array of integers, @ints, increasing order. Write a script to return the element before which you find the smallest gap.

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

"ch-1.pl" 1


preamble 2
Min Gap subroutine. Contains all the important code for this problem. 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.

Let’s not even store anything. Instead go down the list and update two variables: one to store the current minimum gap, and the other to store the element before the current smallest gap found.

I use a small trick here. A way of saying The Maximum Integer is 0 + q/inf/.

Min Gap subroutine. Contains all the important code for this problem. 3 ⟩≡


sub min_gap{
my($min_gap, $element_min_gap) = (0 + q/inf/, 0 + q/inf/);
{
my $x = shift @_;
my $y = shift @_;
if($x && $y){
my $gap = $y - $x;
if($gap < $min_gap){
$min_gap = $gap;
$element_min_gap = $y;
}
}
unshift @_, $y;
redo if @_ > 1;
}
return $element_min_gap;
}

Fragment referenced in 1.

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

main 4 ⟩≡


MAIN:{
say min_gap 2, 8, 10, 11, 15;
say min_gap 1, 5, 6, 7, 14;
say min_gap 8, 20, 25, 28;
}

Fragment referenced in 1.

Sample Run
$ perl perl/ch-1.pl 
11 
6 
28
    

Part 2: Min Diff

You are given an array of integers, @ints. Write a script to find the minimum difference between any two elements.

"ch-2.pl" 5


preamble 2
Min Diff subroutine. All the code for solving the problem is here. 6
main 7

From Part 1 we know that if we sort the list we know we need to only check adjacent elements to find the minimum difference.

Min Diff subroutine. All the code for solving the problem is here. 6 ⟩≡


sub min_diff{
my $min_gap = 0 + q/inf/;
my @i = sort {$a <=> $b} @_;
{
my $x = shift @i;
my $y = shift @i;
if($x && $y){
my $gap = $y - $x;
$min_gap = $gap if $gap < $min_gap;
}
unshift @i, $y;
redo if @i > 1;
}
return $min_gap;
}

Fragment referenced in 5.

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

main 7 ⟩≡


MAIN:{
say min_diff 1, 5, 8, 9;
say min_diff 9, 4, 1, 7;
}

Fragment referenced in 5.

Sample Run
$ perl ch-2.pl 
1 
2
    

References

The Weekly Challenge 309
Generated Code

(dxxxvi) 8 great CPAN modules released last week

Niceperl

Published by Unknown on Sunday 23 February 2025 08:21

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

  1. CPANPLUS - Ameliorated interface to the CPAN
    • Version: 0.9916 on 2025-02-16, with 13 votes
    • Previous CPAN version: 0.9914 was 3 years, 2 months, 23 days before
    • Author: BINGOS
  2. DateTime - A date and time object for Perl
    • Version: 1.66 on 2025-02-19, with 222 votes
    • Previous CPAN version: 1.65 was 1 year, 3 months, 13 days before
    • Author: DROLSKY
  3. DBIx::DataModel - UML-based Object-Relational Mapping (ORM) framework
    • Version: 3.12 on 2025-02-20, with 13 votes
    • Previous CPAN version: 3.11 was 9 months, 22 days before
    • Author: DAMI
  4. Getopt::Long::Complete - A drop-in replacement for Getopt::Long, with shell tab completion
    • Version: 0.318 on 2025-02-21, with 14 votes
    • Previous CPAN version: 0.317 was 1 year, 9 months, 11 days before
    • Author: PERLANCAR
  5. LWP - The World-Wide Web library for Perl
    • Version: 6.78 on 2025-02-20, with 169 votes
    • Previous CPAN version: 6.77 was 11 months, 9 days before
    • Author: OALDERS
  6. Net::DNS - Perl Interface to the Domain Name System
    • Version: 1.50 on 2025-02-21, with 27 votes
    • Previous CPAN version: 1.49 was 1 month, 25 days before
    • Author: NLNETLABS
  7. Specio - Type constraints and coercions for Perl
    • Version: 0.50 on 2025-02-19, with 12 votes
    • Previous CPAN version: 0.49 was 1 month, 27 days before
    • Author: DROLSKY
  8. SPVM - The SPVM Language
    • Version: 0.990045 on 2025-02-21, with 35 votes
    • Previous CPAN version: 0.990043 was 14 days before
    • Author: KIMOTO

Creating an Automated Scripting Application with Perl

Perl on Medium

Published by Gathering Insight on Saturday 22 February 2025 03:15

From Development to Deployment

What's new on CPAN - January 2025

perl.com

Published on Thursday 20 February 2025 00:00

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

APIs & Apps

Config & Devops

Data

Development & Version Control

Science & Mathematics

Other