<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Planet Perl</title>
  <link rel="alternate" href="https://perl.theplanetarium.org/" type="text/html"/>
  <subtitle>There's More Than One Way To Aggregate It</subtitle>
  <author>
    <name>Dave Cross</name>
    <email>dave@theplanetarium.org</email>
  </author>
  <updated>2026-06-13T21:03:13Z</updated>
  <link rel="self" href="https://perl.theplanetarium.org/" type="application/atom+xml"/>
  <id>https://perl.theplanetarium.org/</id>
  <entry>
    <author>
      <name>/u/niceperl</name>
      <uri>https://www.reddit.com/user/niceperl</uri>
    </author>
    <category term="perl" label="r/perl"/>
    <content type="html">&amp;#32; submitted by &amp;#32; &lt;a href="https://www.reddit.com/user/niceperl"&gt; /u/niceperl &lt;/a&gt; &lt;br/&gt; &lt;span&gt;&lt;a href="https://niceperl.blogspot.com/2026/06/dciv-17-great-cpan-modules-released.html"&gt;[link]&lt;/a&gt;&lt;/span&gt; &amp;#32; &lt;span&gt;&lt;a href="https://www.reddit.com/r/perl/comments/1u4t8au/dciv_17_great_cpan_modules_released_last_week/"&gt;[comments]&lt;/a&gt;&lt;/span&gt;</content>
    <id>t3_1u4t8au</id>
    <link href="https://www.reddit.com/r/perl/comments/1u4t8au/dciv_17_great_cpan_modules_released_last_week/"/>
    <updated>2026-06-13T15:02:58+00:00</updated>
    <published>2026-06-13T15:02:58+00:00</published>
    <title>(dciv) 17 great CPAN modules released last week</title>
  </entry>
  <entry xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0">
    <id>tag:blogger.com,1999:blog-5910101498857524639.post-4045454341156764439</id>
    <published>2026-06-13T17:01:05.509+02:00</published>
    <updated>2026-06-13T17:01:05.509+02:00</updated>
    <category scheme="http://www.blogger.com/atom/ns#" term="cpan"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="perl"/>
    <title type="text">(dciv) 17 great CPAN modules released last week</title>
    <content type="html">Updates for &lt;i&gt;great CPAN modules&lt;/i&gt; released last week. A module is considered &lt;i&gt;great&lt;/i&gt; if its favorites count is greater or equal than 12.&lt;br/&gt;&lt;br/&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/PETDANCE/ack-v3.10.0' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;App::Ack&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - A grep-like program for searching source code
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;v3.10.0&lt;/strong&gt; on 2026-06-07, with 817 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: v3.9.0 was released 1 year, 11 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/PETDANCE'&gt;PETDANCE&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/SHLOMIF/Config-IniFiles-3.001000' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Config::IniFiles&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - A module for reading .ini-style configuration files.
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;3.001000&lt;/strong&gt; on 2026-06-11, with 15 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 3.000003 was released 6 years, 2 months, 17 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/SHLOMIF'&gt;SHLOMIF&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/RURBAN/Cpanel-JSON-XS-4.42' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Cpanel::JSON::XS&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - cPanel fork of JSON::XS, fast and correct serializing
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;4.42&lt;/strong&gt; on 2026-06-07, with 47 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 4.41 was released 10 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/RURBAN'&gt;RURBAN&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/BRIANDFOY/CPANSA-DB-20260607.001' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;CPANSA::DB&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - the CPAN Security Advisory data as a Perl data structure, mostly for CPAN::Audit
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;20260607.001&lt;/strong&gt; on 2026-06-07, with 25 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 20260531.001 was released 5 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/BRIANDFOY'&gt;BRIANDFOY&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/CUKEBOT/Cucumber-TagExpressions-10.0.0' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Cucumber::TagExpressions&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - A library for parsing and evaluating cucumber tag expressions (filters)
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;10.0.0&lt;/strong&gt; on 2026-06-11, with 18 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 9.1.0 was released 3 months, 21 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/CUKEBOT'&gt;CUKEBOT&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/SCHUBIGER/DateTime-Format-Natural-1.27' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;DateTime::Format::Natural&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Parse informal natural language date/time strings
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;1.27&lt;/strong&gt; on 2026-06-07, with 19 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 1.26_02 was released 5 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/SCHUBIGER'&gt;SCHUBIGER&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/RURBAN/GD-2.86' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;GD&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Perl interface to the libgd graphics library
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;2.86&lt;/strong&gt; on 2026-06-09, with 32 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 2.85 was released 7 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/RURBAN'&gt;RURBAN&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/HAARG/HTTP-Tiny-0.096' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;HTTP::Tiny&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - A small, simple, correct HTTP/1.1 client
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;0.096&lt;/strong&gt; on 2026-06-08, with 116 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 0.095 was released 4 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/HAARG'&gt;HAARG&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/JHTHORSEN/JSON-Validator-5.19' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;JSON::Validator&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Validate data against a JSON schema
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;5.19&lt;/strong&gt; on 2026-06-10, with 59 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 5.18 was released 1 day before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/JHTHORSEN'&gt;JHTHORSEN&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/MSIMERSON/Mail-DMARC-1.20260612' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Mail::DMARC&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Perl implementation of DMARC
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;1.20260612&lt;/strong&gt; on 2026-06-12, with 38 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 1.20260306 was released 3 months, 6 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/MSIMERSON'&gt;MSIMERSON&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/NLNETLABS/Net-DNS-1.55' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Net::DNS&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Perl Interface to the Domain Name System
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;1.55&lt;/strong&gt; on 2026-06-11, with 29 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 1.54_02 was released 3 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/NLNETLABS'&gt;NLNETLABS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/DCANTRELL/Number-Phone-4.0011' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Number::Phone&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - base class for Number::Phone::* modules
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;4.0011&lt;/strong&gt; on 2026-06-10, with 24 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 4.0010 was released 3 months, 4 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/DCANTRELL'&gt;DCANTRELL&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/CRUX/Protocol-HTTP2-1.13' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Protocol::HTTP2&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - HTTP/2 protocol implementation (RFC 7540)
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;1.13&lt;/strong&gt; on 2026-06-07, with 27 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 1.12 was released 3 months, 20 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/CRUX'&gt;CRUX&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/KIMOTO/SPVM-0.990189' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;SPVM&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - The SPVM Language
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;0.990189&lt;/strong&gt; on 2026-06-12, with 36 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 0.990188 was released 1 day before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/KIMOTO'&gt;KIMOTO&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/EXODIST/Test-Simple-1.302220' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Test::Simple&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Basic utilities for writing tests.
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;1.302220&lt;/strong&gt; on 2026-06-09, with 200 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 1.302219 was released 6 months before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/EXODIST'&gt;EXODIST&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/OALDERS/WWW-Mechanize-2.21' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;WWW::Mechanize&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Handy web browsing in a Perl object
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;2.21&lt;/strong&gt; on 2026-06-13, with 104 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 2.20 was released 7 months, 21 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/OALDERS'&gt;OALDERS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/CORION/WWW-Mechanize-Chrome-0.79' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;WWW::Mechanize::Chrome&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - automate the Chrome browser
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;0.79&lt;/strong&gt; on 2026-06-08, with 22 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 0.78 was released the same day&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/CORION'&gt;CORION&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content>
    <link rel="replies" type="application/atom+xml" href="https://niceperl.blogspot.com/feeds/4045454341156764439/comments/default" title="Enviar comentarios"/>
    <link rel="replies" type="text/html" href="https://niceperl.blogspot.com/2026/06/dciv-17-great-cpan-modules-released.html#comment-form" title="0 comentarios"/>
    <link rel="edit" type="application/atom+xml" href="https://www.blogger.com/feeds/5910101498857524639/posts/default/4045454341156764439"/>
    <link rel="self" type="application/atom+xml" href="https://www.blogger.com/feeds/5910101498857524639/posts/default/4045454341156764439"/>
    <link rel="alternate" type="text/html" href="https://niceperl.blogspot.com/2026/06/dciv-17-great-cpan-modules-released.html" title="(dciv) 17 great CPAN modules released last week"/>
    <author>
      <name>prz</name>
      <uri>http://www.blogger.com/profile/17989445983340548566</uri>
      <email>noreply@blogger.com</email>
      <gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="https://img1.blogblog.com/img/b16-rounded.gif"/>
    </author>
    <thr:total>0</thr:total>
  </entry>
  <entry>
    <author>
      <name>/u/christian_hansen</name>
      <uri>https://www.reddit.com/user/christian_hansen</uri>
    </author>
    <category term="perl" label="r/perl"/>
    <content type="html">&lt;!-- SC_OFF --&gt;&lt;div class="md"&gt;&lt;p&gt;&lt;a href="https://blogs.perl.org/users/chansen/2026/06/timestr---time-zones-and-leap-seconds.html"&gt;This blog post&lt;/a&gt; is a follow up on my previous post, &lt;a href="https://blogs.perl.org/users/chansen/2026/05/introducing-timestr.html"&gt;&lt;em&gt;Introducing Time::Str&lt;/em&gt;&lt;/a&gt;, covered parsing and formatting. This one covers two additions, time zones and leap seconds, and ends with a note on the new C parsers.&lt;/p&gt; &lt;p&gt;If you have any questions or feedback, feel free to leave them here or on the blog, and I&amp;#39;ll be happy to respond.&lt;/p&gt; &lt;/div&gt;&lt;!-- SC_ON --&gt; &amp;#32; submitted by &amp;#32; &lt;a href="https://www.reddit.com/user/christian_hansen"&gt; /u/christian_hansen &lt;/a&gt; &lt;br/&gt; &lt;span&gt;&lt;a href="https://www.reddit.com/r/perl/comments/1u4qkgr/timestr_time_zones_and_leap_seconds/"&gt;[link]&lt;/a&gt;&lt;/span&gt; &amp;#32; &lt;span&gt;&lt;a href="https://www.reddit.com/r/perl/comments/1u4qkgr/timestr_time_zones_and_leap_seconds/"&gt;[comments]&lt;/a&gt;&lt;/span&gt;</content>
    <id>t3_1u4qkgr</id>
    <link href="https://www.reddit.com/r/perl/comments/1u4qkgr/timestr_time_zones_and_leap_seconds/"/>
    <updated>2026-06-13T13:08:56+00:00</updated>
    <published>2026-06-13T13:08:56+00:00</published>
    <title>Time::Str - Time Zones and Leap Seconds</title>
  </entry>
  <entry>
  <title>PEVANS Core Perl 5: Grant Report for May 2026</title>
  <link rel="alternate" type="text/html" href="https://news.perlfoundation.org/post/pevans_core_dev_may_2026"/>
  <id>tag:news.perlfoundation.org,2026-06-13:/post/pevans_core_dev_may_2026</id>
  <published>2026-06-13T10:36:52</published>
  <updated>2026-06-13T10:36:52</updated>
  <summary>
  <![CDATA[
     Paul writes: May is always a quiet month for me because I my big stage event to look after, but I got a few things done: 4 Experimentation in Object::Pad's version of how to fix the "late added fields" bug  https://github.com/Perl/perl5/issues/24393 1 Fix a couple of integer overflow bugs relating to security reports 3 Begin work on the `av_splice` API  https://github.com/Perl/perl5/pull/24451 Total: 8 hours June's focus is getting 
   ]]>
  </summary>
  <author>
    <name>alh</name>
  </author>
  <category term="Grants" scheme="http://www.sixapart.com/ns/types#category"/>
  <category term="Perl 5 Development" scheme="http://www.sixapart.com/ns/types#category"/>  <content type="html" xml:lang="en-us" xml:base="http://news.perlfoundation.org/">
   <![CDATA[
     
       <img src="_ra-rel-mnt_/simplecas/fetch_content/7f97282811f6a9f862d7e659c79e5462cc195d94/grant-funding.png" style="max-width:100%;max-height:100%;padding:20px;" /><br>
     
     <p>Paul writes:</p>

<p>May is always a quiet month for me because I my big stage event to look
after, but I got a few things done:</p>

<ul>
<li>4 = Experimentation in Object::Pad's version of how to fix the "late added fields" bug
<ul>
<li>https://github.com/Perl/perl5/issues/24393</li>
</ul></li>
<li>1 = Fix a couple of integer overflow bugs relating to security reports</li>
<li>3 = Begin work on the <code>av_splice</code> API
<ul>
<li>https://github.com/Perl/perl5/pull/24451</li>
</ul></li>
</ul>

<p>Total: 8 hours</p>

<p>June's focus is getting 5.44 out the door, and lining up the various
features in design or development to start the next cycle.</p>

    ]]>
  </content>
</entry>
  <entry xmlns:re="http://purl.org/atompub/rank/1.0">
        <id>https://stackoverflow.com/q/79949253</id>
        <re:rank scheme="https://stackoverflow.com">2</re:rank>
        <title type="text">Numerically sorting in Perl</title>
            <category scheme="https://stackoverflow.com/tags" term="perl"/>
        <author>
            <name>mscha</name>
            <uri>https://stackoverflow.com/users/299242</uri>
        </author>
        <link rel="alternate" href="https://stackoverflow.com/questions/79949253/numerically-sorting-in-perl"/>
        <published>2026-05-31T12:46:05Z</published>
        <updated>2026-06-11T16:58:26Z</updated>
        <summary type="html">
            &lt;p&gt;In Perl, is there an &lt;code&gt;nsort&lt;/code&gt; function (to sort numerically) available in a mainstream CPAN module?
There is &lt;code&gt;nsort_by&lt;/code&gt; in both &lt;code&gt;List::MoreUtils&lt;/code&gt; and &lt;code&gt;List::UtilsBy&lt;/code&gt;, but no &lt;code&gt;nsort&lt;/code&gt;.  &lt;code&gt;Sort::Naturally&lt;/code&gt; has &lt;code&gt;nsort&lt;/code&gt;, but I don't want a “natural” sort, but a plain numeric one.&lt;/p&gt;
&lt;p&gt;Sure, I can do &lt;code&gt;sort { $a &amp;lt;=&amp;gt; $b }&lt;/code&gt; but I'd like to do it in a cleaner way.&lt;/p&gt;

        </summary>
    </entry>
  <entry>
    <author>
      <name>/u/Background-Gur-8129</name>
      <uri>https://www.reddit.com/user/Background-Gur-8129</uri>
    </author>
    <category term="perl" label="r/perl"/>
    <content type="html">&lt;!-- SC_OFF --&gt;&lt;div class="md"&gt;&lt;p&gt;I&amp;#39;m actually somewhat enthused over the new Core OOP additions over the last few releases. I didn&amp;#39;t think the create an object (usually a hash) and bless it was all that hard, but felt a little ... clunky compared to other languages. The newer syntax and encapsulation behavior is a welcome addition to the language. To make sure I really understood it, I tried a few examples. Most was pretty easy, until I got inheritance and the train went off the rails in that it stopped being DWIM suddenly. IMO, the docs seem a little lacking but I was able to start piecing the knowledge together with lots of &amp;#39;net searching and a small example -- mostly.&lt;/p&gt; &lt;pre&gt;&lt;code&gt;use v5.42; use feature &amp;#39;class&amp;#39;; no warnings &amp;#39;experimental::class&amp;#39;; class Animal { # Define the parent class field $name :param :reader :writer; method speak() { say &amp;quot;$name makes a sound.&amp;quot;; } my method secret() { say __CLASS__ . &amp;quot; secret is 42&amp;quot;; } # only callable inside the class method cheat() { $self-&amp;gt;&amp;amp;secret; } } class Dog :isa(Animal) { # Define the child class field $breed :param; method speak { # Override or extend functionality print &amp;quot;override: &amp;quot;; $self-&amp;gt;SUPER::speak(); #say &amp;quot;$name (the $breed) says: Woof!&amp;quot;; ## &amp;lt;&amp;lt;-- EXPECTED # Global symbol &amp;quot;$name&amp;quot; requires explicit package name #say &amp;quot;$SUPER::name (the $breed) says: Woof!&amp;quot;; ## &amp;lt;&amp;lt;-- UNDERSTAND THIS MIGHT BE NEEDED # Use of uninitialized value $SUPER::name #say $self-&amp;gt;SUPER::name, &amp;quot; (the $breed) says: Woof!&amp;quot;; #method call, so same as below say $self-&amp;gt;name(), &amp;quot; (the $breed) says: Bark!&amp;quot;; # works! WTH?! } method rename($newname) { say &amp;quot;renaming from &amp;quot; . $self-&amp;gt;name() . &amp;quot; to $newname&amp;quot;; #$name = $newname; ## &amp;lt;&amp;lt;-- EXPECTED # Global symbol &amp;quot;$name&amp;quot; requires explicit package name #$SUPER::name = $newname; ## &amp;lt;&amp;lt;-- UNDERSTAND THIS MIGHT BE NEEDED #no error but also doesn&amp;#39;t work # go add &amp;quot;:writer&amp;quot; to parent class $self-&amp;gt;set_name($newname); # works! WTH?! } } # Main my $buddy = Dog-&amp;gt;new( name =&amp;gt; &amp;quot;Buddy&amp;quot;, breed =&amp;gt; &amp;quot;Golden Retriever&amp;quot; ); $buddy-&amp;gt;speak(); $buddy-&amp;gt;rename(&amp;quot;buddyboy&amp;quot;); $buddy-&amp;gt;speak(); my $anna = Animal-&amp;gt;new( name =&amp;gt; &amp;quot;Anna&amp;quot; ); $anna-&amp;gt;speak(); #$anna-&amp;gt;&amp;amp;secret(); # ??? Undefined subroutine &amp;amp;main::secret called; cannot do this! $anna-&amp;gt;cheat(); &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;I think that exercises most everything. After getting stuck, I went back to reread perlclass several times and finally spotted &amp;quot;lexical&amp;quot; hiding in a couple of paragraphs...which was really important. [Hint: I think that needs to be highlighted more, as well as adding some more example in the doc.]&lt;/p&gt; &lt;p&gt;The heart of the my problem is that there seems to be no &amp;quot;protected&amp;quot; scoping for variable (fields). Why not? [See the &amp;quot;EXPECTED&amp;quot; in the example.]&lt;/p&gt; &lt;p&gt;This is more obvious with a small chart:&lt;/p&gt; &lt;pre&gt;&lt;code&gt;What we have in 5.42.2: class Base { method m1 { } # scope: public [&amp;amp; protected] my method m2 { } # scope: private # do not want # scope: public # not available # scope: protected field f1; # scope: private }; Why isn&amp;#39;t it: class Base { method m1 { } # scope: public [&amp;amp; protected] my method m2 { } # scope: private # do not want # scope: public field f1; # scope: protected my field f1; # scope: private }; &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;That would allow a derived class to use the base class&amp;#39;s vars easily and with less typing, no calling a function/method to get or set. Or did I miss something in my reading and there is a way to have &amp;quot;protected vars&amp;quot;? Or am I being impatient and it&amp;#39;s coming in 5.44 or 5.46 and I just need to hold off on this until then?&lt;/p&gt; &lt;/div&gt;&lt;!-- SC_ON --&gt; &amp;#32; submitted by &amp;#32; &lt;a href="https://www.reddit.com/user/Background-Gur-8129"&gt; /u/Background-Gur-8129 &lt;/a&gt; &lt;br/&gt; &lt;span&gt;&lt;a href="https://www.reddit.com/r/perl/comments/1u2gx9g/confused_about_a_few_parts_of_the_new_core_oop/"&gt;[link]&lt;/a&gt;&lt;/span&gt; &amp;#32; &lt;span&gt;&lt;a href="https://www.reddit.com/r/perl/comments/1u2gx9g/confused_about_a_few_parts_of_the_new_core_oop/"&gt;[comments]&lt;/a&gt;&lt;/span&gt;</content>
    <id>t3_1u2gx9g</id>
    <link href="https://www.reddit.com/r/perl/comments/1u2gx9g/confused_about_a_few_parts_of_the_new_core_oop/"/>
    <updated>2026-06-10T22:23:33+00:00</updated>
    <published>2026-06-10T22:23:33+00:00</published>
    <title>Confused about a few parts of the new Core OOP</title>
  </entry>
  <entry>
    <title>Time::Str - Time Zones and Leap Seconds</title>
    <link rel="alternate" href="https://blogs.perl.org/users/chansen/2026/06/timestr---time-zones-and-leap-seconds.html"/>
    <id>tag:blogs.perl.org,2026:/users/chansen//165.12067</id>
    <published>2026-06-10T13:10:21Z</published>
    <updated>2026-06-10T13:38:12Z</updated>
    <author>
        <name>Christian Hansen</name>
        
    </author>
    <content type="html" xml:lang="en" xml:base="https://blogs.perl.org/users/chansen/">
        

        <![CDATA[<p><a href="https://metacpan.org/pod/Time::Str">Time::Str</a> parses and formats
date/time strings across 20+ standard formats, with an optional C/XS
backend and nanosecond precision. The previous post, 
<em><a href="https://blogs.perl.org/users/chansen/2026/05/introducing-timestr.html">Introducing Time::Str</a></em>, 
covered parsing and formatting. This one covers two additions, time zones 
and leap seconds, and ends with a note on the new C parsers.</p>

<h2>Time Zones</h2>

<p>Time::Str has understood the offset in a timestamp (<code>+01:00</code>,
<code>Z</code>), but it could not turn a zone name, or a local time with no offset,
into a precise instant. Two new modules add that:</p>

<ul>
<li><strong><a href="https://metacpan.org/pod/Time::Str::TimeZone">Time::Str::TimeZone</a></strong>
resolves names to objects and caches them.</li>
<li><strong><a href="https://metacpan.org/pod/Time::TZif">Time::TZif</a></strong> and
<strong><a href="https://metacpan.org/pod/Time::TZif::POSIX">Time::TZif::POSIX</a></strong>
compute the UTC offset of a zone at a given instant.</li>
</ul>

<h3>Example</h3>

<pre><code>use Time::Str::TimeZone qw(timezone);
use Time::Str           qw(str2time time2str);

$str  = 'Dec. 24, 2012 12:30 p.m.';
$tz   = timezone('America/New_York');
$time = str2time($str, format =&gt; 'DateTime', timezone =&gt; $tz);

say time2str($time, timezone =&gt; $tz);
# 2012-12-24T12:30:00-05:00
</code></pre>

<p>The input string has no offset. The <code>timezone</code> object resolves the local
wall-clock time to UTC (New York in December is EST, -05:00), and
<code>time2str</code> renders the result back in the same zone. The result is
DST-aware, so a July date prints <code>-04:00</code>.</p>

<h3>Resolving abbreviations</h3>

<p>The first post showed that Time::Str captures abbreviations such as
<code>IST</code> in <code>tz_abbrev</code> without deciding what they mean, since one
abbreviation can name several zones. A <code>timezone_map</code> supplies the
meaning for your data:</p>

<pre><code>$map = {
  EST =&gt; timezone('America/New_York'),
  EDT =&gt; timezone('America/New_York'),
};

$str  = 'Dec. 24, 2012 12:30 p.m. EST';
$time = str2time($str, format =&gt; 'DateTime', timezone_map =&gt; $map);
</code></pre>

<p>The abbreviation selects an object, and the object determines the 
offset for that instant.</p>

<h3>Time::TZif and Time::TZif::POSIX</h3>

<p>Time::TZif reads compiled TZif files (RFC 8536), the binary zoneinfo
the operating system ships. Time::TZif::POSIX evaluates a POSIX <code>TZ</code>
rule string (IEEE Std 1003.1), for zones expressed as rules such as
<code>EST5EDT,M3.2.0,M11.1.0</code>:</p>

<pre><code>use Time::TZif;

$tz = Time::TZif-&gt;new(
  path =&gt; "$dir/America/New_York",
  name =&gt; 'America/New_York',
);
$off = $tz-&gt;offset_for_utc($epoch);  # seconds east


use Time::TZif::POSIX;

$tz = Time::TZif::POSIX-&gt;new(
  tz_string =&gt; 'EST5EDT,M3.2.0,M11.1.0',
);
</code></pre>

<p>Both provide the same two methods, <code>offset_for_utc</code> and
<code>offset_for_local</code>, which <code>str2time</code> and <code>time2str</code> use. Either object
can be passed as <code>timezone =&gt;</code>.</p>

<h3>Implementation notes</h3>

<ul>
<li><strong><code>TZ</code> handling follows POSIX.</strong> It honors the <code>TZ</code> environment
variable: a database name, a POSIX rule, or the system default via
<code>/etc/localtime</code>.</li>
<li><strong>It uses the system IANA database.</strong> OS vendors keep the tzdb
current, so on a current POSIX system there is nothing to bundle or
upgrade separately.</li>
<li><strong>Maintenance.</strong> DateTime::TimeZone ships its own copy of the tzdb and
is re-released when the rules change; Time::TZif reads the system copy
instead.</li>
<li><strong>Memory.</strong> For <code>America/New_York</code>, Time::TZif uses 17,765 bytes
against 87,174 for DateTime::TimeZone.</li>
<li><strong>Offset lookup speed</strong> is shown below.</li>
<li><strong>Runtime reload.</strong> Clearing the cache (<code>Time::Str::TimeZone-&gt;reset</code>)
lets a long-running process pick up an updated database or a changed
<code>TZ</code> without restarting.</li>
</ul>

<h3>Choosing how local times resolve</h3>

<p>A spring-forward gap and a fall-back overlap have no single answer: one
wall-clock time does not exist, another occurs twice. Time::TZif
resolves these by policy.</p>

<p>Defaults are set on the constructor and apply to every lookup the object
makes:</p>

<pre><code>$tz = Time::TZif-&gt;new(
  path           =&gt; $path,
  name           =&gt; 'America/New_York',
  gap_policy     =&gt; 'later',    # spring-forward
  overlap_policy =&gt; 'earlier',  # fall-back
);
</code></pre>

<p>Either default can be overridden for a single call, by passing the
policy to <code>offset_for_local</code>:</p>

<pre><code># resolve this overlap as daylight time, this once
$off = $tz-&gt;offset_for_local($time, overlap_policy =&gt; 'dst');
</code></pre>

<p>The five values are <code>reject</code> (the constructor default, which croaks on
an impossible or ambiguous local time), <code>earlier</code> and <code>later</code> (pick by
clock order), and <code>std</code> and <code>dst</code> (pick the standard-time or
daylight-time side). A local time then resolves the way your libc or
DateTime.pm would, per object or per call.</p>

<h3>Benchmarks</h3>

<p>Memory held for <code>America/New_York</code>:</p>

<pre style="overflow-x:auto;font-size:.85em;line-height:1.25">
                        bytes
Time::TZif              17765
DateTime::TimeZone      87174
</pre>

<p>UTC offset lookup:</p>

<pre style="overflow-x:auto;font-size:.85em;line-height:1.25">
                      Rate DateTime::Lite   DateTime  Time::TZif
DateTime::Lite     64306/s             --       -91%        -99%
DateTime          709978/s          1004%         --        -86%
Time::TZif       5093119/s          7820%       617%          --
</pre>

<p>Time::TZif is roughly 7x DateTime on this lookup.</p>

<h3>Limitation: Windows</h3>

<p>The current catalog targets POSIX systems, where the zoneinfo files and
<code>TZ</code> semantics are standard. A Windows fallback is planned on top of
<a href="https://metacpan.org/pod/Time::OlsonTZ::Data">Time::OlsonTZ::Data</a>,
originally by the late Zefram and now maintained by Dan Book, which
packages the Olson database for platforms that do not ship it.</p>

<h2>Leap Seconds</h2>

<p>When I asked for feedback on IRC, Karen Etheridge ran her JSON Schema
tests against <code>str2time</code>. It accepted any timestamp whose seconds field
was <code>60</code>.</p>

<p>A leap second can appear only as <code>23:59:60 UTC</code>, and only on June 30 or
December 31. <code>12:30:60</code> is not a leap second.</p>

<p><code>str2time</code> now checks this without a table:</p>

<pre><code>str2time('2016-12-31T23:59:60Z');
# ok: folded onto 23:59:59

str2time('2016-12-31T12:30:60Z');
# croaks: "Unable to convert: a leap second must occur at 23:59:60 UTC"

str2time('2016-06-15T23:59:60Z');
# croaks: "Unable to convert: no leap second on this UTC date"
</code></pre>

<p>POSIX time cannot represent a 61st second, so <code>str2time</code> folds
<code>23:59:60</code> onto the preceding <code>23:59:59</code>, then confirms the UTC instant
is the last second of June 30 or December 31 (since 1972). The check
runs after the offset is applied, so it also holds for non-UTC offsets:</p>

<pre><code>str2time('2017-01-01T05:29:60+05:30');  # ok
# the same instant as 2016-12-31 23:59:60 UTC
</code></pre>

<p>The check is table-free: it accepts every June 30 and December 31 slot,
whether or not a leap second was inserted that day.</p>

<h3>Time::LeapSecond</h3>

<p>That gap led to
<a href="https://metacpan.org/pod/Time::LeapSecond">Time::LeapSecond</a>, which
knows the leap seconds that were actually scheduled. It reads the system
data file (TZDB <code>leap-seconds</code> or IERS <code>leap-seconds.list</code>), falls back
to a built-in table, and exposes the instants, the TAI-UTC offset, and
the file's expiration <code>$EXPIRES</code> (the POSIX epoch the data is complete
until).</p>

<p>The plan is to use it in <code>str2time</code>: while <code>time()</code> is before
<code>$EXPIRES</code> the table is authoritative, so an unlisted <code>:60</code> is rejected;
once past it the file may be stale, so <code>str2time</code> falls back to the
table-free check and accepts any valid slot. Better to accept a wrong
leap second than reject a real one.</p>

<h2>Native C parsers</h2>

<p>An update on the first post's "what's next": several parsers are now
generated C, built with <a href="http://www.colm.net/open-source/ragel/">Ragel</a>,
which removes the regex step from the parse path. Parsing
<code>2012-12-24T12:30:45.123456+01:00</code>:</p>

<pre style="overflow-x:auto;font-size:.85em;line-height:1.25">
                     Rate DT8601 DT3339 D::Parse T::Moment T::Str
DT::F::ISO8601    23442/s     --   -50%     -78%     -100%  -100%
DT::F::RFC3339    46804/s   100%     --     -56%      -99%  -100%
D::Parse         105263/s   349%   125%       --      -99%   -99%
T::Moment       7030938/s 29893% 14922%    6579%        --   -36%
T::Str         11020543/s 46912% 23446%   10369%       57%     --
</pre>

<p>On this input Time::Str is about 57% faster than my other module
<a href="https://metacpan.org/pod/Time::Moment">Time::Moment</a>.</p>

<hr />

<p>Time::Str, Time::TZif, Time::TZif::POSIX, Time::Str::TimeZone and
Time::LeapSecond are on
<a href="https://metacpan.org/pod/Time::Str">CPAN</a> and
<a href="https://github.com/chansen/p5-time-str">GitHub</a>.</p>

<pre><code>cpanm Time::Str
</code></pre>
]]>
    </content>
</entry>
  <entry>
    <author>
      <name>/u/Henrybk</name>
      <uri>https://www.reddit.com/user/Henrybk</uri>
    </author>
    <category term="perl" label="r/perl"/>
    <content type="html">&lt;!-- SC_OFF --&gt;&lt;div class="md"&gt;&lt;p&gt;Hello there.&lt;br/&gt; I have been using perl for a good 15 years now and stumbled upon something today I could not find a good solution and would like some input.&lt;/p&gt; &lt;p&gt;This is for a hobby, not work related.&lt;/p&gt; &lt;p&gt;I like running an offline game server and a few AI players (bots) in it and develop them over time, this project has bern going for about 5-6 years, the game being ragnarok and the bot being openkore, a standalone perl script that logs into the game and plays it.&lt;/p&gt; &lt;p&gt;I have recently delved into making the bots share decision making, for that I used socket based communication between them using IO:Socket, then I made a central standalone script that receives updates from the bots via sockets and decides the next state of the group, then it sends back this decision to each individual bot.&lt;/p&gt; &lt;p&gt;This runs in a loop, with each bot sending updates every second and the decisions being made every 10 seconds.&lt;/p&gt; &lt;p&gt;That worked very well until I increased the number of agents above 25-30, then the number of socket reads started being too much for my script, since each bot reads the update from every other bot the number of reads per second scales to N squared.&lt;/p&gt; &lt;p&gt;I could just run many separate groups of 20 bots each but I would like to approach it in a way to avoid that.&lt;/p&gt; &lt;p&gt;I would like input in a good to go about this.&lt;/p&gt; &lt;p&gt;I tried looking into IPC::Shareable to maybe create a shared %state variable in memory to which the controller could write and each bot read, and likewise a %info one where bots could update their info and the controller read them all but it only works in unix and use this system in windows.&lt;/p&gt; &lt;p&gt;The bot project is this: &lt;a href="https://github.com/OpenKore/openkore"&gt;https://github.com/OpenKore/openkore&lt;/a&gt;&lt;/p&gt; &lt;p&gt;But I run a very customized fork not the one from the repository.&lt;/p&gt; &lt;p&gt;I have a few videos in youtube about the development of said bot in: &lt;a href="https://youtube.com/@henrybk5644?si=O68e4xIzHLURepXj"&gt;https://youtube.com/@henrybk5644?si=O68e4xIzHLURepXj&lt;/a&gt;&lt;/p&gt; &lt;p&gt;So what do you guys think would be a good idea to increase the scalability of this system or reduce socket communication overhead?&lt;/p&gt; &lt;p&gt;I thought maybe C++ memory sharing over perlXS but I never looked into that.&lt;/p&gt; &lt;p&gt;Thanks.&lt;/p&gt; &lt;/div&gt;&lt;!-- SC_ON --&gt; &amp;#32; submitted by &amp;#32; &lt;a href="https://www.reddit.com/user/Henrybk"&gt; /u/Henrybk &lt;/a&gt; &lt;br/&gt; &lt;span&gt;&lt;a href="https://www.reddit.com/r/perl/comments/1u1fq2v/memory_sharing_between_scripts/"&gt;[link]&lt;/a&gt;&lt;/span&gt; &amp;#32; &lt;span&gt;&lt;a href="https://www.reddit.com/r/perl/comments/1u1fq2v/memory_sharing_between_scripts/"&gt;[comments]&lt;/a&gt;&lt;/span&gt;</content>
    <id>t3_1u1fq2v</id>
    <link href="https://www.reddit.com/r/perl/comments/1u1fq2v/memory_sharing_between_scripts/"/>
    <updated>2026-06-09T19:48:39+00:00</updated>
    <published>2026-06-09T19:48:39+00:00</published>
    <title>Memory sharing between scripts</title>
  </entry>
  <entry>
    <title>This week in PSC (228) | 2026-06-08</title>
    <link rel="alternate" href="https://blogs.perl.org/users/psc/2026/06/this-week-in-psc-228-2026-06-08.html"/>
    <id>tag:blogs.perl.org,2026:/users/psc//4112.12066</id>
    <published>2026-06-09T06:41:41Z</published>
    <updated>2026-06-09T06:52:42Z</updated>
    <author>
        <name>Perl Steering Council</name>
        
    </author>
    <content type="html" xml:lang="en" xml:base="https://blogs.perl.org/users/psc/">
        <![CDATA[<p>We were all present.</p>

<ul>
<li>5.43.11 has so far turned up a few problems, thankfully small. As a result there are new versions of Archive::Tar and HTTP::Tiny to sync, which we intend to merge.</li>
<li>We decided how to proceed with our schedule: we will wait another week for any other findings in 5.43.11, and if nothing else shows up then we intend to start working on 5.44.0-RC0 at that point.</li>
<li>We discussed briefly the trajectory of <a href="https://perl.topicbox.com/groups/perl-core/Tded84d01cb16966e">the core team’s LLM policy conversation</a>. For now we continue keeping an eye on the thread.</li>
<li>We noted PRs to add <a href="https://github.com/Perl/PPCs/pull/89">two</a> <a href="https://github.com/Perl/PPCs/pull/90">new</a> documents to the PPCs repository but didn’t have time to discuss them in this meeting. We intend to do so in the next one.</li>
</ul>

<p>[<a href="https://www.nntp.perl.org/group/perl.perl5.porters/;msgid=aidxkeywlOt4qg04@klangraum.plasmasturm.org">P5P posting of this summary</a>]</p>
]]>
        

    </content>
</entry>
  <entry>
    <author>
      <name>/u/george-frazee</name>
      <uri>https://www.reddit.com/user/george-frazee</uri>
    </author>
    <category term="perl" label="r/perl"/>
    <content type="html">&lt;!-- SC_OFF --&gt;&lt;div class="md"&gt;&lt;p&gt;&lt;strong&gt;edit: SOLVED. Had to change $xCt++ to ++$xCt&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;System Info:&lt;/strong&gt;&lt;/p&gt; &lt;pre&gt;&lt;code&gt;% perl -version This is perl 5, version 34, subversion 1 (v5.34.1) built for darwin-thread-multi-2level (with 2 registered patches, see perl -V for more detail) % system_profiler SPSoftwareDataType | grep &amp;#39;System Version&amp;#39; System Version: macOS 15.5 (24F74) &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;I have a list of files that I&amp;#39;m feeding into perl from the command line and using regex to extract info (a date), create a folder, and then move the file into that folder. Anything that doesn&amp;#39;t get matched in the regex gets dropped into a separate folder &amp;quot;__OTHER&amp;quot; to be looked at.&lt;/p&gt; &lt;p&gt;The issue is that the FIRST instance of a file that should be placed into the __OTHER directory ALSO creates a directory (empty) matching the filename. The rest behave as expected.&lt;/p&gt; &lt;p&gt;Script:&lt;/p&gt; &lt;pre&gt;&lt;code&gt;#! /usr/bin/perl -wnl use File::Copy; BEGIN { $file=&amp;quot;&amp;quot;; $extraDir=&amp;quot;__OTHER&amp;quot;; $xCt=0; $moved=0; mkdir $extraDir; } $file=&amp;quot;$_&amp;quot;; $moved=0; (s/^Test_(\d{4}_\d{2}_\d{2}).+/$1 - / or move(&amp;quot;$file&amp;quot;,&amp;quot;$extraDir/$file&amp;quot;) and $xCt++ and $moved=1); $moved == 0 and mkdir; move(&amp;quot;$file&amp;quot;,&amp;quot;$_/$file&amp;quot;); END{ print &amp;quot;$. files processed; $xCt in $extraDir&amp;quot;; } &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Sample File Names I&amp;#39;m using:&lt;/p&gt; &lt;pre&gt;&lt;code&gt;1f7edcd5-b0cb-4fb0-892f-38a324454eb9.jpg 2b3aa5b9-d80c-4f43-a370-82f4e14dac64.jpg 3f69d564-7c93-4105-ad2f-66678523693c.jpg Test_2025_01_01_02_59_59_0a876bef-c475-48bb-968c-39373dcd36b0.jpg Test_2025_01_01_02_59_59_2a336499-b914-4105-9eca-a9c92c4fe4b6.jpg Test_2025_01_01_02_59_59_5cfd88c1-67b8-4aa4-a785-d528de3f254b.jpg Test_2025_01_02_02_59_59_2ec971d9-915a-4966-8306-e611fa0c455a.jpg Test_2025_01_02_02_59_59_4a9951ab-c7ac-4974-a1e2-735ca33e7e61.jpg Test_2025_01_02_02_59_59_4bb85bcb-f760-4680-a2d1-8940cba9d5f3.jpg Test_2025_01_02_02_59_59_5c1dc5fa-a5fc-49f2-a434-20931649178a.jpg Test_2025_01_21_02_59_59_cc8b1938-b9f7-4ccc-bd59-8d452f78eb4c.jpg Test_2025_01_21_02_59_59_d5a5b732-d38e-468c-9f22-08ef90a7b5a5.jpg Test_2025_01_21_02_59_59_d87482dd-ac2f-4621-9029-e6612d7331bd.jpg Test_2025_01_21_02_59_59_d972e346-b707-46a5-9a98-ef0195d8d246.jpg Test_2025_01_21_02_59_59_dd5dac68-57ea-4389-a256-fd88c67ede9e.jpg Test_2025_01_21_02_59_59_e506e2f7-aa98-4b4e-9eae-9cac9126c790.jpg Test_2025_01_21_02_59_59_f5b80b75-43c1-4638-aad6-79a1ca686560.jpg &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;And the result:&lt;/p&gt; &lt;pre&gt;&lt;code&gt;% find . -exec file -- {} + .: directory ./1f7edcd5-b0cb-4fb0-892f-38a324454eb9.jpg: directory ./2025_01_02 - : directory ./2025_01_02 - /Test_2025_01_02_02_59_59_2ec971d9-915a-4966-8306-e611fa0c455a.jpg: empty ./2025_01_02 - /Test_2025_01_02_02_59_59_4bb85bcb-f760-4680-a2d1-8940cba9d5f3.jpg: empty ./2025_01_02 - /Test_2025_01_02_02_59_59_5c1dc5fa-a5fc-49f2-a434-20931649178a.jpg: empty ./2025_01_02 - /Test_2025_01_02_02_59_59_4a9951ab-c7ac-4974-a1e2-735ca33e7e61.jpg: empty ./2025_01_01 - : directory ./2025_01_01 - /Test_2025_01_01_02_59_59_2a336499-b914-4105-9eca-a9c92c4fe4b6.jpg: empty ./2025_01_01 - /Test_2025_01_01_02_59_59_5cfd88c1-67b8-4aa4-a785-d528de3f254b.jpg: empty ./2025_01_01 - /Test_2025_01_01_02_59_59_0a876bef-c475-48bb-968c-39373dcd36b0.jpg: empty ./2025_01_21 - : directory ./2025_01_21 - /Test_2025_01_21_02_59_59_dd5dac68-57ea-4389-a256-fd88c67ede9e.jpg: empty ./2025_01_21 - /Test_2025_01_21_02_59_59_d87482dd-ac2f-4621-9029-e6612d7331bd.jpg: empty ./2025_01_21 - /Test_2025_01_21_02_59_59_f5b80b75-43c1-4638-aad6-79a1ca686560.jpg: empty ./2025_01_21 - /Test_2025_01_21_02_59_59_e506e2f7-aa98-4b4e-9eae-9cac9126c790.jpg: empty ./2025_01_21 - /Test_2025_01_21_02_59_59_cc8b1938-b9f7-4ccc-bd59-8d452f78eb4c.jpg: empty ./2025_01_21 - /Test_2025_01_21_02_59_59_d972e346-b707-46a5-9a98-ef0195d8d246.jpg: empty ./2025_01_21 - /Test_2025_01_21_02_59_59_d5a5b732-d38e-468c-9f22-08ef90a7b5a5.jpg: empty ./__OTHER: directory ./__OTHER/1f7edcd5-b0cb-4fb0-892f-38a324454eb9.jpg: empty ./__OTHER/2b3aa5b9-d80c-4f43-a370-82f4e14dac64.jpg: empty ./__OTHER/3f69d564-7c93-4105-ad2f-66678523693c.jpg: empty &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;I can always manually fix one file, but I&amp;#39;m just confused why the first one does this? Not sure if it&amp;#39;s the first file it&amp;#39;s encountering at all based on how it&amp;#39;s sorting? Or why that would matter?&lt;/p&gt; &lt;p&gt;VERY new to Perl overall, obviously, so it&amp;#39;s probably something silly.&lt;/p&gt; &lt;p&gt;TIA.&lt;/p&gt; &lt;/div&gt;&lt;!-- SC_ON --&gt; &amp;#32; submitted by &amp;#32; &lt;a href="https://www.reddit.com/user/george-frazee"&gt; /u/george-frazee &lt;/a&gt; &lt;br/&gt; &lt;span&gt;&lt;a href="https://www.reddit.com/r/perl/comments/1u0l438/first_record_in_implicit_n_loop_behaves/"&gt;[link]&lt;/a&gt;&lt;/span&gt; &amp;#32; &lt;span&gt;&lt;a href="https://www.reddit.com/r/perl/comments/1u0l438/first_record_in_implicit_n_loop_behaves/"&gt;[comments]&lt;/a&gt;&lt;/span&gt;</content>
    <id>t3_1u0l438</id>
    <link href="https://www.reddit.com/r/perl/comments/1u0l438/first_record_in_implicit_n_loop_behaves/"/>
    <updated>2026-06-08T21:16:54+00:00</updated>
    <published>2026-06-08T21:16:54+00:00</published>
    <title>First record in implicit -n loop behaves differently than the rest. Hoping to find an explanation.</title>
  </entry>
  <entry xmlns:media="http://search.yahoo.com/mrss/">
    <id>tag:github.com,2008:Grit::Commit/8848c13d93120f501f8dc6f9ba087f53dc743993</id>
    <link type="text/html" rel="alternate" href="https://github.com/Perl/perl5/commit/8848c13d93120f501f8dc6f9ba087f53dc743993"/>
    <title>
        cpan/Archive-Tar - Update to version 3.12
    </title>
    <updated>2026-06-08T15:03:03Z</updated>
    <media:thumbnail height="30" width="30" url="https://avatars.githubusercontent.com/u/50472?s=30&amp;v=4"/>
    <author>
      <name>Leont</name>
      <uri>https://github.com/Leont</uri>
    </author>
    <content type="html">
      &lt;pre style='white-space:pre-wrap;width:81ex'&gt;cpan/Archive-Tar - Update to version 3.12

3.12  02/06/2026 (Stig Palmquist)
- Allow &amp;#39;..&amp;#39; links in secure extract in parent path for
  symlinks and hardlinks&lt;/pre&gt;
    </content>
  </entry>
  <entry xmlns:media="http://search.yahoo.com/mrss/">
    <id>tag:github.com,2008:Grit::Commit/f9f540fb1494960e02fa53656f833026fca7153c</id>
    <link type="text/html" rel="alternate" href="https://github.com/Perl/perl5/commit/f9f540fb1494960e02fa53656f833026fca7153c"/>
    <title>
        inline.h: fix missing C before &lt; &gt; in POD
    </title>
    <updated>2026-06-08T14:25:20Z</updated>
    <media:thumbnail height="30" width="30" url="https://avatars.githubusercontent.com/u/278465?s=30&amp;v=4"/>
    <author>
      <name>mauke</name>
      <uri>https://github.com/mauke</uri>
    </author>
    <content type="html">
      &lt;pre style='white-space:pre-wrap;width:81ex'&gt;inline.h: fix missing C before &amp;lt; &amp;gt; in POD&lt;/pre&gt;
    </content>
  </entry>
  <entry>
    <title>Perl 🐪 Weekly #776 - Learning Perl</title>
    <link rel="alternate" href="https://dev.to/szabgab/perl-weekly-776-learning-perl-717" type="text/html"/>
    <content type="html">&lt;p&gt;Originally published at &lt;a href="https://perlweekly.com/archive/776.html" rel="noopener noreferrer"&gt;Perl Weekly 776&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hi there,&lt;/p&gt;

&lt;p&gt;Recently, I came across an article, &lt;a href="https://medium.com/@realmerlyn/the-day-i-decided-never-to-learn-python-2c59d1a1edc5" rel="noopener noreferrer"&gt;The Day I Decided Never to Learn Python&lt;/a&gt; by &lt;strong&gt;Randal L. Schwartz&lt;/strong&gt;. Well, &lt;strong&gt;Randal&lt;/strong&gt; doesn't need an introduction. He took us back to &lt;strong&gt;2001&lt;/strong&gt;, the same era when I first started learning &lt;strong&gt;Perl&lt;/strong&gt; in 1999. He was a major guiding force during my early programming days.&lt;/p&gt;

&lt;p&gt;Last week, I joined a live session by &lt;strong&gt;Gabor&lt;/strong&gt; focussed on &lt;strong&gt;FalkorDB&lt;/strong&gt;. It was fun watching him code and talk while I sat back as a silent spectator. You can learn a lot just by watching how he approaches coding. It reminded me of many years ago when I did pair programming with him and submitted a pull request to the &lt;strong&gt;Dancer2&lt;/strong&gt; project. Those were the golden days, when I had so much energy and time. That being said, I am still actively learning &lt;strong&gt;Perl&lt;/strong&gt; and discovering how to do new things with it. These concepts may not be new to everyone, but they are new to me. For example, I recently played with &lt;strong&gt;GraphQL&lt;/strong&gt; for the first time, and I've also been experimenting with &lt;strong&gt;RAG&lt;/strong&gt; and &lt;strong&gt;JSON-RPC&lt;/strong&gt;. I have shared my recent experiments down below.&lt;/p&gt;

&lt;p&gt;The process of learning never stops. A few days ago, I noticed an update for &lt;strong&gt;HTTP::Message v7.02&lt;/strong&gt;. Since it was released by &lt;strong&gt;Olaf Alders&lt;/strong&gt;, I was curious to see what had changed. It turned to be something, I hadn't realised for all these years. While I am well-acquainted with HTTP methods like GET, POST, and PUT, I didn't know "0" could actually be a valid HTTP method name if you wanted it to be. This release added support for exactly that, thanks to contributor, &lt;strong&gt;Karen Etheridge&lt;/strong&gt;. Amidst all of this, I am still trying to find time for my upcoming book on &lt;strong&gt;DBIx::Class&lt;/strong&gt;. I recently shared a blog post demonstrating the power of DBIC components, and I am trying my best not to lose focus.&lt;/p&gt;

&lt;p&gt;You might find that this edition is full of my own personal posts, as there was unfortunately very little community news to report this week. Regardless, I hope you enjoy the rest of the newsletter.&lt;/p&gt;

&lt;p&gt;--&lt;br&gt;
  Your editor: Mohammad Sajid Anwar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Announcements
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://blogs.perl.org/users/psc/2026/06/this-week-in-psc-227-2026-06-01.html" rel="noopener noreferrer"&gt;This week in PSC (227) | 2026-06-01&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;This week we were back to full strength. We have now dealt with all of the belated issues and all of the blockers. Paul will be shipping 5.43.11 very shortly. With the amount of changes we have had to merge, we will not be able to rush the .11 cycle, but we intend to start the work on the 5.44 RC early, to ensure that we can release with as little additional delay as possible.&lt;/p&gt;




&lt;h2&gt;
  
  
  Articles
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://theweeklychallenge.org/blog/resultclass-components/" rel="noopener noreferrer"&gt;Result Class - Components&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Continue with the series post on DBIx::Class, in this post I am showing the power of DBIC components dealing with date/timestamp column.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://theweeklychallenge.org/blog/rag-with-perl/" rel="noopener noreferrer"&gt;RAG with Perl&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;In this post, I try to decode what RAG is and how we can implement RAG engine in Perl talking to LLM and Vector database in a docker container.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://theweeklychallenge.org/blog/cpan-deb-package/" rel="noopener noreferrer"&gt;CPAN Debian Package&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;First time managed to build a debian package for DBIx::Class::Async with step by step instructions.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://theweeklychallenge.org/blog/jsonrpc-with-perl/" rel="noopener noreferrer"&gt;JSON-RPC with Perl&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;After dealing with gRPC, next in line was JSON-RPC. The motivation was to explore MCP after getting to know JSON-RPC. It turned out to be too easy demonstrate.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://theweeklychallenge.org/blog/mojo-meets-graphql/" rel="noopener noreferrer"&gt;Mojo meets GraphQL&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The post is meant for beginners as I am exploring GraphQL for the first time as well. The best part is the use of GraphiQL for building and testing the API.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://theweeklychallenge.org/blog/dbic-graphql/" rel="noopener noreferrer"&gt;DBIx::Class and GraphQL&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;In this post, I shared how to integrate DBIx::Class with GraphQL. Having played with GraphQL, I can say it is not for weak heart. If you are coming from REST API background then it will take some time to get your head around it. I am telling this from my personal exprience.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://theweeklychallenge.org/blog/cpan-graphql/" rel="noopener noreferrer"&gt;CPAN and GraphQL&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;After DBIx::Class integration with GraphQL, my immediate task was to make the process easy as it doesn't have to this complicated. In the process, I released brand new CPAN distribution: DBIx::Class::Schema::GraphQL.&lt;/p&gt;




&lt;h2&gt;
  
  
  CPAN
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://metacpan.org/dist/FalkorDB" rel="noopener noreferrer"&gt;FalkorDB&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Perl client module for FalkorDB. This code was mostly generated using AI tools and has not been checked manually yet.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://metacpan.org/pod/DBIx::Class::Schema::GraphQL" rel="noopener noreferrer"&gt;DBIx::Class::Schema::GraphQL&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;It was created while working on the DBIx::Class integration with GraphQL. Using this module, it is so easy to build GraphQL API.&lt;/p&gt;




&lt;h2&gt;
  
  
  Grants
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://news.perlfoundation.org/post/maintaining_perl_tonyc_may_2026" rel="noopener noreferrer"&gt;Maintaining Perl (Tony Cook) May 2026&lt;/a&gt;
&lt;/h3&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://news.perlfoundation.org/post/maintaining_perl_dave_mitchell_may_2026" rel="noopener noreferrer"&gt;Maintaining Perl 5 Core (Dave Mitchell): May 2026&lt;/a&gt;
&lt;/h3&gt;




&lt;h2&gt;
  
  
  The Weekly Challenge
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://theweeklychallenge.org" rel="noopener noreferrer"&gt;The Weekly Challenge&lt;/a&gt; by &lt;a href="https://manwar.org" rel="noopener noreferrer"&gt;Mohammad Sajid Anwar&lt;/a&gt; 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 Marc Perry.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-377" rel="noopener noreferrer"&gt;The Weekly Challenge - 377&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Welcome to a new week with a couple of fun tasks "Reverse Existence" and "Prefix Suffix". If you are new to the weekly challenge then why not join us and have fun every week. For more information, please read the &lt;a href="https://theweeklychallenge.org/faq" rel="noopener noreferrer"&gt;FAQ&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://theweeklychallenge.org/blog/recap-challenge-376" rel="noopener noreferrer"&gt;RECAP - The Weekly Challenge - 376&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Enjoy a quick recap of last week's contributions by Team PWC dealing with the "Chessboard Squares" and "Doubled Words" tasks in Perl and Raku. You will find plenty of solutions to keep you busy.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://raku-musings.com/doubled-chessboard.html" rel="noopener noreferrer"&gt;Doubled Chessboard&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The post offers an orderly, aesthetically pleasing way of solving the Weekly Challenge problems using the modern-day features of Raku syntax. With the use of well-defined subset custom types to strongly validate input and a simple, tokenising object-oriented class structure for text processing, Arne creates a solution that is easy to read and maintain and takes care of the complex edge cases such as applying a look behind that crosses over multiple lines.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://dev.to/boblied/pwc-376-doubled-words-7g3"&gt;Doubled Words&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Bob presents a creative solution to a challenging text processing issue by using a well known yet little used built-in feature of the Perl. The result is an elegant mechanism for bypassing tokens through a clearly documented and separated mechanism of backtracking while retaining context about the structure through the use of captured groups in the split regex.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.sommrey.de/the-bears-den/2026/06/05/ch-376.html" rel="noopener noreferrer"&gt;Chess Solo&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Jorg provides a very concise and mathematically elegant solution for the colorisation of a chessboard. By recognising that under mod 2 operations the coordinate bases are completely annihilated, implementations can be created in both Perl and J using only one line of code and they are both efficient and structurally minimalist.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://kolouch.net/perlweeklychallenge/blog-376.html" rel="noopener noreferrer"&gt;The Weekly Challenge 376&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;An unusually clear yet detailed solution is provided in this blog post, as it combines clean, idiomatic code examples with short technical explanations about how to use regex to parse doubled words and how to compare two mathematical coordinates. Complex logic is presented so anyone can read easily and learn from.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://wlmb.github.io/2026/06/01/PWC376/" rel="noopener noreferrer"&gt;Perl Weekly Challenge 376&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The excellent demonstration of the capabilities of Perl as a function-based programming language is shown through this post with extremely short and idiomatic solutions. Luis Mochán has used expressive, single-line statements to convert complicated constraints into small, clean, logical data flows in an extraordinary manner with Perl.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/MatthiasMuth/perlweeklychallenge-club/tree/muthm-376/challenge-376/matthias-muth#readme" rel="noopener noreferrer"&gt;A 1-Bit Chessboard and Fancy Separators&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Matthias presents an analytical and well-defined solution to the difficulties presented by Challenge 376 through the use of well-separated parsing and formatting, clear comments on the use of regular expressions, and the submission of a clear and clean solution suitable for production.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://packy.dardan.com/b/r4" rel="noopener noreferrer"&gt;You might think I’m crazy, but I don’t even care&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;A well-structured and very interesting review of Perl Weekly Challenge 376 is presented with a reference to principles from a popular culture item. Packy clearly illustrates the elegant way to process text in the real world while exhibiting outstanding technical expertise by explaining the complexity of lookahead logic and the constraints of the boundary in a way that allows for simple, idiomatic, and highly maintainable solutions.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="http://ccgi.campbellsmiths.force9.co.uk/challenge/376" rel="noopener noreferrer"&gt;Squares and pairs&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;This solution offers a very neat, simple, and mathematically pleasing method for solving the chessboard parity problem. Peter has effectively utilised the ASCII values (ord) of the column letters as well as the numeric row values to reduce a spatial coordinate problem to a quick and efficient calculation of a bitwise parity (&amp;amp; 1). The source code is formatted well, clearly commented, and takes advantage of the mathematics behind the solution so as to avoid unnecessary conditional barriers.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://reiniermaliepaard.nl/pwc/index.php?id=pwc376-1" rel="noopener noreferrer"&gt;The Weekly Challenge - 376: Chessboard Squares&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;This post gives a very clear, well-organized, and visually intuitive representation of how to solve the programming challenge "Chessboard Squares". Explicitly laying out the grid coordinates with their appropriate color will provide an excellent foundation for developing an accurate and efficient lookup algorithm.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://hatley-software.blogspot.com/2026/06/robbie-hatleys-solutions-in-perl-for.html" rel="noopener noreferrer"&gt;The Weekly Challenge #376&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;By using an elegant mathematical approach to the parity of squares on a chessboard, along with an incredibly efficient, single-pass regular expression, this code shows immense technical skill. The code also uses multi-line lookaheads, HTML tags, and back references, all handled by a simple subroutine (double_double_toil_and_trouble), that is suitable for use at production level.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://blog.firedrake.org/archive/2026/06/The_Weekly_Challenge_376__Half_a_Chessboard.html" rel="noopener noreferrer"&gt;Half a Chessboard&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;A general description of a previously completed task, this post shows a real-life application of code reuse. Roger created a nice, modular solution to decode coordinate mathematics (on the basis of (x+y) mod 2) by cleanly wrapping the existing helper function from the previous task. Therefore, through this implementation, he provides a concise representation of the solution and eliminates any duplicate logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://dev.to/simongreennet/weekly-challenge-double-chessboard-5ce5"&gt;Double chessboard&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;In this blog post, Simon's clever use of the bitwise XOR operator (^) as a parity check for a chess board is very creative. Additionally, he shows a well-organised and simple method of utilising re.split and list comprehensions to find the position of words while also overcoming some challenging lookahead and HTML boundary situations.&lt;/p&gt;




&lt;h2&gt;
  
  
  Rakudo
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://rakudoweekly.blog/2026/06/01/2026-22-some-ast-fruit/" rel="noopener noreferrer"&gt;2026.22 Some AST Fruit&lt;/a&gt;
&lt;/h3&gt;




&lt;h2&gt;
  
  
  Weekly collections
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="http://niceperl.blogspot.com/" rel="noopener noreferrer"&gt;NICEPERL's lists&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://niceperl.blogspot.com/2026/06/dciii-22-great-cpan-modules-released.html" rel="noopener noreferrer"&gt;Great CPAN modules released last week&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The corner of Gabor
&lt;/h2&gt;

&lt;p&gt;A couple of entries sneaked in by Gabor.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://academy.code-maven.com/l/os-perl-2026-06-03-part-1" rel="noopener noreferrer"&gt;FalkorDB client in Perl using CLI AI Agents&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;This is the first hour of the live coding session using AI to write Perl we had last week. (Free, registration required)&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://academy.code-maven.com/l/os-perl-2026-06-03-part-2" rel="noopener noreferrer"&gt;FalkorDB using Perl&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;This is the second hour of the live coding session using AI to write Perl we had last week. (Free, registration required)&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://luma.com/perl-maven" rel="noopener noreferrer"&gt;Next: Perl development using AI&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The next session in which each participant will have the opportunity to show how s/he is using AI to write Perl code. I am sure we will learn a lot from each other!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.youtube.com/watch?v=xvxZAGIPGhg" rel="noopener noreferrer"&gt;Growing Pains: Scaling AI Coding across Team and Repo Boundaries with Graham Knapp&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Video recordings from the session yesterday. It is not Perl specific, but helps you understand things. For more such event, sign up to the &lt;a href="https://www.meetup.com/code-mavens/" rel="noopener noreferrer"&gt;Code Mavens&lt;/a&gt; Meetup group&lt;/p&gt;




&lt;h2&gt;
  
  
  Events
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://boston.pm.org/" rel="noopener noreferrer"&gt;Boston Perl Mongers virtual monthly&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;June 9, 2026&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://paris.mongueurs.net/" rel="noopener noreferrer"&gt;Paris.pm monthly meeting&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;June 10, 2026&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.meetup.com/hacklafayette/" rel="noopener noreferrer"&gt;Purdue Perl Mongers (HackLafayette) - TBA&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;June 11, 2026&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://luma.com/perl-maven" rel="noopener noreferrer"&gt;Perl development using AI (online)&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;June 17, 2026&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://berlin.pm.org/" rel="noopener noreferrer"&gt;Berlin.pm - Naumanns Biergarten&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;June 24, 2026&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://luma.com/calendar/cal-ZFzHes2YwV6j0h9" rel="noopener noreferrer"&gt;Toronto.pm - June Social Evening&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;June 25, 2026&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://tprc.us/tprc-2026-gsp/" rel="noopener noreferrer"&gt;The Perl and Raku Conference 2026&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;June 26-29, 2026, Greenville, SC, USA&lt;/p&gt;




&lt;p&gt;You joined the Perl Weekly to get weekly e-mails about the Perl programming language and related topics.&lt;/p&gt;

&lt;p&gt;Want to see more? See the &lt;a href="https://perlweekly.com/archive/" rel="noopener noreferrer"&gt;archives&lt;/a&gt; of all the issues.&lt;/p&gt;

&lt;p&gt;Not yet subscribed to the newsletter? &lt;a href="https://perlweekly.com/subscribe.html" rel="noopener noreferrer"&gt;Join us free of charge&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;(C) Copyright &lt;a href="https://szabgab.com/" rel="noopener noreferrer"&gt;Gabor Szabo&lt;/a&gt;&lt;br&gt;
The articles are copyright the respective authors.&lt;/p&gt;

</content>
    <author>
      <name>Gabor Szabo</name>
    </author>
    <id>https://dev.to/szabgab/perl-weekly-776-learning-perl-717</id>
    <published>2026-06-08T06:13:39Z</published>
    <updated>2026-06-08T06:13:39Z</updated>
    <category term="perl"/>
    <category term="news"/>
    <category term="programming"/>
  </entry>
  <entry>
    <title>RECAP - The Weekly Challenge - 376 | Jun 2026 | The Weekly Challenge</title>
    <link rel="alternate" href="https://theweeklychallenge.org/blog/recap-challenge-376/" type="text/html"/>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">Thank you Team PWC for your continuous support and encouragement.</div>
    </content>
    <id>https://theweeklychallenge.org/blog/recap-challenge-376/</id>
    <published>2026-06-08T00:00:00Z</published>
    <updated>2026-06-08T00:00:00Z</updated>
  </entry>
  <entry>
    <title>The Weekly Challenge - 377 | Jun 2026 | The Weekly Challenge</title>
    <link rel="alternate" href="https://theweeklychallenge.org/blog/perl-weekly-challenge-377/" type="text/html"/>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">Welcome to the Week #377 of The Weekly Challenge.</div>
    </content>
    <id>https://theweeklychallenge.org/blog/perl-weekly-challenge-377/</id>
    <published>2026-06-08T00:00:00Z</published>
    <updated>2026-06-08T00:00:00Z</updated>
  </entry>
  <entry xmlns:media="http://search.yahoo.com/mrss/">
    <id>tag:github.com,2008:Grit::Commit/3b48f573bfa490d38e4d5f482d44f7640c05d139</id>
    <link type="text/html" rel="alternate" href="https://github.com/Perl/perl5/commit/3b48f573bfa490d38e4d5f482d44f7640c05d139"/>
    <title>
        perlclass.pod: Update KNOWN BUGS section
    </title>
    <updated>2026-06-07T17:41:39Z</updated>
    <media:thumbnail height="30" width="30" url="https://avatars.githubusercontent.com/u/2728929?s=30&amp;v=4"/>
    <author>
      <name>johannessen</name>
      <uri>https://github.com/johannessen</uri>
    </author>
    <content type="html">
      &lt;pre style='white-space:pre-wrap;width:81ex'&gt;perlclass.pod: Update KNOWN BUGS section&lt;/pre&gt;
    </content>
  </entry>
  <entry>
    <title>Weekly Challenge: Double chessboard</title>
    <link rel="alternate" href="https://dev.to/simongreennet/weekly-challenge-double-chessboard-5ce5" type="text/html"/>
    <content type="html">&lt;h2&gt;
  
  
  Weekly Challenge 376
&lt;/h2&gt;

&lt;p&gt;Each week Mohammad S. Anwar sends out &lt;a href="https://theweeklychallenge.org/" rel="noopener noreferrer"&gt;The Weekly Challenge&lt;/a&gt;, a chance for all of us to come up with solutions to two weekly tasks. My solutions are written in Python first, and then converted to Perl. Unless otherwise stated, Copilot (and other AI tools) have NOT been used to generate the solution. It's a great way for us all to practice some coding.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-376/" rel="noopener noreferrer"&gt;Challenge&lt;/a&gt;, &lt;a href="https://github.com/manwar/perlweeklychallenge-club/tree/master/challenge-376/sgreen" rel="noopener noreferrer"&gt;My solutions&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Task 1: Chessboard Squares
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Task
&lt;/h3&gt;

&lt;p&gt;You are given two coordinates of a square on 8x8 chessboard.&lt;/p&gt;

&lt;p&gt;Write a script to find the given two coordinates have the same colour.&lt;/p&gt;

&lt;h3&gt;
  
  
  My solution
&lt;/h3&gt;

&lt;p&gt;This - like most first tasks - is relatively straight forward. I have a function called &lt;code&gt;is_black&lt;/code&gt; and it takes a &lt;code&gt;cell&lt;/code&gt; variable as a parameter.&lt;/p&gt;

&lt;p&gt;After checking the square is valid (first letter &lt;code&gt;a-g&lt;/code&gt;, second number &lt;code&gt;1-8&lt;/code&gt;), it then uses the exclusive xor operator &lt;code&gt;^&lt;/code&gt; to determine if a square is black.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_black&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;^[a-h][1-8]$&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Cell &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cell&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; is not valid!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;aceg&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;same_color&lt;/code&gt; function simply checks if the two specified squares are the same.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;same_color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;is_black&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nf"&gt;is_black&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Perl solution follows the same logic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;is_black&lt;/span&gt;&lt;span class="p"&gt;($cell) {&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$cell&lt;/span&gt; &lt;span class="o"&gt;!~&lt;/span&gt; &lt;span class="sr"&gt;/^[a-h][1-8]$/&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;die&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Cell '&lt;/span&gt;&lt;span class="si"&gt;$cell&lt;/span&gt;&lt;span class="s2"&gt;' is not valid!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aceg&lt;/span&gt;&lt;span class="p"&gt;",&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$cell&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$cell&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt; &lt;span class="p"&gt;( $c1, $c2 ) {&lt;/span&gt;
    &lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;is_black&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$c1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nv"&gt;is_black&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$c2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;false&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Examples
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./ch-1.py a7 f4
&lt;span class="nb"&gt;true&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;./ch-1.py c1 e8
&lt;span class="nb"&gt;false&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;./ch-1.py b5 h2
&lt;span class="nb"&gt;false&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;./ch-1.py f3 h1
&lt;span class="nb"&gt;true&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;./ch-1.py a1 g7
&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Task 2: Doubled Words
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Task
&lt;/h3&gt;

&lt;p&gt;You are given a string (which may contain embedded newlines) which is taken from a page on a website. The string will not contain brackets &lt;code&gt;qw{ [ ] }.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Write a script that will find doubled words (such as "this this") and highlight (wrap in brackets) each doubled word.&lt;/p&gt;

&lt;p&gt;The script should:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Work across lines, even finding situations where a word at the end of one line is repeated at the beginning of the next.&lt;/li&gt;
&lt;li&gt;Find doubled words despite capitalization differences, such as with 'The the...', as well as allow differing amounts of white-space (spaces, tabs, newlines, and the like) to lie between the words.&lt;/li&gt;
&lt;li&gt;Find doubled words even when separated by HTML tags. For example, to  make a word bold: '...it is &lt;b&gt;very&lt;/b&gt; very important...'. Only show  lines containing doubled words.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  My solution
&lt;/h3&gt;

&lt;p&gt;For input from the command line I replace a literal &lt;code&gt;\n&lt;/code&gt; (i.e. a backslash followed by the letter 'n') with a new line character. The output replaces new lines with a literal &lt;code&gt;\n&lt;/code&gt;. This ensures that I can copy and paste the examples. The Python test suite calls the function directly, so does not need this functionality.&lt;/p&gt;

&lt;p&gt;Wow. This one is really tricky. To me an English word is some letters, optionally with a hyphen or apostrophe in the middle (e.g. &lt;code&gt;one-sided&lt;/code&gt; or &lt;code&gt;don't&lt;/code&gt;). Annoyingly apostrophes can also be used before or after a word to indicate a quote.&lt;/p&gt;

&lt;p&gt;My first attempt at solving this was so bad, I went back to the drawing board for my second attempt. I have a solution that words (all five tests pass), but I'm sure that there is a more efficient solution.&lt;/p&gt;

&lt;p&gt;I start this task by separating HTML (regular expression &lt;code&gt;&amp;lt;[^&amp;gt;]+&amp;gt;&lt;/code&gt;, an open angle bracket, multiple characters that aren't a close angle bracket, and a close angle bracket) and words (regular expression &lt;code&gt;[a-z0-9]+(?:['-][a-z0-9]+)*&lt;/code&gt;, letters optionally with hyphen or apostrophe in the middle) from other content (white space, punctuation, etc). As the first parameter to &lt;code&gt;re.split&lt;/code&gt; is surround by parentheses, the words and HTML are also returned.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;doubled_words&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_string&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;regexp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;(&amp;lt;[^&amp;gt;]+&amp;gt;|[a-z]+(?:[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;-][a-z]+)*)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;words_and_html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;regexp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;input_string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IGNORECASE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next step is to find the position of all words only. This uses list comprehension to exclude even (0-based) elements (white space and punctuation) and HTML elements.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="n"&gt;parts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="n"&gt;i&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next I go through the &lt;code&gt;word_positions&lt;/code&gt; list and replace words that are the same as the next word (case insensitive). It should be noted that triple words will only have the first two occurrences replaced.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;word_positions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;this_pos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;word_positions&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;next_pos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;word_positions&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;this_pos&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;next_pos&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;this_pos&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;this_pos&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;next_pos&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;next_pos&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that done, I then separate the original input and new parts into two lists separated by new lines.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="n"&gt;input_lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[\r\n]+&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;input_string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;output_lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[\r\n]+&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, I find the lines that are different (using list comprehension again) and return only the lines that are different, separated by new lines.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="n"&gt;different_lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="n"&gt;output&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output_lines&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;input_lines&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;different_lines&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Perl solution follows the same logic, and uses &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;grep&lt;/code&gt; to mimic list comprehension.&lt;/p&gt;

&lt;h3&gt;
  
  
  Examples
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./ch-2.py &lt;span class="s2"&gt;"you're given the job of checking the pages on a&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;web server for doubled words (such as 'this this'), a common problem&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;with documents subject to heavy editing."&lt;/span&gt;
&lt;span class="s2"&gt;"web server for doubled words (such as '[this] [this]'), a common problem"&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;./ch-2.py &lt;span class="s2"&gt;"Find doubled words despite capitalization differences, such as with 'The&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;the...', as well as allow differing amounts of whitespace (spaces,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;tabs, newlines, and the like) to lie between the words."&lt;/span&gt;
&lt;span class="s2"&gt;"Find doubled words despite capitalization differences, such as with '[The]&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;[the]...', as well as allow differing amounts of whitespace (spaces,"&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;./ch-2.py &lt;span class="s2"&gt;"to make a word bold: '...it is &amp;lt;B&amp;gt;very&amp;lt;/B&amp;gt; very important...'."&lt;/span&gt;
&lt;span class="s2"&gt;"to make a word bold: '...it is &amp;lt;B&amp;gt;[very]&amp;lt;/B&amp;gt; [very] important...'."&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;./ch-2.py &lt;span class="s2"&gt;"Perl officially stands for Practical Extraction and Report Language, except when it doesn't."&lt;/span&gt;
&lt;span class="s2"&gt;""&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;./ch-2.py &lt;span class="s2"&gt;"There's more than one one way to do it.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Easy things should be easy and hard things should be possible."&lt;/span&gt;
&lt;span class="s2"&gt;"There's more than [one] [one] way to do it."&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;./ch-2.py &lt;span class="s2"&gt;"I can't can't do this"&lt;/span&gt;
&lt;span class="s2"&gt;"I [can't] [can't] do this"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</content>
    <author>
      <name>Simon Green</name>
    </author>
    <id>https://dev.to/simongreennet/weekly-challenge-double-chessboard-5ce5</id>
    <published>2026-06-07T12:17:33Z</published>
    <updated>2026-06-07T12:17:33Z</updated>
    <category term="python"/>
    <category term="perl"/>
    <category term="theweeklychallenge"/>
  </entry>
  <entry>
    <title>CPAN and GraphQL | Jun 2026 | The Weekly Challenge</title>
    <link rel="alternate" href="https://theweeklychallenge.org/blog/cpan-graphql/" type="text/html"/>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">On the subject of GraphQL, I have written two blog posts so far:</div>
    </content>
    <id>https://theweeklychallenge.org/blog/cpan-graphql/</id>
    <published>2026-06-07T00:00:00Z</published>
    <updated>2026-06-07T00:00:00Z</updated>
  </entry>
  <entry>
    <title>The Weekly Challenge - Guest Contributions | Jun 2026 | The Weekly Challenge</title>
    <link rel="alternate" href="https://theweeklychallenge.org/blog/guest-contribution/" type="text/html"/>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">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, CUDA, D, Dart, Dc, Elixir, Elm, Emacs Lisp, Erlang, Excel VBA, F#, Factor, Fennel, Fish, Forth, Fortran, Gembase, Gleam, 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, PicoLisp, Python, PostgreSQL, Postscript, PowerShell, Prolog, R, Racket, Rexx, Ring, Roc, Ruby, Rust, Scala, Scheme, Sed, Smalltalk, SQL, Standard ML, SVG, Swift, Tcl, TypeScript, Typst, Uiua, V, Visual BASIC, WebAssembly, Wolfram, XSLT, YaBasic and Zig.</div>
    </content>
    <id>https://theweeklychallenge.org/blog/guest-contribution/</id>
    <published>2026-06-07T00:00:00Z</published>
    <updated>2026-06-07T00:00:00Z</updated>
  </entry>
  <entry xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0">
    <id>tag:blogger.com,1999:blog-5910101498857524639.post-2933389105103436999</id>
    <published>2026-06-06T20:02:35.813+02:00</published>
    <updated>2026-06-06T20:02:35.813+02:00</updated>
    <category scheme="http://www.blogger.com/atom/ns#" term="cpan"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="perl"/>
    <title type="text">(dciii) 22 great CPAN modules released last week</title>
    <content type="html">Updates for &lt;i&gt;great CPAN modules&lt;/i&gt; released last week. A module is considered &lt;i&gt;great&lt;/i&gt; if its favorites count is greater or equal than 12.&lt;br/&gt;&lt;br/&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/OLIVER/App-Netdisco-2.099007' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;App::Netdisco&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - An open source web-based network management tool.
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;2.099007&lt;/strong&gt; on 2026-06-05, with 877 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 2.099005 was released 5 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/OLIVER'&gt;OLIVER&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/PMQS/App-zipdetails-4.007' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;App::zipdetails&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Display details about the internal structure of Zip files
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;4.007&lt;/strong&gt; on 2026-06-01, with 66 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 4.006 was released 16 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/PMQS'&gt;PMQS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/BINGOS/Archive-Tar-3.12' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Archive::Tar&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Manipulates TAR archives
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;3.12&lt;/strong&gt; on 2026-06-02, with 16 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 3.10 was released 8 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/BINGOS'&gt;BINGOS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/GWILLIAMS/Attean-0.039' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Attean&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - A Semantic Web Framework
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;0.039&lt;/strong&gt; on 2026-06-02, with 19 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 0.038_03 was released the same day&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/GWILLIAMS'&gt;GWILLIAMS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/BRIANDFOY/CPANSA-DB-20260531.001' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;CPANSA::DB&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - the CPAN Security Advisory data as a Perl data structure, mostly for CPAN::Audit
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;20260531.001&lt;/strong&gt; on 2026-06-02, with 25 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 20260524.001 was released 9 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/BRIANDFOY'&gt;BRIANDFOY&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/JONASBN/Crypt-OpenSSL-X509-2.1.1' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Crypt::OpenSSL::X509&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Perl extension to OpenSSL's X509 API.
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;2.1.1&lt;/strong&gt; on 2026-06-03, with 26 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 2.1.1 was released 6 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/JONASBN'&gt;JONASBN&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/HMBRAND/DBI-1.648' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;DBI&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Database independent interface for Perl
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;1.648&lt;/strong&gt; on 2026-06-04, with 283 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 1.647 was released 1 year, 4 months, 15 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/HMBRAND'&gt;HMBRAND&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/RURBAN/GD-2.85' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;GD&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Perl interface to the libgd graphics library
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;2.85&lt;/strong&gt; on 2026-06-02, with 32 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 2.84 was released 4 months, 28 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/RURBAN'&gt;RURBAN&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/OALDERS/HTTP-Message-7.02' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;HTTP::Message&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - HTTP style message (base class)
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;7.02&lt;/strong&gt; on 2026-06-05, with 71 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 7.01 was released 7 months, 17 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/OALDERS'&gt;OALDERS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/ETHER/JSON-Schema-Modern-0.640' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;JSON::Schema::Modern&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Validate data against a schema using a JSON Schema
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;0.640&lt;/strong&gt; on 2026-05-30, with 17 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 0.639 was released 20 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/ETHER'&gt;ETHER&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/JHTHORSEN/JSON-Validator-5.17' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;JSON::Validator&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Validate data against a JSON schema
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;5.17&lt;/strong&gt; on 2026-06-04, with 59 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 5.16 was released the same day&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/JHTHORSEN'&gt;JHTHORSEN&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/BINGOS/Module-CoreList-5.20260601' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Module::CoreList&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - what modules shipped with versions of perl
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;5.20260601&lt;/strong&gt; on 2026-06-01, with 45 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 5.20260420 was released 1 month, 11 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/BINGOS'&gt;BINGOS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/JBERGER/Mojo-JWT-1.02' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Mojo::JWT&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - JSON Web Token the Mojo way
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;1.02&lt;/strong&gt; on 2026-06-03, with 18 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 1.01 was released 1 year, 7 months, 18 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/JBERGER'&gt;JBERGER&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/JHTHORSEN/Mojo-Redis-3.31' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Mojo::Redis&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Redis driver based on Mojo::IOLoop
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;3.31&lt;/strong&gt; on 2026-06-04, with 21 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 3.30 was released the same day&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/JHTHORSEN'&gt;JHTHORSEN&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/SRI/Mojolicious-9.46' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Mojolicious&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Real-time web framework
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;9.46&lt;/strong&gt; on 2026-06-04, with 512 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 9.45 was released 29 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/SRI'&gt;SRI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/JHTHORSEN/Mojolicious-Plugin-OpenAPI-5.12' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Mojolicious::Plugin::OpenAPI&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - OpenAPI / Swagger plugin for Mojolicious
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;5.12&lt;/strong&gt; on 2026-06-06, with 56 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 5.11 was released 1 year, 2 months, 18 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/JHTHORSEN'&gt;JHTHORSEN&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/RURBAN/Net-Ping-2.77' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Net::Ping&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - check a remote host for reachability
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;2.77&lt;/strong&gt; on 2026-06-02, with 15 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 2.76 was released 8 months, 24 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/RURBAN'&gt;RURBAN&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/JHTHORSEN/OpenAPI-Client-1.09' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;OpenAPI::Client&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - A client for talking to an Open API powered server
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;1.09&lt;/strong&gt; on 2026-06-04, with 16 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 1.08 was released the same day&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/JHTHORSEN'&gt;JHTHORSEN&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/KIMOTO/SPVM-0.990181' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;SPVM&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - The SPVM Language
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;0.990181&lt;/strong&gt; on 2026-06-03, with 36 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 0.990180 was released 2 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/KIMOTO'&gt;KIMOTO&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/HAARG/Storable-3.41' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Storable&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - persistence for Perl data structures
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;3.41&lt;/strong&gt; on 2026-06-06, with 57 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 3.25 was released 4 years, 9 months, 7 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/HAARG'&gt;HAARG&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/DANBERR/Sys-Virt-v12.4.0' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Sys::Virt&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - libvirt Perl API
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;v12.4.0&lt;/strong&gt; on 2026-06-05, with 17 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: v12.3.0 was released 30 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/DANBERR'&gt;DANBERR&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/PEVANS/Tickit-0.77' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Tickit&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Terminal Interface Construction KIT
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;0.77&lt;/strong&gt; on 2026-06-01, with 29 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 0.76 was released the same day&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/PEVANS'&gt;PEVANS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content>
    <link rel="replies" type="application/atom+xml" href="https://niceperl.blogspot.com/feeds/2933389105103436999/comments/default" title="Enviar comentarios"/>
    <link rel="replies" type="text/html" href="https://niceperl.blogspot.com/2026/06/dciii-22-great-cpan-modules-released.html#comment-form" title="0 comentarios"/>
    <link rel="edit" type="application/atom+xml" href="https://www.blogger.com/feeds/5910101498857524639/posts/default/2933389105103436999"/>
    <link rel="self" type="application/atom+xml" href="https://www.blogger.com/feeds/5910101498857524639/posts/default/2933389105103436999"/>
    <link rel="alternate" type="text/html" href="https://niceperl.blogspot.com/2026/06/dciii-22-great-cpan-modules-released.html" title="(dciii) 22 great CPAN modules released last week"/>
    <author>
      <name>prz</name>
      <uri>http://www.blogger.com/profile/17989445983340548566</uri>
      <email>noreply@blogger.com</email>
      <gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="https://img1.blogblog.com/img/b16-rounded.gif"/>
    </author>
    <thr:total>0</thr:total>
  </entry>
  <entry>
  <title>Maintaining Perl (Tony Cook) May 2026 </title>
  <link rel="alternate" type="text/html" href="https://news.perlfoundation.org/post/maintaining_perl_tonyc_may_2026"/>
  <id>tag:news.perlfoundation.org,2026-06-06:/post/maintaining_perl_tonyc_may_2026</id>
  <published>2026-06-06T16:13:25</published>
  <updated>2026-06-06T16:13:25</updated>
  <summary>
  <![CDATA[
     Tony writes: 2026/05/04 Monday  1.12 Dave’s C11 _Atomic on p5p: testing, research and respond  0.35 #24402 research and comment  0.38 more _Atomic research and respond some more  1.23 #24284 read, research and comment, work up a patch and  push for CI  0.23 selfloader: check CI results and make PR 24404  0.68 more _Atomic: research and respond to leont  0.28 #24166 review discussion, 
   ]]>
  </summary>
  <author>
    <name>alh</name>
  </author>
  <category term="Grants" scheme="http://www.sixapart.com/ns/types#category"/>
  <category term="Perl 5 Development" scheme="http://www.sixapart.com/ns/types#category"/>  <content type="html" xml:lang="en-us" xml:base="http://news.perlfoundation.org/">
   <![CDATA[
     
       <img src="_ra-rel-mnt_/simplecas/fetch_content/7f97282811f6a9f862d7e659c79e5462cc195d94/grant-funding.png" style="max-width:100%;max-height:100%;padding:20px;" /><br>
     
     <p>Tony writes:
```
[Hours]         [Activity]
2026/05/04      Monday
 1.12           Dave’s C11 _Atomic on p5p: testing, research and respond
 0.35           #24402 research and comment
 0.38           more _Atomic - research and respond some more
 1.23           #24284 read, research and comment, work up a patch and
                push for CI
 0.23           selfloader: check CI results and make PR 24404
 0.68           more _Atomic: research and respond to leont
 0.28           #24166 review discussion, research</p>

<h1> 0.95           #24166 work up a test case debugging</h1>

<p>5.22</p>

<p>2026/05/05      Tuesday
 0.15           #24284 minor fix
 0.08           selfloader: apply to blead as suggested by PSC
 0.65           #24406 review, find old problems that have already been
                reported.
 0.52           das
 0.55           #24166 work on a fix</p>

<h1> 1.05           #24166 more work on a fix - re-work</h1>

<p>3.00</p>

<p>2026/05/06      Wednesday
 1.68           #24407 testing, research, comments, work on a revert patch
                and push for smoke-me/CI
 1.98           #24407 follow-up, work on a possible fix, push for
                smoke/CI and ask jkeenan to test
 0.63           #24407 clean up, and add checks, testing and push to</p>

<h1>                update smoke-me</h1>

<p>4.29</p>

<p>2026/05/07      Thursday
 1.72           #24407 check smoke results, test the new fix branch
                elsewhere, open PRs #24409 (try to fix some more), #24410
                (revert)
 0.98           #24166 try to work out a fix</p>

<h1> 0.30           smoke-me branch cleanup</h1>

<p>3.00</p>

<p>2026/05/11      Monday
 0.53           #24413 review and comment
 0.20           #24414 review, xenu covered it
 0.83           #24416 review and comment
 0.55           #24410 follow-up
 1.58           security list - testing, debugging, research and reply
 0.50           #24416 follow-up</p>

<h1> 1.05           utf8-strict rebase, re-check, start on line reading</h1>

<p>5.24</p>

<p>2026/05/12      Tuesday
 0.08           #24413 review update and approve
 0.47           investigate detect conflicts failures and work up PR 24419
 1.02           selfloader mixed io - rebase on blead updates, testing,
                push for CI/smoke-me
 0.68           macos readdir, research, setup environment</p>

<h1> 2.03           security list</h1>

<p>4.28</p>

<p>2026/05/13      Wednesday
 0.55           research and work up a trivial patch for the vs2026
                related build failures PR 24421</p>

<h1> 1.53           security list - stuff</h1>

<p>2.08</p>

<p>2026/05/14      Thursday
 0.90           #24412 review, comment
 0.47           #24420 review and approve
 0.17           #24423 review and approve
 1.30           security list</p>

<h1> 0.88           security list</h1>

<p>3.72</p>

<p>2026/05/15      Friday</p>

<h1> 0.50           security list</h1>

<p>0.50</p>

<p>2026/05/18      Monday
 2.58           security list</p>

<h1> 1.75           security list</h1>

<p>4.33</p>

<p>2026/05/19      Tuesday
 0.10           #24421 apply to blead on PSC approval
 0.08           #24419 comment
 0.08           security list</p>

<h1> 1.33           security list</h1>

<p>1.59</p>

<p>2026/05/20      Wednesday</p>

<h1> 0.38           perl-security #147: perldelta, make PR 24433</h1>

<p>0.38</p>

<p>2026/05/21      Thursday
 0.08           #24433 apply to blead
 1.30           #24434 review, research and comment
 0.18           #24431 review, research history and comment
 0.08           #24438 review and approve
 0.25           #24437 review and approve
 0.70           security list - sec 148</p>

<h1> 2.50           security list - debugging</h1>

<p>5.09</p>

<p>2026/05/22      Friday
 0.20           #24433 follow-up on security ticket
 0.42           #24434 review and comment
 0.12           #24431 review and approve</p>

<h1> 1.17           security list sec 148</h1>

<p>1.91</p>

<p>2026/05/25      Monday
 1.40           #24439 look into MacOS and Cygwin lockups (cygwin still
                running)
 1.88           security list, more #24439 follow-up, security stuff re-
                work</p>

<h1> 1.27           security list - re-work, testing</h1>

<p>4.55</p>

<p>2026/05/26      Tuesday
 2.07           security list - debugging, fixes, debugging</p>

<h1> 1.98           security list - more debugging, fix some issues</h1>

<p>4.05</p>

<p>2026/05/27      Wednesday
 1.58           security list sec 148
 0.85           security list</p>

<h1> 2.22           security list</h1>

<p>4.65</p>

<p>Which I calculate is 57.88 hours.</p>

<p>Approximately 21 tickets were reviewed or worked on, and 2 patches
were applied.
```</p>

    ]]>
  </content>
</entry>
  <entry>
  <title>Maintaining Perl 5 Core (Dave Mitchell): May 2026 </title>
  <link rel="alternate" type="text/html" href="https://news.perlfoundation.org/post/maintaining_perl_dave_mitchell_may_2026"/>
  <id>tag:news.perlfoundation.org,2026-06-06:/post/maintaining_perl_dave_mitchell_may_2026</id>
  <published>2026-06-06T16:06:50</published>
  <updated>2026-06-06T16:06:50</updated>
  <summary>
  <![CDATA[
     Dave writes: Last month I continued looking into race conditions in threads and threads::shared. I have now reached the point where the threads-related test suite can run cleanly under 'valgrind --tool=helgrind drd' and the threads-related tests can be repeatedly run in 40 terminals for days without issue. I've pushed the work as GH ##24439. Summary: 20:21 GH #24258 dist/threads/t/free.t: Rare test failure in debugging build on FreeBSD Total: 20:21 
   ]]>
  </summary>
  <author>
    <name>alh</name>
  </author>
  <category term="Grants" scheme="http://www.sixapart.com/ns/types#category"/>
  <category term="Perl 5 Development" scheme="http://www.sixapart.com/ns/types#category"/>  <content type="html" xml:lang="en-us" xml:base="http://news.perlfoundation.org/">
   <![CDATA[
     
       <img src="_ra-rel-mnt_/simplecas/fetch_content/7f97282811f6a9f862d7e659c79e5462cc195d94/grant-funding.png" style="max-width:100%;max-height:100%;padding:20px;" /><br>
     
     <p>Dave writes:</p>

<p>Last month I continued looking into race conditions in threads and
threads::shared. I have now reached the point where the threads-related
test suite can run cleanly under 'valgrind --tool=helgrind / drd' and the
threads-related tests can be repeatedly run in 40 terminals for days
without issue.</p>

<p>I've pushed the work as GH ##24439.</p>

<p>Summary:
*     20:21 GH #24258 dist/threads/t/free.t: Rare test failure in debugging build on FreeBSD</p>

<p>Total:
* 20:21 (HH:MM)</p>

    ]]>
  </content>
</entry>
  <entry>
    <title>Public Identifiers, UUIDs and a Tiny SEO Fix</title>
    <link rel="alternate" href="https://perlhacks.com/2026/06/public-identifiers-uuids-and-a-tiny-seo-fix/" type="text/html"/>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml"><h1>Public Identifiers, UUIDs and a Tiny SEO Fix</h1>
<p>A recent question from my friend and colleague Mohammad got me thinking about the way we identify data in web applications.</p>
<p>While working on the DBIC component of a REST API, he came across the term <em>enumeration attack</em>. In this type of attack, an attacker systematically guesses resource identifiers in order to access data they shouldn’t be able to see.</p>
<p>For example, if your API exposes URLs like this:</p><pre class="urvanov-syntax-highlighter-plain-tag">GET /users/123
GET /users/124
GET /users/125</pre><p>then it’s easy for someone to try a large range of identifiers and see what they get back.</p>
<p>Mohammad’s question was simple:</p>
<blockquote><p>Should we replace sequential IDs with UUIDs? And if we do, should we index the UUID column?</p></blockquote>
<p>As is often the case, the answer turned out to be “it depends”.</p>
<h2>Two Different Types of Data</h2>
<p>The first thing I realised is that not all data objects have the same requirements.</p>
<p>Some objects are naturally public.</p>
<p>For example, books on a publishing website are intended to be discovered. In fact, you probably want people to be able to guess their URLs:</p><pre class="urvanov-syntax-highlighter-plain-tag">/books/design-patterns-in-modern-perl</pre><p>In this case, a human-readable slug makes perfect sense. Other objects are private by nature. User accounts, orders, invoices and API resources generally shouldn’t be enumerable. In those cases, a UUID is often a better choice:</p><pre class="urvanov-syntax-highlighter-plain-tag">/users/550e8400-e29b-41d4-a716-446655440000</pre><p>The important observation is that slugs and UUIDs solve different problems.</p>
<ul>
<li>Slugs are for humans (and, perhaps, search engines).</li>
<li>UUIDs are for machines.</li>
</ul>
<h2>Database Design</h2>
<p>A common question is whether a UUID should replace the primary key.</p>
<p>In most cases, I don’t think it should.</p>
<p>My preferred design is:</p><pre class="urvanov-syntax-highlighter-plain-tag">CREATE TABLE users (
  id BIGINT PRIMARY KEY,
  uuid UUID NOT NULL UNIQUE
);</pre><p>The integer primary key remains the internal identifier used for joins and foreign keys.</p>
<p>The UUID becomes the public identifier exposed through APIs.</p>
<p>This gives you the best of both worlds:</p>
<ul>
<li>Small, efficient foreign keys.</li>
<li>Fast joins.</li>
<li>Unguessable public identifiers.</li>
</ul>
<p>If the application regularly searches by UUID then the UUID column should be indexed. In practice, declaring it <code inline="">UNIQUE</code> will usually create the appropriate index automatically.</p>
<h2>The Hybrid Approach</h2>
<p>Thinking about this reminded me that many large sites use a hybrid approach.</p>
<p>Amazon product URLs contain both a human-readable title and a stable identifier:</p><pre class="urvanov-syntax-highlighter-plain-tag">/Design-Patterns-Modern-Perl/dp/B0XXXXX123</pre><p>The ASIN is what really identifies the product.</p>
<p>The title is there for humans.</p>
<p>Stack Overflow does something similar:</p><pre class="urvanov-syntax-highlighter-plain-tag">/questions/12345/how-do-i-index-a-uuid-column</pre><p>Again, the question ID is authoritative. The title is helpful context.</p>
<p>My Line of Succession website uses the same idea.</p>
<p>A person page looks like this:</p><pre class="urvanov-syntax-highlighter-plain-tag">/p/2b5998-the-prince-william-prince-of-wales</pre><p>The important part is the identifier:</p><pre class="urvanov-syntax-highlighter-plain-tag">2b5998</pre><p>The rest is descriptive text.</p>
<p>This turns out to be particularly useful for royalty because titles change constantly. Someone might be “Prince William”, then “The Prince of Wales”, and eventually “King William V”.</p>
<p>By separating identity from presentation, old links continue to work regardless of title changes.</p>
<h2>A Tiny Bug</h2>
<p>While thinking about all of this, I discovered a small bug in Line of Succession.</p>
<p>The site allows any descriptive text after the identifier. These URLs all resolve to the same person:</p><pre class="urvanov-syntax-highlighter-plain-tag">/p/2b5998-the-prince-william-prince-of-wales
/p/2b5998-prince-billy
/p/2b5998-fred</pre><p>The application correctly ignores the descriptive text and uses only the identifier.</p>
<p>However, there was a problem.</p>
<p>The page was generating its canonical URL from the incoming request path rather than from the person record.</p>
<p>That meant a request for:</p><pre class="urvanov-syntax-highlighter-plain-tag">/p/2b5998-prince-billy</pre><p>generated:</p><pre class="urvanov-syntax-highlighter-plain-tag">&lt;link rel="canonical"
      href="https://lineofsuccession.co.uk/p/2b5998-prince-billy"&gt;</pre><p>which is obviously not the canonical URL.</p>
<p>The fix was surprisingly small:</p><pre class="urvanov-syntax-highlighter-plain-tag">sub canonical( $self ) {
   if ($self-&gt;request-&gt;is_date_page) {
     return '/' . $self-&gt;canonical_date;
+  } elsif($self-&gt;request-&gt;is_person_page) {
+    return '/p/' . $self-&gt;request-&gt;person-&gt;slug;
   } else {
     return $self-&gt;request-&gt;path;
   }
 }</pre><p>At the same time I simplified another method by making it reuse the canonical URL logic.</p>
<p>The result was a six-line patch that fixed the SEO issue and made the code slightly cleaner.</p>
<p>Those are my favourite kinds of fixes.</p>
<h2>Future Improvements</h2>
<p>The fix also revealed an emerging abstraction in the code.</p>
<p>At the moment, various parts of the application know how to construct URLs for different object types.</p>
<p>A cleaner approach would be to give objects responsibility for generating their own URLs.</p>
<p>I’m considering a <code inline="">HasURL</code> role that would require an object to provide an identifier and optionally a prefix, and then build the URL automatically.</p>
<p>That’s a job for another day.</p>
<p>For now, a small question about UUIDs led to a useful discussion about public identifiers, a review of URL design, and a tiny production fix. Not bad for an afternoon’s work.</p><p>The post <a href="https://perlhacks.com/2026/06/public-identifiers-uuids-and-a-tiny-seo-fix/">Public Identifiers, UUIDs and a Tiny SEO Fix</a> first appeared on <a href="https://perlhacks.com">Perl Hacks</a>.</p></div>
    </content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml"><p>Public Identifiers, UUIDs and a Tiny SEO Fix A recent question from my friend and colleague Mohammad got me thinking about the way we identify data in web applications. While working on the DBIC component of a REST API, he came across the term enumeration attack. In this type of attack, an attacker systematically guesses […]</p>
<p>The post <a href="https://perlhacks.com/2026/06/public-identifiers-uuids-and-a-tiny-seo-fix/">Public Identifiers, UUIDs and a Tiny SEO Fix</a> first appeared on <a href="https://perlhacks.com">Perl Hacks</a>.</p></div>
    </summary>
    <author>
      <name>Dave Cross</name>
    </author>
    <id>https://perlhacks.com/?p=2452</id>
    <published>2026-06-06T14:29:38Z</published>
    <updated>2026-06-06T14:29:38Z</updated>
    <category term="Programming"/>
    <category term="Database Design"/>
    <category term="line of succession"/>
    <category term="perl"/>
    <category term="seo"/>
    <category term="Software Architecture"/>
    <category term="URL Design"/>
    <category term="web development"/>
  </entry>
  <entry xmlns:re="http://purl.org/atompub/rank/1.0">
        <id>https://stackoverflow.com/q/79951585</id>
        <re:rank scheme="https://stackoverflow.com">3</re:rank>
        <title type="text">Output all the paragraphs that match</title>
            <category scheme="https://stackoverflow.com/tags" term="regex"/>
            <category scheme="https://stackoverflow.com/tags" term="perl"/>
            <category scheme="https://stackoverflow.com/tags" term="multiline"/>
        <author>
            <name>Signor Pizza</name>
            <uri>https://stackoverflow.com/users/22133250</uri>
        </author>
        <link rel="alternate" href="https://stackoverflow.com/questions/79951585/output-all-the-paragraphs-that-match"/>
        <published>2026-06-04T20:29:14Z</published>
        <updated>2026-06-06T13:22:42Z</updated>
        <summary type="html">
            &lt;p&gt;The regex itself is &lt;a href="https://regex101.com/?regex=%28%5E%5CS.*%24%5Cn%29%2B%5Efont%5C.size+%3D+12%5C.0%24%28%5Cn%5E%5CS.*%24%29%2B&amp;amp;testString=%23+bbox.tolerance+%3D+1e-5%0A%0A%5B%5Bheading%5D%5D%0A%23+Complex+Plane%0Alevel+%3D+1%0Agreedy+%3D+true%0Afont.name+%3D+%22CoFoRobert-Medium%22%0Afont.size+%3D+12.0%0A%23+font.size_tolerance+%3D+1e-5%0A%23+font.color+%3D+0x333333%0A%23+font.superscript+%3D+false%0A%23+font.italic+%3D+false%0A%23+font.serif+%3D+true%0A%23+font.monospace+%3D+false%0A%23+font.bold+%3D+false%0A%23+bbox.left+%3D+128.5%0A%23+bbox.top+%3D+358.7200012207031%0A%23+bbox.right+%3D+208.11978149414062%0A%23+bbox.bottom+%3D+373.52801513671875%0A%23+bbox.tolerance+%3D+1e-5%0A%0A%5B%5Bheading%5D%5D&amp;amp;flags=gm&amp;amp;flavor=pcre2&amp;amp;delimiter=%2F" rel="nofollow noreferrer"&gt;functional&lt;/a&gt; (it matches the paragraph it finds &lt;code&gt;^font\.size = 12\.0$&lt;/code&gt; line in), but I can't figure out how to get a suitable perl command to reproduce the result.&lt;/p&gt;
&lt;p&gt;I am currently running&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;perl -lne 'BEGIN{undef $/;} print while /(^\S.*\n)+^font\.size = 12\.0(\n^\S.*)+/gm' teststring.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but it's just printing out the entire file.  How can I get Perl to behave like Regex101?&lt;/p&gt;
&lt;h1&gt;Regex&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;/(^\S.*$\n)+^font\.size = 12\.0$(\n^\S.*$)+/gm
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;teststring.txt&lt;/h1&gt;
&lt;pre class="lang-none prettyprint-override"&gt;&lt;code&gt;# bbox.tolerance = 1e-5

[[heading]]
# Complex Plane
level = 1
greedy = true
font.name = &amp;quot;CoFoRobert-Medium&amp;quot;
font.size = 12.0
# font.size_tolerance = 1e-5
# font.color = 0x333333
# font.superscript = false
# font.italic = false
# font.serif = true
# font.monospace = false
# font.bold = false
# bbox.left = 128.5
# bbox.top = 358.7200012207031
# bbox.right = 208.11978149414062
# bbox.bottom = 373.52801513671875
# bbox.tolerance = 1e-5

[[heading]]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Expected output:&lt;/p&gt;
&lt;pre class="lang-none prettyprint-override"&gt;&lt;code&gt;[[heading]]
# Complex Plane
level = 1
greedy = true
font.name = &amp;quot;CoFoRobert-Medium&amp;quot;
font.size = 12.0
# font.size_tolerance = 1e-5
# font.color = 0x333333
# font.superscript = false
# font.italic = false
# font.serif = true
# font.monospace = false
# font.bold = false
# bbox.left = 128.5
# bbox.top = 358.7200012207031
# bbox.right = 208.11978149414062
# bbox.bottom = 373.52801513671875
# bbox.tolerance = 1e-5
&lt;/code&gt;&lt;/pre&gt;

        </summary>
    </entry>
  <entry>
    <title>DBIx::Class and GraphQL | Jun 2026 | The Weekly Challenge</title>
    <link rel="alternate" href="https://theweeklychallenge.org/blog/dbic-graphql/" type="text/html"/>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">Two days ago, I wrote a blog post titled, Mojo meets GraphQL. It was my first time using GraphQL and it was mostly well received.</div>
    </content>
    <id>https://theweeklychallenge.org/blog/dbic-graphql/</id>
    <published>2026-06-06T00:00:00Z</published>
    <updated>2026-06-06T00:00:00Z</updated>
  </entry>
  <entry xmlns:media="http://search.yahoo.com/mrss/">
    <id>tag:github.com,2008:Grit::Commit/8e50dbf32b80ca84a9d4d8c9d63010c54aa73018</id>
    <link type="text/html" rel="alternate" href="https://github.com/Perl/perl5/commit/8e50dbf32b80ca84a9d4d8c9d63010c54aa73018"/>
    <title>
        Storable: fix bugtracker metadata
    </title>
    <updated>2026-06-05T16:12:55Z</updated>
    <media:thumbnail height="30" width="30" url="https://avatars.githubusercontent.com/u/50029?s=30&amp;v=4"/>
    <author>
      <name>haarg</name>
      <uri>https://github.com/haarg</uri>
    </author>
    <content type="html">
      &lt;pre style='white-space:pre-wrap;width:81ex'&gt;Storable: fix bugtracker metadata&lt;/pre&gt;
    </content>
  </entry>
  <entry xmlns:re="http://purl.org/atompub/rank/1.0">
        <id>https://stackoverflow.com/q/79951531</id>
        <re:rank scheme="https://stackoverflow.com">0</re:rank>
        <title type="text">How can I take the bitwise NOT of a variable?</title>
            <category scheme="https://stackoverflow.com/tags" term="perl"/>
        <author>
            <name>sam_</name>
            <uri>https://stackoverflow.com/users/32797948</uri>
        </author>
        <link rel="alternate" href="https://stackoverflow.com/questions/79951531/how-can-i-take-the-bitwise-not-of-a-variable"/>
        <published>2026-06-04T18:00:45Z</published>
        <updated>2026-06-05T09:42:31Z</updated>
        <summary type="html">
            &lt;p&gt;I am making a calculator and want to make it get the bitwise NOT as a function.  How could I do that?&lt;/p&gt;
&lt;p&gt;Here's the code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;my $val1 = &amp;lt;STDIN&amp;gt;;

print ~$val1, &amp;quot;\n&amp;quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If I enter &lt;code&gt;5&lt;/code&gt;, it produces &amp;quot;��&amp;quot;.&lt;/p&gt;

        </summary>
    </entry>
  <entry>
    <title>PWC 376 Doubled Words</title>
    <link rel="alternate" href="https://dev.to/boblied/pwc-376-doubled-words-7g3" type="text/html"/>
    <content type="html">&lt;p&gt;There are two things that every Perl developer knows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Parsing HTML with regular expressions is a bad idea.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;My&lt;/em&gt; situation is unique and exceptional, such that parsing HTML with regular expressions is ingenious and optimal.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's see the task. I think you know where this is going.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-376/#TASK2" rel="noopener noreferrer"&gt;Task 2: Double Words&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;You are given a string (which may contain embedded newlines) which is taken from a page on a website. The string will not contain brackets &lt;code&gt;[]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Write a script that will find doubled words (such as “this this”) and highlight (wrap in brackets) each doubled word.&lt;/p&gt;

&lt;p&gt;The script should:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Work across lines, even finding situations where a word at the end of one line is repeated at the beginning of the next.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Find doubled words despite capitalization differences, such as with 'The the...', as well as allow differing amounts of whitespace (spaces, tabs, newlines, and the like) to lie between the words.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Find doubled words even when separated by HTML tags. For example, to make a word bold: '...it is &amp;lt;B&amp;gt;very&amp;lt;/B&amp;gt; very important...'.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Only show lines containing doubled words.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Adapted from &lt;a href="https://regex.info/book.html" rel="noopener noreferrer"&gt;&lt;em&gt;Mastering Regular Expressions&lt;/em&gt;, Third Edition, by Jeffrey E. F. Friedl&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Example 1&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Input:&lt;/em&gt; &lt;code&gt;$str = "you're given the job of checking the pages on a\nweb server for doubled words (such as 'this this'), a common problem\nwith documents subject to heavy editing."&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Output:&lt;/em&gt; &lt;code&gt;"web server for doubled words (such as '[this] [this]'), a common problem"&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Example 2&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Input:&lt;/em&gt; &lt;code&gt;$str = "Find doubled words despite capitalization differences, such as with 'The\nthe...', as well as allow differing amounts of whitespace (spaces,\ntabs, newlines, and the like) to lie between the words."&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Output:&lt;/em&gt; &lt;code&gt;"Find doubled words despite capitalization differences, such as with '[The]\n[the]...', as well as allow differing amounts of whitespace (spaces,"&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Example 3&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Input:&lt;/em&gt; &lt;code&gt;$str = "to make a word bold: '...it is &amp;lt;B&amp;gt;very&amp;lt;/B&amp;gt; very important...'."&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Output:&lt;/em&gt; &lt;code&gt;"to make a word bold: '...it is &amp;lt;B&amp;gt;[very]&amp;lt;/B&amp;gt; [very] important...'."&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Example 4&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Input:&lt;/em&gt; &lt;code&gt;$str = "Perl officially stands for Practical Extraction and Report Language, except when it doesn't."&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Output:&lt;/em&gt; &lt;code&gt;""&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Example 5&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Input:&lt;/em&gt; &lt;code&gt;$str = "There's more than one one way to do it.\nEasy things should be easy and hard things should be possible."&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Output:&lt;/em&gt; &lt;code&gt;"There's more than [one] [one] way to do it."&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  So it begins
&lt;/h2&gt;

&lt;p&gt;The reference to &lt;em&gt;Mastering Regular Expressions&lt;/em&gt; seems like a pretty strong hint. Back when I was doing HTML and XML processing, I always favored using a module to parse tagged text (&lt;a href="https://metacpan.org/dist/XML-Twig" rel="noopener noreferrer"&gt;&lt;code&gt;XML::Twig&lt;/code&gt;&lt;/a&gt; was a particular favorite), but let's take the hint.&lt;/p&gt;

&lt;p&gt;A sort of obvious thing to do here is to split the string into words, but it's going to be annoying because of the possibility of HTML tags.  And once we break the string up, we'll lose the space and tags that we need to retain for the requested output.&lt;/p&gt;

&lt;p&gt;"The string will not contain brackets" is an odd thing to say. But it turns out to be useful, because we only want to print output lines that &lt;em&gt;do&lt;/em&gt; contain brackets, so this little clause is actually doing us a favor.&lt;/p&gt;

&lt;h2&gt;
  
  
  An outline
&lt;/h2&gt;

&lt;p&gt;Let's assume that we can conjure up a regular expression to use with &lt;code&gt;split&lt;/code&gt; to extract the words; let's call it &lt;code&gt;$sepRE&lt;/code&gt;. We can then compare consecutive pairs of words to find duplication. That solves half the problem, but loses the context in the original string. We need to reproduce the original text, plus highlighting brackets, including all the stuff between words.&lt;/p&gt;

&lt;p&gt;Because we have weird habits, we have (more than once) read through all the documentation of &lt;code&gt;split&lt;/code&gt;, and so we know that there is a variation in which the function can return both the desired substrings &lt;em&gt;and&lt;/em&gt; the separators. To wit, if we enclose the regular expression in parentheses, &lt;code&gt;split&lt;/code&gt; will return all the pieces of the string, alternating between separators and substrings. The first piece we need looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@word&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="sr"&gt;/($sepRE)/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$str&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the words will be in either the even or odd elements of &lt;code&gt;@word&lt;/code&gt;, depending on whether the string started with a separator. We can check for duplicates by skipping along in pairs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Take every other word. Skip over a leading separator.&lt;/span&gt;
&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$word&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;m/$sepRE/&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
                     &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$second&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nv"&gt;$#word&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$word&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$first&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nv"&gt;$word&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$second&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$w&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;eq&lt;/span&gt; &lt;span class="nv"&gt;$w&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$word&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$first&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;s/($w[0])/[$1]/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$word&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$second&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;s/($w[1])/[$1]/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nv"&gt;$first&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;$second&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That marks up the duplicate words, but only in the &lt;code&gt;@word&lt;/code&gt; array. We need to face the problem of getting the desired output. To get there, put the &lt;code&gt;@word&lt;/code&gt; array back into a single string, and then &lt;code&gt;grep&lt;/code&gt; for the lines that contain our newly-inserted brackets.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Reassemble the string, now with some words possibly bracketed&lt;/span&gt;
&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$highlighted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;join&lt;/span&gt;&lt;span class="p"&gt;("",&lt;/span&gt; &lt;span class="nv"&gt;@word&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;# Output includes only lines where we inserted brackets&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;join&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;",&lt;/span&gt;
            &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="sr"&gt;/[\[\]]/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                 &lt;span class="nb"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/\n/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$highlighted&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A few minor details
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Case insensitivity. In our check for duplicates, we need to ignore case differences, so let's compare the lowercase versions of the words: &lt;code&gt;if ( lc($w[0]) eq lc($w[1]) )&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Punctuation. As shown in Example 2, punctuation surrounding the words should be ignored. Let's whip up a quick function to trim leading and trailing punctuation (the &lt;code&gt;[:punct:]&lt;/code&gt; character class is handy for this), and use it before we compare&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;trimPunct&lt;/span&gt;&lt;span class="err"&gt;($&lt;/span&gt;&lt;span class="nf"&gt;word&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$word&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;s/^[[:punct:]]+//&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nv"&gt;$word&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;s/[[:punct:]]+$//&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$word&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;trimPunct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$word&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$first&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
            &lt;span class="nv"&gt;trimPunct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$word&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$second&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  About that regular expression
&lt;/h2&gt;

&lt;p&gt;Time to take care of that regular expression that acts as the word separator. With some experimentation (the &lt;a href="https://regex101.com" rel="noopener noreferrer"&gt;regex101&lt;/a&gt; web site is good for that), we arrived at this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt; &lt;span class="nv"&gt;state&lt;/span&gt; &lt;span class="nv"&gt;$sepRE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
&lt;span class="sx"&gt;qr/ \s*     # Possible white space followed by
  (?:       # ( a group of a tag and more white space
   &amp;lt;[^&amp;gt;]*&amp;gt;  #  ... an HTML tag
   \s*      #  ... optional space
  )+        # ) there can be multiple tags
  | \s+     # Or just white space
/&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not too bad. Didn't even require look-around assertions.  Some notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;state $sepRE = qr/.../&lt;/code&gt; -- This is a constant regular expression, so we can use &lt;code&gt;state&lt;/code&gt; to only evaluate it once.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;qr//x&lt;/code&gt; -- The &lt;code&gt;x&lt;/code&gt; flag allows us to add formatting and comments to the expression &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;(?:...)&lt;/code&gt; -- We want to group, but we don't need the overhead of capturing, so &lt;code&gt;(?:)&lt;/code&gt; is a non-capturing group.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;complicated | \s+&lt;/code&gt; -- Why is the complicated part first? Because the alternatives are evaluated left to right. If &lt;code&gt;\s+&lt;/code&gt; eats up the white space, the expression matches and wouldn't proceed to trying tags.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Okay, here's the &lt;a href="https://github.com/boblied/perlweeklychallenge-club/blob/master/challenge-376/bob-lied/perl/ch-2.pl" rel="noopener noreferrer"&gt;whole thing&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;task&lt;/span&gt;&lt;span class="err"&gt;($&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;state&lt;/span&gt; &lt;span class="nv"&gt;$sepRE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sx"&gt;qr/ \s*     # Possible white space followed by
                     (?:       # ( a group of a tag and more white space
                      &amp;lt;[^&amp;gt;]*&amp;gt;  #  ... an HTML tag
                      \s*      #  ... optional space
                     )+        # ) There can be multiple tags
                     | \s+     # Or just white space
                   /&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;# Using () in RE includes separators in the array&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@word&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="sr"&gt;/($sepRE)/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$str&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;# Take every other word. Skip over a leading separator.&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$word&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;m/$sepRE/&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$second&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nv"&gt;$#word&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;trimPunct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$word&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$first&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="nv"&gt;trimPunct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$word&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$second&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;lc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$w&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="ow"&gt;eq&lt;/span&gt; &lt;span class="nb"&gt;lc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$w&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$word&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$first&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;s/($w[0])/[$1]/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nv"&gt;$word&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$second&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;s/($w[1])/[$1]/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nv"&gt;$first&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;$second&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;# Reassemble the string, now with some words possibly bracketed&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$highlighted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;join&lt;/span&gt;&lt;span class="p"&gt;("",&lt;/span&gt; &lt;span class="nv"&gt;@word&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;# Output includes only lines where we inserted brackets&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;join&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;",&lt;/span&gt; &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="sr"&gt;/[\[\]]/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/\n/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$highlighted&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the music for this week's challenge was &lt;a href="https://www.youtube.com/watch?v=dD-SpHH7qDA" rel="noopener noreferrer"&gt;Double Vision&lt;/a&gt; by Foreigner.&lt;/p&gt;

</content>
    <author>
      <name>Bob Lied</name>
    </author>
    <id>https://dev.to/boblied/pwc-376-doubled-words-7g3</id>
    <published>2026-06-04T14:18:08Z</published>
    <updated>2026-06-04T14:18:08Z</updated>
    <category term="perl"/>
    <category term="perlweeklychallenge"/>
    <category term="pwc"/>
  </entry>
  <entry xmlns:media="http://search.yahoo.com/mrss/">
    <id>tag:github.com,2008:Grit::Commit/04ac2edde8bd88a72f6d3ebbd973529d194ccf5d</id>
    <link type="text/html" rel="alternate" href="https://github.com/Perl/perl5/commit/04ac2edde8bd88a72f6d3ebbd973529d194ccf5d"/>
    <title>
        RMG: separate email preparation from version bump
    </title>
    <updated>2026-06-03T06:21:38Z</updated>
    <media:thumbnail height="30" width="30" url="https://avatars.githubusercontent.com/u/44421?s=30&amp;v=4"/>
    <author>
      <name>book</name>
      <uri>https://github.com/book</uri>
    </author>
    <content type="html">
      &lt;pre style='white-space:pre-wrap;width:81ex'&gt;RMG: separate email preparation from version bump

- make the perlpolicy update more prominent by adding a specific section
  header
- clarify the PERL_API constants instructions and make them release-specific
- move the end-of-support email instructions to the email section

Co-authored-by: Eric Herman &amp;lt;eric@freesa.org&amp;gt;&lt;/pre&gt;
    </content>
  </entry>
  <entry>
    <title>Question: How does Debian solve converging configuration files?</title>
    <link rel="alternate" href="https://wesley.schwengle.net/answerrit/question-how-does-debian-solve-converging-configuration-files-2013/" type="text/html"/>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml"><p>Someone on Reddit asked how you can maintain your own version of application
while also being able to upgrade packages without getting conflicts between
your changes and Debians changes.</p>
<h2 id="answer">Answer</h2>
<p>This is normal in Debian life. Debian often solves this via three ways.</p>
<ol>
<li>.d config directories.</li>
<li>Ordering</li>
<li>dpkg-divert</li>
</ol>
<p>Sudo, apache, nginx, and lightdm, all support the first way. Some packages like
<code>unattended-upgrades</code> use the 2nd way, ordering and some like <code>minidnla</code> only
allow for the third way.
LightDM might be a bit different, it follows order twice.</p></div>
    </content>
    <id>https://wesley.schwengle.net/answerrit/question-how-does-debian-solve-converging-configuration-files-2013/</id>
    <published>2026-06-02T20:23:46-04:00</published>
    <updated>2026-06-02T20:23:46-04:00</updated>
  </entry>
  <entry>
    <title>The Day I Decided Never to Learn Python</title>
    <link rel="alternate" href="https://medium.com/@realmerlyn/the-day-i-decided-never-to-learn-python-2c59d1a1edc5?source=rss------perl-5" type="text/html"/>
    <content type="html">&lt;div class="medium-feed-item"&gt;&lt;p class="medium-feed-image"&gt;&lt;a href="https://medium.com/@realmerlyn/the-day-i-decided-never-to-learn-python-2c59d1a1edc5?source=rss------perl-5"&gt;&lt;img src="https://cdn-images-1.medium.com/max/636/1*mP6HlAQahZet7OYJBUq2OQ.png" width="636"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p class="medium-feed-snippet"&gt;(A quick disclaimer before we begin: this session took place nearly 30 years ago. While the core structural concepts and my definitive&amp;#x2026;&lt;/p&gt;&lt;p class="medium-feed-link"&gt;&lt;a href="https://medium.com/@realmerlyn/the-day-i-decided-never-to-learn-python-2c59d1a1edc5?source=rss------perl-5"&gt;Continue reading on Medium »&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;</content>
    <author>
      <name>Randal L. Schwartz</name>
    </author>
    <id>https://medium.com/p/2c59d1a1edc5</id>
    <published>2026-06-02T16:37:50Z</published>
    <updated>2026-06-02T20:48:17.036000Z</updated>
    <category term="object-oriented"/>
    <category term="python"/>
    <category term="perl"/>
    <category term="guido-van-rossum"/>
  </entry>
  <entry>
    <title>This week in PSC (227) | 2026-06-01</title>
    <link rel="alternate" href="https://blogs.perl.org/users/psc/2026/06/this-week-in-psc-227-2026-06-01.html"/>
    <id>tag:blogs.perl.org,2026:/users/psc//4112.12064</id>
    <published>2026-06-01T22:10:41Z</published>
    <updated>2026-06-01T22:13:51Z</updated>
    <author>
        <name>Perl Steering Council</name>
        
    </author>
    <content type="html" xml:lang="en" xml:base="https://blogs.perl.org/users/psc/">
        <![CDATA[<p>This week we were back to full strength. We have now dealt with all of the belated issues and all of the blockers. Paul will be shipping 5.43.11 very shortly. With the amount of changes we have had to merge, we will not be able to rush the .11 cycle, but we intend to start the work on the 5.44 RC early, to ensure that we can release with as little additional delay as possible.</p>

<p>[<a href="https://www.nntp.perl.org/group/perl.perl5.porters/;msgid=ah29lbShglGM6XRG@klangraum.plasmasturm.org">P5P posting of this summary</a>]</p>
]]>
        

    </content>
</entry>
  <entry>
    <title>Perl 🐪 Weekly #775 - Events and using AI to write Perl</title>
    <link rel="alternate" href="https://dev.to/szabgab/perl-weekly-775-events-and-using-ai-to-write-perl-59pm" type="text/html"/>
    <content type="html">&lt;p&gt;Originally published at &lt;a href="https://perlweekly.com/archive/775.html" rel="noopener noreferrer"&gt;Perl Weekly 775&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hi there!&lt;/p&gt;

&lt;p&gt;I try to keep track of the Perl-related events. You can find them listed at the bottom of each edition of the newsletter and on the &lt;a href="https://perlweekly.com/events" rel="noopener noreferrer"&gt;events page&lt;/a&gt; on the Perl Weekly web site. There you can also find a link to embed the calendar in your calendar program. There are a number of events scheduled for this month. Most of them online, so if your time-zone permits, you can join those events. The big in-person event is at the end of the month &lt;a href="https://news.perlfoundation.org/post/tprc-schedule-and-lightning-talks" rel="noopener noreferrer"&gt;The Perl and Raku Conference&lt;/a&gt; in Greenville, South Carolina, USA.&lt;/p&gt;

&lt;p&gt;In the last couple of weeks I have been using various AI tools extensively. It still needs some hand-holding, but it already writes code that seems to be way better than the average code I've seen. So I wonder, would it be possible to ask one of the AI tools to convert Python libraries to Perl? You know, we have been complaining for many years that companies provide implementation for their SDK/API/client in several language, but not in Perl. We also saw that CPAN could not keep up with the growth of PyPI, npm and the other 3rd party library registries. So maybe some of you would like to explore the idea of converting some of these libraries to Perl using AI.&lt;/p&gt;

&lt;p&gt;Finally a personal note, I am planning a trip to Korea and Japan in September-October. If you live there and would have any travel recommendations, I'd love to get that.&lt;/p&gt;

&lt;p&gt;Enjoy your week!&lt;/p&gt;

&lt;p&gt;--&lt;br&gt;
  Your editor: Gabor Szabo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Articles
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://blogs.perl.org/users/toby_inkster/2026/05/introducing-zuzuscript.html" rel="noopener noreferrer"&gt;Introducing ZuzuScript&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Toby Inkster created a programming language which blends a fairly JavaScript-like syntax with fairly Perl-like semantics, and a few other features that he hasn't really seen in many programming languages.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://blogs.perl.org/users/ron_savage/2026/05/announce-perlwiki-v-147-jstree-copy-v-121.html" rel="noopener noreferrer"&gt;ANNOUNCE: Perl.Wiki V 1.47, JSTree copy V 1.21&lt;/a&gt;
&lt;/h3&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://perlhacks.com/2026/05/teaching-ai-about-the-british-monarchy-with-mcp/" rel="noopener noreferrer"&gt;Teaching AI About the British Monarchy with MCP&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The site already exposes information through a traditional web interface and a JSON API. But those interfaces were designed for humans and developers respectively. MCP gives AI systems a much cleaner integration point.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://blogs.perl.org/users/ron_savage/2026/05/announce-perlwiki-v-146-other-news.html" rel="noopener noreferrer"&gt;ANNOUNCE: Perl.Wiki V 1.46 &amp;amp; other news&lt;/a&gt;
&lt;/h3&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://news.perlfoundation.org/post/tprc-schedule-and-lightning-talks" rel="noopener noreferrer"&gt;TPRC Schedule Posted - Time to Submit Lightning Talks&lt;/a&gt;
&lt;/h3&gt;




&lt;h2&gt;
  
  
  Discussion
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.reddit.com/r/perl/comments/1tolezs/distzillapluginbundlestarter_use_readmebrief/" rel="noopener noreferrer"&gt;Dist::Zilla::PluginBundle::Starter: Use Readme::Brief instead of Pod2Readme? &lt;/a&gt;
&lt;/h3&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.reddit.com/r/perl/comments/1tnv9zj/perl_eval_question/" rel="noopener noreferrer"&gt;Perl eval question&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Oh, the evil eval.&lt;/p&gt;




&lt;h2&gt;
  
  
  Perl
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://blogs.perl.org/users/psc/2026/05/this-week-in-psc-226-2026-05-25.html" rel="noopener noreferrer"&gt;This week in PSC (226) | 2026-05-25&lt;/a&gt;
&lt;/h3&gt;




&lt;h2&gt;
  
  
  The Weekly Challenge
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://theweeklychallenge.org" rel="noopener noreferrer"&gt;The Weekly Challenge&lt;/a&gt; by &lt;a href="https://manwar.org" rel="noopener noreferrer"&gt;Mohammad Sajid Anwar&lt;/a&gt; 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 Marc Perry.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-376" rel="noopener noreferrer"&gt;The Weekly Challenge - 376&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Welcome to a new week with a couple of fun tasks "Chessboard Squares" and "Doubled Words". If you are new to the weekly challenge then why not join us and have fun every week. For more information, please read the &lt;a href="https://theweeklychallenge.org/faq" rel="noopener noreferrer"&gt;FAQ&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://theweeklychallenge.org/blog/recap-challenge-375" rel="noopener noreferrer"&gt;RECAP - The Weekly Challenge - 375&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Enjoy a quick recap of last week's contributions by Team PWC dealing with the "Single Common Word" and "Find K-Beauty" tasks in Perl and Raku. You will find plenty of solutions to keep you busy.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://raku-musings.com/common-beauty.html" rel="noopener noreferrer"&gt;Common Beauty&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;This is an excellent example of how to use Raku's idiomatic style to perform frequency analysis with a very elegant way of using Bag data type and to make use of the %% operator for nice clean checks of divisibility by using Raku's built in primitives instead of having to write complex manual logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.braincells.com/perl/2026/05/perl_weekly_challenge_week_375.html" rel="noopener noreferrer"&gt;Perl Weekly Challenge: Week 375&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;It provides an excellent, straightforward exhibition on how to solve the problems associated with Weekly Challenge 375 in Raku and Perl. In addition to showing off some of the more sophisticated, expressive data types that Raku supports (i.e., Bag) Jaldhar shows how they were able to implement clever, easy-to-read workarounds in Perl to accomplish essentially the same thing.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.sommrey.de/the-bears-den/2026/05/29/ch-375.html" rel="noopener noreferrer"&gt;Common Beauty&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;This blog post does a great job of examining and comparing the practical solutions using Perl and an advanced version of programming with the J language. The way Jorg has generalised the different types of problems he presented creates a sophisticated solution for someone that will accept any number of bases and/or arrays as inputs, and produces results that would be considered to be of a high standard.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://wlmb.github.io/2026/05/26/PWC375/" rel="noopener noreferrer"&gt;Perl Weekly Challenge 375&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;This post shows a clear-cut way to address a problem and demonstrate a solid grasp of Perl's function-based capabilities. It uses expressive one-line Perl statements to demonstrate how small, readable, and consistent code can be written to transform data.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/MatthiasMuth/perlweeklychallenge-club/tree/muthm-375/challenge-375/matthias-muth#readme" rel="noopener noreferrer"&gt;A Single Beauty&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;This is an exemplary work featuring high-quality code that has a high degree of maintainability, uses excellent error check techniques and provides high levels of readability. In addition to using excellent reading technique, his solutions include well-documented logic and complete test suites.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://packy.dardan.com/b/qf" rel="noopener noreferrer"&gt;You’ve got to get up every morning…&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Packy has created an outstanding multi-language deep dive post comparing different implementations of Raku, Perl, Python, and Elixir. In addition to providing many details about each language's implementation, his approach is to focus on making it easy to read and easy to follow the logic behind each one in spite of their technical complexities. He shows us how we can take the same data structure using different paradigms to create different implementation solutions for the same problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="http://ccgi.campbellsmiths.force9.co.uk/challenge/375" rel="noopener noreferrer"&gt;Single and beautiful&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;This solution exemplifies how effective algorithms can be designed, using math formulas as a way of running multiple sets of frequencies over a single array. It’s an example of a very concise method of solving complex state-tracking issues, using the least amount of code as possible while maintaining a high degree of readability.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://reiniermaliepaard.nl/pwc/index.php?id=pwc375-1" rel="noopener noreferrer"&gt;The Weekly Challenge - 375: Single Common Word&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;A clear and systematically organised method for resolving this issue is provided within this post, as well as a very easy to read content style, making it simple to see the reasoning behind the solution. Among other things, this post displays a good presentation of example test cases and has a good way of providing technical explanations to both new to experienced software programmers alike.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://reiniermaliepaard.nl/pwc/index.php?id=pwc375-2" rel="noopener noreferrer"&gt;The Weekly Challenge - 375: Find K-Beauty&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;This blog post exemplifies well-designed code that solves the "Find K-Beauty" problem in a strong manner. Reinier does an excellent job of providing clear, modular logic and using the least amount of code to implement those solutions. This allows the reader to see how the sliding window method works to find divisors in the number's format.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://hatley-software.blogspot.com/2026/05/robbie-hatleys-solutions-in-perl-for_01906093295.html" rel="noopener noreferrer"&gt;The Weekly Challenge #375&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;This post presents an incredibly complete and conversational analysis of the obstacles, illustrated with sophisticated technical knowledge through a thoroughly well-organised, educational format. Robbie's skill at blending solid, production-level Perl code with detailed explanation of the rationale behind it provides readers with an excellent foundation for either becoming familiarized with this form of problem solving or gaining greater depth of understanding regarding the "how" and "why" of idiomatic Perl.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://blog.firedrake.org/archive/2026/05/The_Weekly_Challenge_375__Uncommon_Beauty.html" rel="noopener noreferrer"&gt;Uncommon Beauty&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Roger produced a very thorough, well-organised explanation of the problem, using techniques such as hash frequencies and sliding windows to create solutions that are both clean and accurate. By comparing the two different languages Perl and Scala, Roger shows that they clearly understand how to approach solving problems using multiple programming languages.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://dev.to/simongreennet/the-weekly-challenge-the-common-beauty-5eh3"&gt;The Common Beauty&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;This is an excellent example of a bilingual coding approach. It contrasts high-level data structures in Python with Perl's more flexible but lower-level data manipulation. Simon offers a clear explanation of the two different languages used to explain how one would move algorithmic logic from one programming paradigm to another by providing step-by-step instructions and side-by-side examples.&lt;/p&gt;




&lt;h2&gt;
  
  
  Videos
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.youtube.com/watch?v=g_f1LVmNNuY" rel="noopener noreferrer"&gt;JSON Schema at the Toronto Perl Mongers&lt;/a&gt;
&lt;/h3&gt;




&lt;h2&gt;
  
  
  Weekly collections
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="http://niceperl.blogspot.com/" rel="noopener noreferrer"&gt;NICEPERL's lists&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://niceperl.blogspot.com/2026/05/dcii-13-great-cpan-modules-released.html" rel="noopener noreferrer"&gt;Great CPAN modules released last week&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Events
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://luma.com/perl-maven" rel="noopener noreferrer"&gt;Exploring Perl Modules + using AI (online)&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;June 3, 2026&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://boston.pm.org/" rel="noopener noreferrer"&gt;Boston Perl Mongers virtual monthly&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;June 9, 2026&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://paris.mongueurs.net/" rel="noopener noreferrer"&gt;Paris.pm monthly meeting&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;June 10, 2026&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.meetup.com/hacklafayette/" rel="noopener noreferrer"&gt;Purdue Perl Mongers (HackLafayette) - TBA&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;June 11, 2026&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://berlin.pm.org/" rel="noopener noreferrer"&gt;Berlin.pm - Naumanns Biergarten&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;June 24, 2026&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://luma.com/calendar/cal-ZFzHes2YwV6j0h9" rel="noopener noreferrer"&gt;Toronto.pm - June Social Evening&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;June 25, 2026&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://tprc.us/tprc-2026-gsp/" rel="noopener noreferrer"&gt;The Perl and Raku Conference 2026&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;June 26-29, 2026, Greenville, SC, USA&lt;/p&gt;




&lt;p&gt;You joined the Perl Weekly to get weekly e-mails about the Perl programming language and related topics.&lt;/p&gt;

&lt;p&gt;Want to see more? See the &lt;a href="https://perlweekly.com/archive/" rel="noopener noreferrer"&gt;archives&lt;/a&gt; of all the issues.&lt;/p&gt;

&lt;p&gt;Not yet subscribed to the newsletter? &lt;a href="https://perlweekly.com/subscribe.html" rel="noopener noreferrer"&gt;Join us free of charge&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;(C) Copyright &lt;a href="https://szabgab.com/" rel="noopener noreferrer"&gt;Gabor Szabo&lt;/a&gt;&lt;br&gt;
The articles are copyright the respective authors.&lt;/p&gt;

</content>
    <author>
      <name>Gabor Szabo</name>
    </author>
    <id>https://dev.to/szabgab/perl-weekly-775-events-and-using-ai-to-write-perl-59pm</id>
    <published>2026-06-01T06:43:21Z</published>
    <updated>2026-06-01T06:43:21Z</updated>
    <category term="perl"/>
    <category term="news"/>
    <category term="programming"/>
  </entry>
  <entry>
    <title>Introducing ZuzuScript</title>
    <link rel="alternate" href="https://blogs.perl.org/users/toby_inkster/2026/05/introducing-zuzuscript.html"/>
    <id>tag:blogs.perl.org,2026:/users/toby_inkster//1019.12063</id>
    <published>2026-06-01T01:22:23Z</published>
    <updated>2026-06-01T01:49:22Z</updated>
    <author>
        <name>Toby Inkster</name>
        <uri>https://toby.ink/</uri>
    </author>
    <content type="html" xml:lang="en" xml:base="https://blogs.perl.org/users/toby_inkster/">
        <![CDATA[<div>
<p>So I've created a programming language which blends a fairly JavaScript-like syntax with fairly Perl-like semantics, and a few other features that I haven't really seen in many programming languages.</p>
<p>This Perl:<p>
<pre>use Path::Tiny;

my $str = uc(substr(Path::Tiny->new("myfile.txt")->slurp_utf8, 0, 80));
</pre>
<p>Becomes this in ZuzuScript:</p>
<pre>from std/path import Path;

let str := new Path("myfile.txt")
  ▷ ^^.slurp_utf8
  ▷ ^^[0:80]
  ▷ uc ^^;
</pre>
<p>The <code>▷</code> operator means "evaluate the left side, then evaluate the right side with <code>^^</code> set to the result of the left side". It's conceptually similar to <code>|</code> in shells and seems to make a lot of expressions so much easier to understand.</p>
</div>]]>
        <![CDATA[<p>Other features I like:</p>

<ul>
<li><p>Path/query operators for XPath/JSONPath-like deep access to nested objects.</p></li>
<li><p>Built-in <code>async</code>/<code>await</code>.</p></li>
<li><p>OO including roles/traits.</p></li>
<li><p>Runs in the browser!</p></li>
<li><p>PairLists (like hashes, but with ordered keys that allow duplicate keys)</p></li>
<li><p><code>for</code>/<code>else</code></p></li>
</ul>

<p>Familiar things from Perl: documentation uses pod, variables are lexical (actually almost everything is lexical), there's a topic variable (but it's called <code>^^</code> instead of <code>$_</code>), different operators for different data types (<code>&gt;</code> for numbers but <code>gt</code> for strings), weak typing, keywords like <code>say</code> and <code>warn</code>, first class regexps, and a CPAN-like site for sharing modules.</p> 

<p>The primary implementation is in Perl, but there are alternative implementations in Rust and JavaScript. Yes, this is coded with AI assistance.</p>

<p>More info: <a href="https://zuzulang.org/">https://zuzulang.org/</a>.</p>]]>
    </content>
</entry>
  <entry xmlns:yt="http://www.youtube.com/xml/schemas/2015" xmlns:media="http://search.yahoo.com/mrss/">
  <id>yt:video:g_f1LVmNNuY</id>
  <yt:videoId>g_f1LVmNNuY</yt:videoId>
  <yt:channelId>UC7y4qaRSb5w2O8cCHOsKZDw</yt:channelId>
  <title>Toronto Perl Mongers / Yanick Champoux</title>
  <link rel="alternate" href="https://www.youtube.com/watch?v=g_f1LVmNNuY"/>
  <author>
   <name>The Perl and Raku Conference - Greenville, SC 2026</name>
   <uri>https://www.youtube.com/channel/UC7y4qaRSb5w2O8cCHOsKZDw</uri>
  </author>
  <published>2026-05-30T04:00:26+00:00</published>
  <updated>2026-05-31T17:30:21+00:00</updated>
  <media:group>
   <media:title>Toronto Perl Mongers / Yanick Champoux</media:title>
   <media:content url="https://www.youtube.com/v/g_f1LVmNNuY?version=3" type="application/x-shockwave-flash" width="640" height="390"/>
   <media:thumbnail url="https://i4.ytimg.com/vi/g_f1LVmNNuY/hqdefault.jpg" width="480" height="360"/>
   <media:description>Yanick Champoux delivers his talk: "JSON Schema: language-agnostic typing", followed by some Q&amp;A. This is part of a fairly regular meeting of the Toronto Perl Mongers, presented on the last Thursday of most months.

See our page on lu.ma for the latest information.</media:description>
   <media:community>
    <media:starRating count="12" average="5.00" min="1" max="5"/>
    <media:statistics views="170"/>
   </media:community>
  </media:group>
 </entry>
  <entry>
    <title>ANNOUNCE: Perl.Wiki V 1.47, JSTree copy V 1.21</title>
    <link rel="alternate" href="https://blogs.perl.org/users/ron_savage/2026/05/announce-perlwiki-v-147-jstree-copy-v-121.html"/>
    <id>tag:blogs.perl.org,2026:/users/ron_savage//297.12062</id>
    <published>2026-05-31T10:11:02Z</published>
    <updated>2026-05-31T10:14:17Z</updated>
    <author>
        <name>Ron Savage</name>
        <uri>http://savage.net.au/</uri>
    </author>
    <content type="html" xml:lang="en" xml:base="https://blogs.perl.org/users/ron_savage/">
        <![CDATA[<p>Both are available from my <a href="https://savage.net.au/">Wiki Haven</a>.</p>

<p>Next step will be the validation module for CPAN::MetaCurator, using the new:<br />
use feature 'class'<br />
code.</p>

<p>After that, back to the re-write of all *.pm in CPAN::MetaCurator.<br />
</p>]]>
        
    </content>
</entry>
  <entry xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0">
    <id>tag:blogger.com,1999:blog-5910101498857524639.post-4667685271776338738</id>
    <published>2026-05-30T17:12:53.819+02:00</published>
    <updated>2026-05-30T17:12:53.820+02:00</updated>
    <category scheme="http://www.blogger.com/atom/ns#" term="cpan"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="perl"/>
    <title type="text">(dcii) 13 great CPAN modules released last week</title>
    <content type="html">Updates for &lt;i&gt;great CPAN modules&lt;/i&gt; released last week. A module is considered &lt;i&gt;great&lt;/i&gt; if its favorites count is greater or equal than 12.&lt;br/&gt;&lt;br/&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/SKAJI/App-cpm-v1.1.1' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;App::cpm&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - a fast CPAN module installer
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;v1.1.1&lt;/strong&gt; on 2026-05-24, with 178 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: v1.1.0 was released 16 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/SKAJI'&gt;SKAJI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/KUERBIS/App-DBBrowser-2.442' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;App::DBBrowser&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Browse SQLite/MySQL/PostgreSQL databases and their tables interactively.
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;2.442&lt;/strong&gt; on 2026-05-22, with 18 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 2.441 was released 7 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/KUERBIS'&gt;KUERBIS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/OLIVER/App-Netdisco-2.099004' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;App::Netdisco&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - An open source web-based network management tool.
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;2.099004&lt;/strong&gt; on 2026-05-29, with 873 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 2.099003 was released 1 day before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/OLIVER'&gt;OLIVER&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/BINGOS/Archive-Tar-3.10' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Archive::Tar&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Manipulates TAR archives
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;3.10&lt;/strong&gt; on 2026-05-25, with 16 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 3.08 was released 3 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/BINGOS'&gt;BINGOS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/RURBAN/Cpanel-JSON-XS-4.41' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Cpanel::JSON::XS&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - cPanel fork of JSON::XS, fast and correct serializing
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;4.41&lt;/strong&gt; on 2026-05-27, with 47 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 4.40 was released 8 months, 19 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/RURBAN'&gt;RURBAN&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/BRIANDFOY/CPANSA-DB-20260524.001' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;CPANSA::DB&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - the CPAN Security Advisory data as a Perl data structure, mostly for CPAN::Audit
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;20260524.001&lt;/strong&gt; on 2026-05-24, with 25 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 20260517.001 was released 7 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/BRIANDFOY'&gt;BRIANDFOY&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/SCHUBIGER/DateTime-Format-Natural-1.26' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;DateTime::Format::Natural&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Parse informal natural language date/time strings
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;1.26&lt;/strong&gt; on 2026-05-28, with 19 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 1.25_04 was released 1 day before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/SCHUBIGER'&gt;SCHUBIGER&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/DBOOK/Minion-Backend-SQLite-v6.0.0' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Minion::Backend::SQLite&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - SQLite backend for Minion job queue
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;v6.0.0&lt;/strong&gt; on 2026-05-26, with 14 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: v5.0.7 was released 3 years, 9 months, 12 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/DBOOK'&gt;DBOOK&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/DBOOK/Mojo-SQLite-v4.0.0' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Mojo::SQLite&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - A tiny Mojolicious wrapper for SQLite
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;v4.0.0&lt;/strong&gt; on 2026-05-25, with 28 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 3.009 was released 4 years, 2 months, 2 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/DBOOK'&gt;DBOOK&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/KIMOTO/SPVM-0.990179' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;SPVM&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - The SPVM Language
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;0.990179&lt;/strong&gt; on 2026-05-29, with 36 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 0.990178 was released the same day&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/KIMOTO'&gt;KIMOTO&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/TODDR/Template-Toolkit-3.106' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Template::Toolkit&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - comprehensive template processing system
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;3.106&lt;/strong&gt; on 2026-05-25, with 149 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 3.105 was released the same day&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/TODDR'&gt;TODDR&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/GFRANKS/Test-MockModule-v0.185.2' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Test::MockModule&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Override subroutines in a module for unit testing
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;v0.185.2&lt;/strong&gt; on 2026-05-29, with 18 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: v0.185.1 was released 2 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/GFRANKS'&gt;GFRANKS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/TODDR/YAML-Syck-1.46' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;YAML::Syck&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Fast, lightweight YAML loader and dumper
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;1.46&lt;/strong&gt; on 2026-05-25, with 18 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 1.45 was released 1 month, 1 day before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/TODDR'&gt;TODDR&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content>
    <link rel="replies" type="application/atom+xml" href="https://niceperl.blogspot.com/feeds/4667685271776338738/comments/default" title="Enviar comentarios"/>
    <link rel="replies" type="text/html" href="https://niceperl.blogspot.com/2026/05/dcii-13-great-cpan-modules-released.html#comment-form" title="0 comentarios"/>
    <link rel="edit" type="application/atom+xml" href="https://www.blogger.com/feeds/5910101498857524639/posts/default/4667685271776338738"/>
    <link rel="self" type="application/atom+xml" href="https://www.blogger.com/feeds/5910101498857524639/posts/default/4667685271776338738"/>
    <link rel="alternate" type="text/html" href="https://niceperl.blogspot.com/2026/05/dcii-13-great-cpan-modules-released.html" title="(dcii) 13 great CPAN modules released last week"/>
    <author>
      <name>prz</name>
      <uri>http://www.blogger.com/profile/17989445983340548566</uri>
      <email>noreply@blogger.com</email>
      <gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="https://img1.blogblog.com/img/b16-rounded.gif"/>
    </author>
    <thr:total>0</thr:total>
  </entry>
  <entry>
    <title>Teaching AI About the British Monarchy with MCP</title>
    <link rel="alternate" href="https://perlhacks.com/2026/05/teaching-ai-about-the-british-monarchy-with-mcp/" type="text/html"/>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml"><p class="isSelectedEnd">One of the more interesting additions I’ve made recently to <a href="https://lineofsuccession.co.uk/">the Line of Succession website</a> is support for the <a href="https://en.wikipedia.org/wiki/Model_Context_Protocol">Model Context Protocol (MCP)</a>.</p>
<p class="isSelectedEnd">If you’ve spent any time around AI tooling recently, you’ve probably seen people talking about MCP. It’s often described as “USB for AI”, which is perhaps a little overblown, but the basic idea is sound. MCP provides a standard way for AI assistants to discover and use external tools and data sources.</p>
<p class="isSelectedEnd">In practical terms, it means that instead of building bespoke integrations for ChatGPT, Claude, Gemini and whatever comes next, you expose a standard MCP endpoint and let the AI clients do the rest.</p>
<p class="isSelectedEnd">For a data-driven site like Line of Succession, that seemed like an obvious experiment.</p>
<h2>What is MCP?</h2>
<p class="isSelectedEnd">The Model Context Protocol was originally developed by Anthropic and has rapidly become one of the emerging standards in the AI ecosystem.</p>
<p class="isSelectedEnd">An MCP server exposes:</p>
<ul data-spread="false">
<li>Information about itself</li>
<li>A list of available tools</li>
<li>Schemas describing how those tools should be called</li>
<li>The results returned by those tools</li>
</ul>
<p class="isSelectedEnd">An AI client can connect to the server, discover the available tools and invoke them when needed.</p>
<p class="isSelectedEnd">Instead of scraping web pages or attempting to infer information from HTML, the AI gets access to structured data.</p>
<p class="isSelectedEnd">That’s exactly the kind of thing Line of Succession is good at.</p>
<h2>Why Add MCP?</h2>
<p class="isSelectedEnd">The site already exposes information through a traditional web interface and a JSON API.</p>
<p class="isSelectedEnd">But those interfaces were designed for humans and developers respectively.</p>
<p class="isSelectedEnd">MCP gives AI systems a much cleaner integration point.</p>
<p class="isSelectedEnd">For example, an AI assistant can now answer questions like:</p>
<ul data-spread="false">
<li>Who was the British sovereign on 14 November 1948?</li>
<li>What did the line of succession look like in 1980?</li>
<li>Who was next in line when Queen Victoria died?</li>
</ul>
<p class="isSelectedEnd">without having to scrape pages or understand the site’s internal URLs.</p>
<p class="isSelectedEnd">More importantly, it ensures that the information comes directly from the same database that powers the website.</p>
<p class="isSelectedEnd">The AI isn’t guessing.</p>
<p class="isSelectedEnd">It’s querying the source of truth.</p>
<p class="isSelectedEnd">As someone who runs a reference website, that’s a pretty attractive proposition.</p>
<h2>The Initial Design</h2>
<p class="isSelectedEnd">My first goal was to keep things simple.</p>
<p class="isSelectedEnd">Rather than exposing dozens of narrowly-focused tools, I started with just two:</p>
<ul data-spread="false">
<li><code dir="ltr">sovereign_on_date</code></li>
<li><code dir="ltr">line_of_succession</code></li>
</ul>
<p class="isSelectedEnd">Those two tools cover a surprisingly large proportion of the questions people are likely to ask.</p>
<p class="isSelectedEnd">The first returns the sovereign reigning on a given date. The second returns the line of succession for a specified date, with a configurable limit on the number of entries returned.</p>
<p class="isSelectedEnd">The implementation currently caps the list at thirty people. That’s enough for most use cases while preventing someone from accidentally asking for all six thousand people currently in the line of succession.</p>
<p class="isSelectedEnd">One thing I learned quite quickly is that MCP isn’t really about exposing huge amounts of data. It’s about exposing useful questions that can be answered from your data.</p>
<h2>MCP Is Mostly JSON-RPC</h2>
<p class="isSelectedEnd">One thing that surprised me when I first started reading the specification was how little protocol code is actually required.</p>
<p class="isSelectedEnd">At its core, MCP uses <a href="https://en.wikipedia.org/wiki/JSON-RPC">JSON-RPC</a>.</p>
<p class="isSelectedEnd">A client sends requests like:</p>
<p/><pre class="urvanov-syntax-highlighter-plain-tag">{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/list"
}</pre><p/>
<p class="isSelectedEnd">and the server responds with:</p>
<p/><pre class="urvanov-syntax-highlighter-plain-tag">{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    ...
  }
}</pre><p/>
<p class="isSelectedEnd">Once I’d written helper methods for creating standard JSON-RPC responses, most of the complexity disappeared.</p>
<p class="isSelectedEnd">The MCP module contains methods like:</p>
<p/><pre class="urvanov-syntax-highlighter-plain-tag">sub rpc_result ($self, $id, $result)</pre><p/>
<p class="isSelectedEnd">and:</p>
<p/><pre class="urvanov-syntax-highlighter-plain-tag">sub rpc_error ($self, $id, $code, $message)</pre><p/>
<p class="isSelectedEnd">which means the Dancer route handlers remain pleasantly small.</p>
<p class="isSelectedEnd">The protocol logic lives in one place and the web application simply delegates to it.</p>
<h2>Separating the MCP Logic</h2>
<p class="isSelectedEnd">I didn’t want protocol-specific code scattered throughout the web application.</p>
<p class="isSelectedEnd">Instead, I created a dedicated module:</p>
<p/><pre class="urvanov-syntax-highlighter-plain-tag">package Succession::MCP;</pre><p/>
<p class="isSelectedEnd">This module is responsible for:</p>
<ul data-spread="false">
<li>Initialisation</li>
<li>Tool discovery</li>
<li>Tool execution</li>
<li>JSON-RPC response generation</li>
<li>Error handling</li>
</ul>
<p class="isSelectedEnd">That keeps the Dancer routes thin and makes the MCP implementation easier to test independently.</p>
<p class="isSelectedEnd">It also means that if I ever decide to expose the same MCP server through a different transport mechanism, most of the work is already done.</p>
<h2>Tool Calls Are Mostly Adapters</h2>
<p class="isSelectedEnd">One pleasant surprise was how little new application logic I actually had to write.</p>
<p class="isSelectedEnd">The MCP server needs to expose tools, but those tools ultimately just answer questions about the succession database. The code to answer those questions already existed.</p>
<p class="isSelectedEnd">For example, the application’s model layer already contained methods such as:</p>
<ul data-spread="false">
<li><code dir="ltr">sovereign_on_date()</code></li>
<li><code dir="ltr">line_of_succession()</code></li>
</ul>
<p class="isSelectedEnd">These methods power parts of the website itself, so they already encapsulate all of the business rules and database queries.</p>
<p class="isSelectedEnd">The MCP implementation simply acts as an adapter.</p>
<p class="isSelectedEnd">When a tool call arrives, the server extracts the arguments, validates them and passes them to the existing model methods:</p>
<p/><pre class="urvanov-syntax-highlighter-plain-tag">sub _call_tool ($self, $tool_name, $args) {
  my $tool = $self-&gt;_tool_dispatch-&gt;{$tool_name};

  return $tool-&gt;($args);
}</pre><p/>
<p class="isSelectedEnd">The tool implementations themselves are deliberately thin:</p>
<p/><pre class="urvanov-syntax-highlighter-plain-tag">sub sovereign_on_date ($self, $args) {
  my $date = $args-&gt;{date};

  my $sovereign = $self-&gt;model-&gt;sovereign_on_date($date);

  ...

}</pre><p/>
<p class="isSelectedEnd">That’s exactly how I wanted it to work.</p>
<p class="isSelectedEnd">The MCP layer doesn’t know how to calculate a line of succession or determine who was sovereign on a particular date. It simply knows how to expose those capabilities through the protocol.</p>
<p class="isSelectedEnd">This is one of the advantages of adding MCP to an existing application. If your business logic is already cleanly separated from your web interface, an MCP server often becomes surprisingly straightforward to implement.</p>
<p>In many ways, adding MCP feels less like building a new application and more like adding another interface alongside the website and API.</p>
<h2>The YAML Epiphany</h2>
<p class="isSelectedEnd">The most interesting design decision came a little later.</p>
<p class="isSelectedEnd">Initially, the tool definitions lived in Perl data structures.</p>
<p class="isSelectedEnd">That worked, but it quickly became obvious that I was duplicating information.</p>
<p class="isSelectedEnd">The MCP server needed tool descriptions.</p>
<p class="isSelectedEnd">The documentation page needed tool descriptions.</p>
<p class="isSelectedEnd">The schemas needed to be defined somewhere.</p>
<p class="isSelectedEnd">And every change required updating multiple places.</p>
<p class="isSelectedEnd">The obvious answer was to move all of the tool definitions into a YAML file.</p>
<p class="isSelectedEnd">The MCP module now loads its tool definitions at startup:</p>
<p/><pre class="urvanov-syntax-highlighter-plain-tag">sub _build__tools ($self) { return LoadFile($self-&gt;tools_file); }</pre><p/>
<p class="isSelectedEnd">The result is a single source of truth.</p>
<p class="isSelectedEnd">The same YAML file drives:</p>
<ul data-spread="false">
<li>The <code dir="ltr">tools/list</code> response</li>
<li>Tool metadata</li>
<li>JSON schemas</li>
<li>Human-readable documentation</li>
</ul>
<p class="isSelectedEnd">Adding a new tool now involves updating one file and writing the code that implements it.</p>
<p class="isSelectedEnd">Everything else follows automatically.</p>
<p class="isSelectedEnd">Here’s the current YAML file:</p>
<p/><pre class="urvanov-syntax-highlighter-plain-tag"># data/mcp-tools.yml

- name: sovereign_on_date
  description: Return the British sovereign on a given date.
  documentation: |
    Looks up the reigning British sovereign for the supplied date.

    Use this when answering questions such as “Who was sovereign on
    6 February 1952?”
  inputSchema:
    type: object
    properties:
      date:
        type: string
        description: Date in YYYY-MM-DD format.
    required:
      - date

- name: line_of_succession
  description: Return the line of succession on a given date.
  documentation: |
    Returns people in the line of succession.

    If no date is supplied, the current line of succession is returned.
  inputSchema:
    type: object
    properties:
      date:
        type: string
        description: Optional date in YYYY-MM-DD format. Omit for the current line of succession.
      limit:
        type: integer
        description: Maximum number of successors to return.
        minimum: 1
        maximum: 100
      required: []</pre><p/>
<p class="isSelectedEnd">Looking back, this is probably the part of the design I’m happiest with. It feels very Perl-ish: keep configuration as data and avoid duplicating information wherever possible.</p>
<h2>Human Documentation Matters</h2>
<p class="isSelectedEnd">One thing I noticed while exploring other MCP servers is that many of them are effectively invisible to humans.</p>
<p class="isSelectedEnd">You know an endpoint exists.</p>
<p class="isSelectedEnd">You know it speaks MCP.</p>
<p class="isSelectedEnd">But unless you inspect the protocol responses manually, you don’t really know what it does.</p>
<p class="isSelectedEnd">I decided to add a conventional web page at <a href="https://lineofsuccession.co.uk/mcp"><code dir="ltr">/mcp</code></a>.</p>
<p class="isSelectedEnd">The page lists all available tools, their descriptions and their schemas.</p>
<p class="isSelectedEnd">The nice part is that there is no duplicated documentation.</p>
<p class="isSelectedEnd">The page is generated from the same YAML definitions used by the MCP server itself.</p>
<p class="isSelectedEnd">If I add a new tool tomorrow, both the machine-readable and human-readable views update automatically.</p>
<h2>Structured Data and Text Responses</h2>
<p class="isSelectedEnd">Another nice feature of MCP is that tool results can include both structured data and human-readable text.</p>
<p class="isSelectedEnd">For example, a tool response might contain:</p>
<p/><pre class="urvanov-syntax-highlighter-plain-tag">{
  "content": [ {
    "type": "text",
    "text": "The sovereign on 14 November 1948 was George VI."
    } ],
  "structuredContent": {
    ...
  }
}</pre><p/>
<p class="isSelectedEnd">The structured content is useful for software.</p>
<p class="isSelectedEnd">The text is useful for humans and language models.</p>
<p class="isSelectedEnd">Both are generated from the same underlying data.</p>
<p class="isSelectedEnd">That gives AI clients flexibility while ensuring consistency.</p>
<h2>Getting Listed</h2>
<p class="isSelectedEnd">Once everything was working, I submitted the server to the MCP directory at <a href="https://mcpservers.org">mcpservers.org</a>.</p>
<p class="isSelectedEnd">That might seem like a small step, but discoverability is important.</p>
<p class="isSelectedEnd">An MCP server hidden on a random website isn’t much use if nobody knows it exists.</p>
<p class="isSelectedEnd">Directories like that are rapidly becoming the equivalent of API catalogues for the AI era.</p>
<p class="isSelectedEnd">Being listed means developers and AI enthusiasts can find the service without first discovering the website.</p>
<h2>Was It Worth It?</h2>
<p class="isSelectedEnd">Absolutely.</p>
<p class="isSelectedEnd">The amount of code required was surprisingly small. Most of the work wasn’t implementing the protocol; it was deciding how best to expose the data.</p>
<p class="isSelectedEnd">More importantly, it opens the site up to an entirely new audience: AI agents.</p>
<p class="isSelectedEnd">Historically, websites were built for humans and APIs were built for developers.</p>
<p class="isSelectedEnd">MCP introduces a third category: services designed specifically for AI systems.</p>
<p class="isSelectedEnd">For a structured-data site like Line of Succession, that’s a natural fit.</p>
<p class="isSelectedEnd">Will MCP still be the dominant standard in five years’ time? I have no idea. The AI industry changes too quickly to make confident predictions.</p>
<p class="isSelectedEnd">But right now it has significant momentum, broad industry support and a growing ecosystem of tools.</p>
<p>And if nothing else, it’s rather satisfying to ask an AI who was on the throne on a particular date and know that the answer came directly from my database rather than from whatever the model happened to remember.</p><p>The post <a href="https://perlhacks.com/2026/05/teaching-ai-about-the-british-monarchy-with-mcp/">Teaching AI About the British Monarchy with MCP</a> first appeared on <a href="https://perlhacks.com">Perl Hacks</a>.</p></div>
    </content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml"><p>One of the more interesting additions I’ve made recently to the Line of Succession website is support for the Model Context Protocol (MCP). If you’ve spent any time around AI tooling recently, you’ve probably seen people talking about MCP. It’s often described as “USB for AI”, which is perhaps a little overblown, but the basic […]</p>
<p>The post <a href="https://perlhacks.com/2026/05/teaching-ai-about-the-british-monarchy-with-mcp/">Teaching AI About the British Monarchy with MCP</a> first appeared on <a href="https://perlhacks.com">Perl Hacks</a>.</p></div>
    </summary>
    <author>
      <name>Dave Cross</name>
    </author>
    <id>https://perlhacks.com/?p=2445</id>
    <published>2026-05-30T09:58:02Z</published>
    <updated>2026-05-30T09:58:02Z</updated>
    <category term="Programming"/>
    <category term="ai"/>
    <category term="dancer2"/>
    <category term="line of succession"/>
    <category term="mcp"/>
    <category term="perl"/>
  </entry>
  <entry xmlns:re="http://purl.org/atompub/rank/1.0">
        <id>https://stackoverflow.com/q/79948430</id>
        <re:rank scheme="https://stackoverflow.com">3</re:rank>
        <title type="text">How do you create a working IO::Socket::INET socket object from a file descriptor?</title>
            <category scheme="https://stackoverflow.com/tags" term="perl"/>
            <category scheme="https://stackoverflow.com/tags" term="sockets"/>
            <category scheme="https://stackoverflow.com/tags" term="systemd"/>
            <category scheme="https://stackoverflow.com/tags" term="file-descriptor"/>
            <category scheme="https://stackoverflow.com/tags" term="plack"/>
        <author>
            <name>daxim</name>
            <uri>https://stackoverflow.com/users/46395</uri>
        </author>
        <link rel="alternate" href="https://stackoverflow.com/questions/79948430/how-do-you-create-a-working-iosocketinet-socket-object-from-a-file-descripto"/>
        <published>2026-05-29T11:38:30Z</published>
        <updated>2026-05-29T11:57:53Z</updated>
        <summary type="html">
            &lt;p&gt;Problem is &lt;code&gt;Bad arg length for Socket::unpack_sockaddr_in&lt;/code&gt;, see below.&lt;/p&gt;
&lt;h1&gt;repro&lt;/h1&gt;
&lt;p&gt;file &lt;code&gt;/tmp/demo/app.psgi&lt;/code&gt;&lt;/p&gt;
&lt;pre class="lang-perl prettyprint-override"&gt;&lt;code&gt;use 5.042;
use strictures;
use Plack::Request qw();
use experimental 'signatures';

my $app = sub($env) {
    my $req = Plack::Request-&amp;gt;new($env);
    return $req-&amp;gt;new_response(200, ['Content-Type' =&amp;gt; 'text/plain'], ['Hello world'])-&amp;gt;finalize;
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;file &lt;code&gt;~/.config/systemd/user/demo.service&lt;/code&gt;, replace … with absolute path to &lt;code&gt;plackup&lt;/code&gt;&lt;/p&gt;
&lt;pre class="lang-ini prettyprint-override"&gt;&lt;code&gt;[Unit]
Description=Socket-activated hello world service
Requires=demo.socket
After=network.target

[Service]
ExecStart=…perl/5.42.2/bin/plackup -a /tmp/demo/app.psgi
Type=simple
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;file &lt;code&gt;~/.config/systemd/user/demo.socket&lt;/code&gt;&lt;/p&gt;
&lt;pre class="lang-ini prettyprint-override"&gt;&lt;code&gt;[Unit]
Description=Socket for hello world service activation
PartOf=demo.service

[Socket]
ListenStream=5000
NoDelay=true
Backlog=128

[Install]
WantedBy=sockets.target
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;patch Plack-1.0054&lt;/p&gt;
&lt;pre class="lang-none prettyprint-override"&gt;&lt;code&gt;diff --git a/lib/HTTP/Server/PSGI.pm b/lib/HTTP/Server/PSGI.pm
index 225d4ca..f060463 100644
--- a/lib/HTTP/Server/PSGI.pm
+++ b/lib/HTTP/Server/PSGI.pm
@@ -90,6 +90,12 @@ sub prepare_socket_class {
 sub setup_listener {
     my $self = shift;
 
+    # TO DO: also handle LISTEN_PID LISTEN_PIDFDID
+    if ($ENV{LISTEN_FDS} &amp;amp;&amp;amp; 1 == $ENV{LISTEN_FDS}) {
+        $self-&amp;gt;{listen_sock} ||= IO::Socket::INET-&amp;gt;new_from_fd(3, 'r+');
+        goto DONE;
+    }
+
     $self-&amp;gt;{listen_sock} ||= do {
         my %args = (
             Listen    =&amp;gt; SOMAXCONN,
@@ -104,6 +110,7 @@ sub setup_listener {
             or die &amp;quot;failed to listen to port $self-&amp;gt;{port}: $!&amp;quot;;
     };
 
+DONE:
     $self-&amp;gt;{server_ready}-&amp;gt;({ %$self, proto =&amp;gt; $self-&amp;gt;{ssl} ? 'https' : 'http' });
 }
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;apply patch, install patched Plack where &lt;code&gt;app.psgi&lt;/code&gt; can use it&lt;/li&gt;
&lt;li&gt;make port 5000 available (perhaps is a Plack app already occupying?)&lt;/li&gt;
&lt;li&gt;run &lt;code&gt;systemctl --user daemon-reload&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;run &lt;code&gt;systemctl --user enable --now demo.socket&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;observed problem&lt;/h1&gt;
&lt;p&gt;Run &lt;code&gt;xh -v :5000&lt;/code&gt; or use any other HTTP client to &lt;code&gt;GET http://localhost:5000&lt;/code&gt;, no response.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;journalctl --user -e -u demo -f&lt;/code&gt; shows the error:&lt;/p&gt;
&lt;pre class="lang-none prettyprint-override"&gt;&lt;code&gt;systemd: Started Socket-activated hello world service.
plackup: HTTP::Server::PSGI: Accepting connections at http://0:5000/
plackup: Bad arg length for Socket::unpack_sockaddr_in, length is 28, should be 16 at …perl/5.42.2/lib/5.42.2/x86_64-linux-ld/Socket.pm line 858.
systemd: demo.service: Main process exited, code=exited, status=29/n/a
systemd: demo.service: Failed with result 'exit-code'.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To start over: &lt;code&gt;systemctl --user stop demo.service&lt;/code&gt; ; &lt;code&gt;systemctl --user restart demo.socket&lt;/code&gt;&lt;/p&gt;
&lt;h1&gt;expected result&lt;/h1&gt;
&lt;p&gt;HTTP request finishes&lt;/p&gt;
&lt;h1&gt;relevant&lt;/h1&gt;
&lt;p&gt;in dist &lt;code&gt;IO&lt;/code&gt;: &lt;a href="http://p3rl.org/IO::Handle#new_from_fd-%28-FD,-MODE-%29" rel="nofollow noreferrer"&gt;&lt;code&gt;new_from_fd&lt;/code&gt; documentation&lt;/a&gt;, &lt;a href="https://metacpan.org/dist/IO/source/t/cachepropagate-udp.t#L24" rel="nofollow noreferrer"&gt;&lt;code&gt;new_from_fd&lt;/code&gt; test&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;to clean up the system&lt;/h1&gt;
&lt;pre class="lang-bash prettyprint-override"&gt;&lt;code&gt;systemctl --user disable --now demo.socket
rm ~/.config/systemd/user/demo.{service,socket} /tmp/demo/app.psgi
# rm -rf …Plack-1.055
systemctl --user daemon-reload
&lt;/code&gt;&lt;/pre&gt;

        </summary>
    </entry>
  <entry xmlns:yt="http://www.youtube.com/xml/schemas/2015" xmlns:media="http://search.yahoo.com/mrss/">
  <id>yt:video:SbBnc8FjUXM</id>
  <yt:videoId>SbBnc8FjUXM</yt:videoId>
  <yt:channelId>UC7y4qaRSb5w2O8cCHOsKZDw</yt:channelId>
  <title>Toronto Perl Mongers / Stephen Zimmerman</title>
  <link rel="alternate" href="https://www.youtube.com/watch?v=SbBnc8FjUXM"/>
  <author>
   <name>The Perl and Raku Conference - Greenville, SC 2026</name>
   <uri>https://www.youtube.com/channel/UC7y4qaRSb5w2O8cCHOsKZDw</uri>
  </author>
  <published>2026-05-17T04:00:05+00:00</published>
  <updated>2026-05-28T21:39:01+00:00</updated>
  <media:group>
   <media:title>Toronto Perl Mongers / Stephen Zimmerman</media:title>
   <media:content url="https://www.youtube.com/v/SbBnc8FjUXM?version=3" type="application/x-shockwave-flash" width="640" height="390"/>
   <media:thumbnail url="https://i4.ytimg.com/vi/SbBnc8FjUXM/hqdefault.jpg" width="480" height="360"/>
   <media:description>Stephen Zimmerman talks about Parsing Perl Without Perl: A Rust LSP for Perl. Recorded April 30, 2026.</media:description>
   <media:community>
    <media:starRating count="24" average="5.00" min="1" max="5"/>
    <media:statistics views="338"/>
   </media:community>
  </media:group>
 </entry>
  <entry>
  <title>TPRC Schedule Posted - Time to Submit Lightning Talks</title>
  <link rel="alternate" type="text/html" href="https://news.perlfoundation.org/post/tprc-schedule-and-lightning-talks"/>
  <id>tag:news.perlfoundation.org,2026-05-27:/post/tprc-schedule-and-lightning-talks</id>
  <published>2026-05-27T22:57:56</published>
  <updated>2026-05-27T22:57:56</updated>
  <summary>
  <![CDATA[
     TPRC hotel pricing and early-bird pricing end at midnight on May 28th. If you haven’t registered and reserved your hotel room, today is the day! The conference schedule is now published. We have a lineup of great speakers! Check it out at https://tprc.us/tprc-2026-gsp/schedule-2/ We are also now accepting submissions for Lightning Talks, which are talks of no more than 5 minutes. They are a great way to participate, and make 
   ]]>
  </summary>
  <author>
    <name>Sarah T Gray</name>
  </author>  <content type="html" xml:lang="en-us" xml:base="http://news.perlfoundation.org/">
   <![CDATA[
     
       <img src="_ra-rel-mnt_/simplecas/fetch_content/586a12dc7c0a0858f0c73abfd0fbe41b183cad65/tprc2026_512x512.png" style="max-width:100%;max-height:100%;padding:20px;" /><br>
     
     <p>TPRC hotel pricing and early-bird pricing end at midnight (Eastern Time) on May 28th. If you haven’t registered and reserved your hotel room, today is the day!</p>

<p>The conference schedule is now published. We have a lineup of great speakers! Check it out at https://tprc.us/tprc-2026-gsp/schedule-2/ .</p>

<p>We are also now accepting submissions for Lightning Talks, which are talks of no more than 5 minutes. They are a great way to participate, and make a contribution to the community! See https://tprc.us/tprc-2026-gsp/lightning-talks/ to submit a talk or to learn more about them.</p>

<p>Did you know that this conference is the Namer for Lightning Talks? It is true, way back in 2000, and we are proud to have an unbroken streak of Gongs ever since! See https://en.wikipedia.org/wiki/Lightning_talk , and https://www.youtube.com/@YAPCNA/search?query=lightning%20talk .</p>

    ]]>
  </content>
</entry>
  <entry>
    <title>The Weekly Challenge: The Common Beauty</title>
    <link rel="alternate" href="https://dev.to/simongreennet/the-weekly-challenge-the-common-beauty-5eh3" type="text/html"/>
    <content type="html">&lt;h2&gt;
  
  
  Weekly Challenge 375
&lt;/h2&gt;

&lt;p&gt;Each week Mohammad S. Anwar sends out &lt;a href="https://theweeklychallenge.org/" rel="noopener noreferrer"&gt;The Weekly Challenge&lt;/a&gt;, a chance for all of us to come up with solutions to two weekly tasks. My solutions are written in Python first, and then converted to Perl. Unless otherwise stated, Copilot (and other AI tools) have NOT been used to generate the solution. It's a great way for us all to practice some coding.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-375/" rel="noopener noreferrer"&gt;Challenge&lt;/a&gt;, &lt;a href="https://github.com/manwar/perlweeklychallenge-club/tree/master/challenge-375/sgreen" rel="noopener noreferrer"&gt;My solutions&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Task 1: Single Common Word
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Task
&lt;/h3&gt;

&lt;p&gt;You are given two array of strings.&lt;/p&gt;

&lt;p&gt;Write a script to return the number of strings that appear exactly once in each of the two given arrays. String comparison is case sensitive.&lt;/p&gt;

&lt;h3&gt;
  
  
  My solution
&lt;/h3&gt;

&lt;p&gt;For input from the command, I take two space separated strings to generate the two arrays.&lt;/p&gt;

&lt;p&gt;For this task, I start by counting the frequency of words in each list (array in Perl).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Counter&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;single_common_word&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;array2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;freq1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;freq2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I then create two sets of words which only appear once in each list.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="n"&gt;unique1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;freq1&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;freq1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;unique2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;freq2&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;freq2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, I return the length of the intersection of both sets.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unique1&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;unique2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Perl solution follows a similar logic. Using the scalar function will return the number of items in the array.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Array::&lt;/span&gt;&lt;span class="nv"&gt;Utils&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;intersect&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;

&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt; &lt;span class="p"&gt;( $str1, $str2 ) {&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@array1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;split&lt;/span&gt; &lt;span class="sr"&gt;/\s+/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$str1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@array2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;split&lt;/span&gt; &lt;span class="sr"&gt;/\s+/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$str2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;%freq1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;%freq2&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$freq1&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="nv"&gt;@array1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nv"&gt;$freq2&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="nv"&gt;@array2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@unique1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$freq1&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nb"&gt;keys&lt;/span&gt; &lt;span class="nv"&gt;%freq1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@unique2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$freq2&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nb"&gt;keys&lt;/span&gt; &lt;span class="nv"&gt;%freq2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nb"&gt;scalar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;intersect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;@unique1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;@unique2&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Examples
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./ch-1.py &lt;span class="s2"&gt;"apple banana cherry"&lt;/span&gt; &lt;span class="s2"&gt;"banana cherry date"&lt;/span&gt;
2

&lt;span class="nv"&gt;$ &lt;/span&gt;./ch-1.py &lt;span class="s2"&gt;"a ab abc"&lt;/span&gt; &lt;span class="s2"&gt;"a a ab abc"&lt;/span&gt;
2

&lt;span class="nv"&gt;$ &lt;/span&gt;./ch-1.py &lt;span class="s2"&gt;"orange lemon"&lt;/span&gt; &lt;span class="s2"&gt;"grape melon"&lt;/span&gt;
0

&lt;span class="nv"&gt;$ &lt;/span&gt;./ch-1.py &lt;span class="s2"&gt;"test test demo"&lt;/span&gt; &lt;span class="s2"&gt;"test demo demo"&lt;/span&gt;
0

&lt;span class="nv"&gt;$ &lt;/span&gt;./ch-1.py &lt;span class="s2"&gt;"Hello world"&lt;/span&gt; &lt;span class="s2"&gt;"hello world"&lt;/span&gt;
1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Task 2: Find K-Beauty
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Task
&lt;/h3&gt;

&lt;p&gt;You are given a number and a digit &lt;code&gt;k&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Write a script to find the K-Beauty of the given number. The K-Beauty of an integer number is defined as the number of substrings of given number when it is read as a string has length of &lt;code&gt;k&lt;/code&gt; and is a divisor of given number.&lt;/p&gt;

&lt;h3&gt;
  
  
  My solution
&lt;/h3&gt;

&lt;p&gt;This is relatively straight forward. Python treats integers and strings as different types (and methods that can be called). The first thing I do is convert &lt;code&gt;num&lt;/code&gt; to a string called &lt;code&gt;s&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;k_beauty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I then generate all possible substrings of length &lt;code&gt;k&lt;/code&gt; and check if it is evenly divisible from the original number. If it is I increment the &lt;code&gt;count&lt;/code&gt; variable. At the end, I return the final &lt;code&gt;count&lt;/code&gt; value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Perl doesn't care (most of the times) about integers vs strings. This makes the code a little more straight forward.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt; &lt;span class="p"&gt;( $num, $k ) {&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$start&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="nb"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$k&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$num&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$k&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="nv"&gt;$count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;$count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Examples
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./ch-2.py 240 2
2

&lt;span class="nv"&gt;$ &lt;/span&gt;./ch-2.py 1020 2
3

&lt;span class="nv"&gt;$ &lt;/span&gt;./ch-2.py 444 2
0

&lt;span class="nv"&gt;$ &lt;/span&gt;./ch-2.py 17 2
1

&lt;span class="nv"&gt;$ &lt;/span&gt;./ch-2.py 123 1
2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</content>
    <author>
      <name>Simon Green</name>
    </author>
    <id>https://dev.to/simongreennet/the-weekly-challenge-the-common-beauty-5eh3</id>
    <published>2026-05-25T13:07:54Z</published>
    <updated>2026-05-25T13:07:54Z</updated>
    <category term="python"/>
    <category term="perl"/>
    <category term="theweeklychallenge"/>
  </entry>
  <entry xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0">
    <id>tag:blogger.com,1999:blog-5910101498857524639.post-1651599864339605645</id>
    <published>2026-05-23T21:09:20.128+02:00</published>
    <updated>2026-05-23T21:09:20.128+02:00</updated>
    <category scheme="http://www.blogger.com/atom/ns#" term="cpan"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="perl"/>
    <title type="text">(dci) 19 great CPAN modules released last week</title>
    <content type="html">Updates for &lt;i&gt;great CPAN modules&lt;/i&gt; released last week. A module is considered &lt;i&gt;great&lt;/i&gt; if its favorites count is greater or equal than 12.&lt;br/&gt;&lt;br/&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/SKAJI/App-FatPacker-Simple-v1.0.2' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;App::FatPacker::Simple&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - only fatpack a script
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;v1.0.2&lt;/strong&gt; on 2026-05-22, with 12 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: v1.0.1 was released the same day&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/SKAJI'&gt;SKAJI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/OLIVER/App-Netdisco-2.099000' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;App::Netdisco&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - An open source web-based network management tool.
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;2.099000&lt;/strong&gt; on 2026-05-20, with 868 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 2.098005 was released 10 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/OLIVER'&gt;OLIVER&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/BINGOS/Archive-Tar-3.08' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Archive::Tar&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Manipulates TAR archives
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;3.08&lt;/strong&gt; on 2026-05-22, with 16 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 3.06 was released 12 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/BINGOS'&gt;BINGOS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/GWILLIAMS/Attean-0.038' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Attean&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - A Semantic Web Framework
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;0.038&lt;/strong&gt; on 2026-05-20, with 19 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 0.037 was released the same day&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/GWILLIAMS'&gt;GWILLIAMS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/ROBM/Cache-FastMmap-1.62' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Cache::FastMmap&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Uses an mmap'ed file to act as a shared memory interprocess cache
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;1.62&lt;/strong&gt; on 2026-05-18, with 25 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 1.61 was released 17 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/ROBM'&gt;ROBM&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/ETHER/Catalyst-Plugin-Authentication-0.10026' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Catalyst::Plugin::Authentication&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Infrastructure plugin for the Catalyst authentication framework.
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;0.10026&lt;/strong&gt; on 2026-05-21, with 12 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 0.10_025 was released 1 day before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/ETHER'&gt;ETHER&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/BRIANDFOY/CPANSA-DB-20260517.001' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;CPANSA::DB&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - the CPAN Security Advisory data as a Perl data structure, mostly for CPAN::Audit
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;20260517.001&lt;/strong&gt; on 2026-05-17, with 25 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 20260503.001 was released 12 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/BRIANDFOY'&gt;BRIANDFOY&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/OALDERS/HTML-Parser-3.85' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;HTML::Parser&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - HTML parser class
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;3.85&lt;/strong&gt; on 2026-05-19, with 51 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 3.84 was released the same day&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/OALDERS'&gt;OALDERS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/OALDERS/HTTP-Daemon-6.17' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;HTTP::Daemon&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - A simple http server class
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;6.17&lt;/strong&gt; on 2026-05-19, with 13 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 6.16 was released 3 years, 2 months, 23 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/OALDERS'&gt;OALDERS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/HAARG/HTTP-Tiny-0.094' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;HTTP::Tiny&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - A small, simple, correct HTTP/1.1 client
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;0.094&lt;/strong&gt; on 2026-05-17, with 116 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 0.093 was released 5 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/HAARG'&gt;HAARG&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/PMQS/IO-Compress-2.220' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;IO::Compress&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - IO Interface to compressed data files/buffers
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;2.220&lt;/strong&gt; on 2026-05-16, with 20 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 2.219 was released 2 months, 7 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/PMQS'&gt;PMQS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/SRI/Minion-12.0' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Minion&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Job queue
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;12.0&lt;/strong&gt; on 2026-05-18, with 236 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 11.0 was released 8 months, 26 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/SRI'&gt;SRI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/HAARG/Role-Tiny-2.002005' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Role::Tiny&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Roles: a nouvelle cuisine portion size slice of Moose
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;2.002005&lt;/strong&gt; on 2026-05-17, with 72 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 2.002004 was released 5 years, 3 months, 24 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/HAARG'&gt;HAARG&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/YVES/Sereal-5.006' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Sereal&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Fast, compact, powerful binary (de-)serialization
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;5.006&lt;/strong&gt; on 2026-05-20, with 65 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 5.005 was released the same day&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/YVES'&gt;YVES&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/YVES/Sereal-Decoder-5.006' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Sereal::Decoder&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Fast, compact, powerful binary deserialization
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;5.006&lt;/strong&gt; on 2026-05-20, with 26 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 5.005 was released the same day&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/YVES'&gt;YVES&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/YVES/Sereal-Encoder-5.006' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Sereal::Encoder&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Fast, compact, powerful binary serialization
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;5.006&lt;/strong&gt; on 2026-05-20, with 25 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 5.005 was released the same day&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/YVES'&gt;YVES&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/TODDR/Template-Toolkit-3.103' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Template::Toolkit&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - comprehensive template processing system
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;3.103&lt;/strong&gt; on 2026-05-21, with 149 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 3.102 was released 1 year, 10 months, 29 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/TODDR'&gt;TODDR&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/CORION/WWW-Mechanize-Chrome-0.77' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;WWW::Mechanize::Chrome&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - automate the Chrome browser
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;0.77&lt;/strong&gt; on 2026-05-17, with 22 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 0.76 was released 2 months, 4 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/CORION'&gt;CORION&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/TODDR/XML-LibXML-2.0213' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;XML::LibXML&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Interface to Gnome libxml2 xml parsing and DOM library
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;2.0213&lt;/strong&gt; on 2026-05-21, with 103 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 2.0212 was released 1 day before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/TODDR'&gt;TODDR&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content>
    <link rel="replies" type="application/atom+xml" href="https://niceperl.blogspot.com/feeds/1651599864339605645/comments/default" title="Enviar comentarios"/>
    <link rel="replies" type="text/html" href="https://niceperl.blogspot.com/2026/05/dci-19-great-cpan-modules-released-last.html#comment-form" title="0 comentarios"/>
    <link rel="edit" type="application/atom+xml" href="https://www.blogger.com/feeds/5910101498857524639/posts/default/1651599864339605645"/>
    <link rel="self" type="application/atom+xml" href="https://www.blogger.com/feeds/5910101498857524639/posts/default/1651599864339605645"/>
    <link rel="alternate" type="text/html" href="https://niceperl.blogspot.com/2026/05/dci-19-great-cpan-modules-released-last.html" title="(dci) 19 great CPAN modules released last week"/>
    <author>
      <name>prz</name>
      <uri>http://www.blogger.com/profile/17989445983340548566</uri>
      <email>noreply@blogger.com</email>
      <gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="https://img1.blogblog.com/img/b16-rounded.gif"/>
    </author>
    <thr:total>0</thr:total>
  </entry>
  <entry xmlns:re="http://purl.org/atompub/rank/1.0">
        <id>https://stackoverflow.com/q/79944496</id>
        <re:rank scheme="https://stackoverflow.com">-3</re:rank>
        <title type="text">"Modification of a read-only value attempted" when using JSON object</title>
            <category scheme="https://stackoverflow.com/tags" term="json"/>
            <category scheme="https://stackoverflow.com/tags" term="perl"/>
            <category scheme="https://stackoverflow.com/tags" term="constants"/>
        <author>
            <name>U. Windl</name>
            <uri>https://stackoverflow.com/users/32596570</uri>
        </author>
        <link rel="alternate" href="https://stackoverflow.com/questions/79944496/modification-of-a-read-only-value-attempted-when-using-json-object"/>
        <published>2026-05-21T08:27:04Z</published>
        <updated>2026-05-22T18:20:02Z</updated>
        <summary type="html">
            &lt;p&gt;A few years ago I wrote some Perl code using  JSON. It still worked in SLES15 SP6, but in SLES15 SP7 I get an error like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Modification of a read-only value attempted at (eval 73)[/usr/lib/perl5/vendor_perl/5.26.1/JSON.pm:287] line 63.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The code in question is:&lt;/p&gt;
&lt;pre class="lang-perl prettyprint-override"&gt;&lt;code&gt;use JSON -support_by_pp;
#...
use constant JSON_INDENT        =&amp;gt; JSON-&amp;gt;new(); # indenting JSONizer
JSON_INDENT-&amp;gt;utf8(1);
JSON_INDENT-&amp;gt;indent(1);
JSON_INDENT-&amp;gt;indent_length(0);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If I comment the last line, then the error does not occur.&lt;/p&gt;
&lt;p&gt;(I use the constant in code like &lt;code&gt;print JSON_INDENT-&amp;gt;pretty-&amp;gt;encode($JSON), &amp;quot;\n&amp;quot;&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;For the SP upgrade I noticed these related changes:
Package &lt;code&gt;perl-JSON-XS-4.40.0-bp157.2.3.1.x86_64&lt;/code&gt; was added, and package &lt;code&gt;perl-Cpanel-JSON-XS&lt;/code&gt; was upgraded from &lt;code&gt;4.37-bp156.2.3.1&lt;/code&gt; to &lt;code&gt;4.380.0-150700.3.3.1&lt;/code&gt; (both &lt;code&gt;x86_64&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;What is the problem, and how to resolve it?&lt;/p&gt;
&lt;p&gt;The package code in question is:&lt;/p&gt;
&lt;pre class="lang-perl prettyprint-override"&gt;&lt;code&gt;sub _load_xs {
    my ($module, $opt) = @_;
    __load_xs($module, $opt) or return;

    my $data = join(&amp;quot;&amp;quot;, &amp;lt;DATA&amp;gt;); # this code is from Jcode 2.xx.
    close(DATA);
    eval $data;
    JSON::Backend::XS-&amp;gt;init($module);

    return 1;
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Line 287 is &lt;code&gt;eval $data;&lt;/code&gt;.&lt;/p&gt;

        </summary>
    </entry>
  <entry>
  <title>TPRC is about 30 days from now!</title>
  <link rel="alternate" type="text/html" href="https://news.perlfoundation.org/post/tprc-2026-30-day-away"/>
  <id>tag:news.perlfoundation.org,2026-05-20:/post/tprc-2026-30-day-away</id>
  <published>2026-05-20T20:14:32</published>
  <updated>2026-05-20T20:14:32</updated>
  <summary>
  <![CDATA[
     It is just over 30 days before the start of The Perl and Raku Conference. Even if you are a procrastinator, it’s time to make your plans to attend! Early bird pricing for registration will end on May 28. Special conference pricing for our block of hotel rooms also expires on May 28. So it is definitely time to get yourself registered and to get your room reserved. Speakers have 
   ]]>
  </summary>
  <author>
    <name>Sarah T Gray</name>
  </author>  <content type="html" xml:lang="en-us" xml:base="http://news.perlfoundation.org/">
   <![CDATA[
     
       <img src="_ra-rel-mnt_/simplecas/fetch_content/f934ea07d0332b09dd0246ade879359029fb3f35/tprc2026_851x315.png" style="max-width:100%;max-height:100%;padding:20px;" /><br>
     
     <p>It is just over 30 days before the start of The Perl and Raku Conference.  Even if you are a procrastinator, it’s time to make your plans to attend!</p>

<p>Early bird pricing for registration will end on May 28.  Special conference pricing for our block of hotel rooms also expires on May 28.  So it is definitely time to get yourself registered and to get your room reserved.
Speakers have been notified, and the schedule is being built. <br />
Go to https://tprc.us for all the information about how to register, how to reserve your room, and to see the schedule once it is posted.</p>

<p>When you are making your travel plans, consider the following:  On Monday, June 29, we are offering a class: Teaching AI New Tricks: Perly MCP’s for Claude.  This class is described at https://tprc.us.  Registration for the class is a separate ticket.  Check out the details on our website!</p>

<p>Also, on Friday evening, June 26 after our first day of talks, we are offering our version of “Pizza Planet”.  We will provide a pizza supper, followed by transportation to the Roper Mountain Science Center and Planetarium show, and an opportunity to visit the Daniel Observatory.  This experience is included as part of your conference fee, so come join the fun! You are guaranteed a ticket if you register by May 28!</p>

<p>The conference planning team needs to know if you are coming so we can make sure and have everything ready for you (t-shirt, lunches, name badge, planetarium tickets, etc). Please register today! </p>

    ]]>
  </content>
</entry>
  <entry>
    <title>Greybeards rise</title>
    <link rel="alternate" href="https://wesley.schwengle.net/article/greybeards-rise-how-a-vim-colorscheme-changed-my-desktop-bf5a/" type="text/html"/>
    <content type="html">&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;p&gt;Twenty years of desktop environments — WindowMaker, KDE3, fvwm, i3 — and the
lesson is always the same: consistency beats aesthetics. This is how I took one
vim colorscheme (iceberg) and spread it across my entire desktop: terminal,
prompt, window manager, launcher, screensaver, and even git. One palette
aligns the whole UI. The only constraint you lay on yourself: timebox it.
Because theming takes a fuck-ton of time.&lt;/p&gt;
&lt;h2 id="iceberg-ahead"&gt;Iceberg ahead&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m no ricer by any means. But I can tell you my process. Nothing is planned,
but everything I did, I did with a masterplan.&lt;/p&gt;</content>
    <id>https://wesley.schwengle.net/article/greybeards-rise-how-a-vim-colorscheme-changed-my-desktop-bf5a/</id>
    <published>2026-05-19T11:41:50-04:00</published>
    <updated>2026-05-19T11:41:50-04:00</updated>
  </entry>
  <entry>
    <title>The Long Road from CGI to Containers</title>
    <link rel="alternate" href="https://perlhacks.com/2026/05/the-long-road-from-cgi-to-containers/" type="text/html"/>
    <content type="html">&lt;p data-start="69" data-end="215"&gt;One of the defining characteristics of a good programmer is an instinct for keeping implementation details in the correct layer of an application.&lt;/p&gt;
&lt;p data-start="217" data-end="364"&gt;That sounds abstract, but it turns out to explain a huge amount of the progress we’ve made in software development over the last twenty-five years.&lt;/p&gt;
&lt;p data-start="366" data-end="423"&gt;And nowhere is that clearer than in Perl web development.&lt;/p&gt;
&lt;p data-start="425" data-end="532"&gt;Many of us who built web applications during the dotcom boom spent years learning this lesson the hard way.&lt;/p&gt;
&lt;p data-start="534" data-end="561"&gt;We wrote CGI programs that:&lt;/p&gt;
&lt;ul data-start="562" data-end="828"&gt;
&lt;li data-section-id="1hrkapv" data-start="562" data-end="584"&gt;parsed HTTP requests&lt;/li&gt;
&lt;li data-section-id="ia7w56" data-start="585" data-end="601"&gt;generated HTML by hand&lt;/li&gt;
&lt;li data-section-id="11qm9he" data-start="602" data-end="635"&gt;connected directly to databases&lt;/li&gt;
&lt;li data-section-id="oxywwx" data-start="636" data-end="657"&gt;embedded SQL inline&lt;/li&gt;
&lt;li data-section-id="10ssi1" data-start="658" data-end="698"&gt;mixed business logic with presentation&lt;/li&gt;
&lt;li data-section-id="1k0ef25" data-start="699" data-end="727"&gt;relied on Apache behaviour&lt;/li&gt;
&lt;li data-section-id="1o4kt96" data-start="728" data-end="765"&gt;assumed specific filesystem layouts&lt;/li&gt;
&lt;li data-section-id="1xpkcp2" data-start="766" data-end="828"&gt;and often only worked on one particular server configuration&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-start="830" data-end="861"&gt;It all worked. Until it didn’t.&lt;/p&gt;
&lt;p data-start="863" data-end="1015"&gt;The history of Perl web development is, in many ways, the history of gradually moving implementation details into more appropriate architectural layers.&lt;/p&gt;
&lt;hr data-start="1017" data-end="1020" /&gt;
&lt;h2 data-section-id="el1fv2" data-start="1022" data-end="1044"&gt;The Early CGI Years&lt;/h2&gt;
&lt;p data-start="1046" data-end="1107"&gt;Early Perl CGI applications were often a single giant script.&lt;/p&gt;
&lt;p data-start="1109" data-end="1135"&gt;You’d open a file and see:&lt;/p&gt;
&lt;ul data-start="1136" data-end="1261"&gt;
&lt;li data-section-id="vbdqpi" data-start="1136" data-end="1154"&gt;request handling&lt;/li&gt;
&lt;li data-section-id="gqcdm0" data-start="1155" data-end="1171"&gt;authentication&lt;/li&gt;
&lt;li data-section-id="v39dg3" data-start="1172" data-end="1189"&gt;HTML generation&lt;/li&gt;
&lt;li data-section-id="1wl0ikq" data-start="1190" data-end="1203"&gt;SQL queries&lt;/li&gt;
&lt;li data-section-id="pcs1uo" data-start="1204" data-end="1220"&gt;business logic&lt;/li&gt;
&lt;li data-section-id="xq775k" data-start="1221" data-end="1236"&gt;configuration&lt;/li&gt;
&lt;li data-section-id="1a36h93" data-start="1237" data-end="1261"&gt;deployment assumptions&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-start="1263" data-end="1309"&gt;…all mixed together in a glorious ball of mud.&lt;/p&gt;
&lt;p data-start="1311" data-end="1331"&gt;Something like this:&lt;/p&gt;
&lt;div class="relative w-full mt-4 mb-1"&gt;
&lt;div class=""&gt;
&lt;div class="relative"&gt;
&lt;div class="h-full min-h-0 min-w-0"&gt;
&lt;div class="h-full min-h-0 min-w-0"&gt;
&lt;div class="border border-token-border-light border-radius-3xl corner-superellipse/1.1 rounded-3xl"&gt;
&lt;div class="h-full w-full border-radius-3xl bg-token-bg-elevated-secondary corner-superellipse/1.1 overflow-clip rounded-3xl lxnfua_clipPathFallback"&gt;
&lt;div class="relative"&gt;
&lt;div class=""&gt;
&lt;div class="relative z-0 flex max-w-full"&gt;
&lt;div id="code-block-viewer" class="q9tKkq_viewer cm-editor z-10 light:cm-light dark:cm-light flex h-full w-full flex-col items-stretch ͼd ͼr" dir="ltr"&gt;
&lt;div class="cm-scroller"&gt;
&lt;pre class="urvanov-syntax-highlighter-plain-tag"&gt;#!/usr/bin/perl

use CGI;
use DBI;

my $cgi = CGI-&amp;gt;new;

print $cgi-&amp;gt;header;
print "&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;";

my $dbh = DBI-&amp;gt;connect(
  "dbi:mysql:test",
  "user",
  "pass"
);

my $sth = $dbh-&amp;gt;prepare(
  "select * from users where id = ?"
);

$sth-&amp;gt;execute($cgi-&amp;gt;param('id'));

while (my $row = $sth-&amp;gt;fetchrow_hashref) {
  print "&amp;lt;h1&amp;gt;$row-&amp;gt;{name}&amp;lt;/h1&amp;gt;";
}

print "&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;";&lt;/pre&gt;&lt;br /&gt;
At the time, this felt perfectly normal.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-start="1759" data-end="1827"&gt;And to be fair, it &lt;em data-start="1778" data-end="1783"&gt;was&lt;/em&gt; a huge step forward from static HTML sites.&lt;/p&gt;
&lt;p data-start="1829" data-end="1870"&gt;But the design had a fundamental problem:&lt;/p&gt;
&lt;p data-start="1872" data-end="1919"&gt;Everything knew too much about everything else.&lt;/p&gt;
&lt;p data-start="1921" data-end="1948"&gt;The application logic knew:&lt;/p&gt;
&lt;ul data-start="1949" data-end="2086"&gt;
&lt;li data-section-id="39oag0" data-start="1949" data-end="1966"&gt;how HTTP worked&lt;/li&gt;
&lt;li data-section-id="uiq751" data-start="1967" data-end="1984"&gt;how HTML worked&lt;/li&gt;
&lt;li data-section-id="15et8bv" data-start="1985" data-end="2018"&gt;how Apache launched CGI scripts&lt;/li&gt;
&lt;li data-section-id="1ugkrtw" data-start="2019" data-end="2044"&gt;how the database worked&lt;/li&gt;
&lt;li data-section-id="jts300" data-start="2045" data-end="2086"&gt;how the operating system was configured&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-start="2088" data-end="2134"&gt;Every concern leaked into every other concern.&lt;/p&gt;
&lt;p data-start="2136" data-end="2154"&gt;That made systems:&lt;/p&gt;
&lt;ul data-start="2155" data-end="2245"&gt;
&lt;li data-section-id="1mg424a" data-start="2155" data-end="2169"&gt;hard to test&lt;/li&gt;
&lt;li data-section-id="az09iw" data-start="2170" data-end="2185"&gt;hard to reuse&lt;/li&gt;
&lt;li data-section-id="1ueutk7" data-start="2186" data-end="2202"&gt;hard to deploy&lt;/li&gt;
&lt;li data-section-id="b3tx90" data-start="2203" data-end="2218"&gt;hard to scale&lt;/li&gt;
&lt;li data-section-id="1lbws61" data-start="2219" data-end="2245"&gt;and terrifying to change&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-start="2247" data-end="2250" /&gt;
&lt;h2 data-section-id="196ob5l" data-start="2252" data-end="2299"&gt;The First Big Lesson: Put Logic in Libraries&lt;/h2&gt;
&lt;p data-start="2301" data-end="2448"&gt;One of the first signs of a developer maturing is the realisation that application logic should live in reusable modules, not in front-end scripts.&lt;/p&gt;
&lt;p data-start="2450" data-end="2466"&gt;Instead of this:&lt;/p&gt;
&lt;div class="relative w-full mt-4 mb-1"&gt;
&lt;div class=""&gt;
&lt;div class="relative"&gt;
&lt;div class="h-full min-h-0 min-w-0"&gt;
&lt;div class="h-full min-h-0 min-w-0"&gt;
&lt;div class="border border-token-border-light border-radius-3xl corner-superellipse/1.1 rounded-3xl"&gt;
&lt;div class="h-full w-full border-radius-3xl bg-token-bg-elevated-secondary corner-superellipse/1.1 overflow-clip rounded-3xl lxnfua_clipPathFallback"&gt;
&lt;div class="relative"&gt;
&lt;div class=""&gt;
&lt;div class="relative z-0 flex max-w-full"&gt;
&lt;div id="code-block-viewer" class="q9tKkq_viewer cm-editor z-10 light:cm-light dark:cm-light flex h-full w-full flex-col items-stretch ͼd ͼr" dir="ltr"&gt;
&lt;div class="cm-scroller"&gt;
&lt;pre class="urvanov-syntax-highlighter-plain-tag"&gt;if ($user-&amp;gt;{status} eq 'gold') {
  $discount = 0.2;
}&lt;/pre&gt;&lt;br /&gt;
being embedded directly in a CGI script, it becomes:&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="relative w-full mt-4 mb-1"&gt;
&lt;div class=""&gt;
&lt;div class="relative"&gt;
&lt;div class="h-full min-h-0 min-w-0"&gt;
&lt;div class="h-full min-h-0 min-w-0"&gt;
&lt;div class="border border-token-border-light border-radius-3xl corner-superellipse/1.1 rounded-3xl"&gt;
&lt;div class="h-full w-full border-radius-3xl bg-token-bg-elevated-secondary corner-superellipse/1.1 overflow-clip rounded-3xl lxnfua_clipPathFallback"&gt;
&lt;div class="relative"&gt;
&lt;div class=""&gt;
&lt;div class="relative z-0 flex max-w-full"&gt;
&lt;div id="code-block-viewer" class="q9tKkq_viewer cm-editor z-10 light:cm-light dark:cm-light flex h-full w-full flex-col items-stretch ͼd ͼr" dir="ltr"&gt;
&lt;div class="cm-scroller"&gt;
&lt;pre class="urvanov-syntax-highlighter-plain-tag"&gt;my $discount = $user-&amp;gt;discount_rate;&lt;/pre&gt;&lt;br /&gt;
That sounds like a small change, but architecturally it’s enormous.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-start="2708" data-end="2750"&gt;Now the business logic lives in a library.&lt;/p&gt;
&lt;p data-start="2752" data-end="2816"&gt;And once that happens, several good things follow automatically.&lt;/p&gt;
&lt;h3 data-section-id="1sxaypq" data-start="2818" data-end="2857"&gt;Multiple Interfaces Become Possible&lt;/h3&gt;
&lt;p data-start="2859" data-end="2892"&gt;If the logic is in modules, then:&lt;/p&gt;
&lt;ul data-start="2893" data-end="2966"&gt;
&lt;li data-section-id="17qbl7e" data-start="2893" data-end="2910"&gt;a web front-end&lt;/li&gt;
&lt;li data-section-id="oyv07r" data-start="2911" data-end="2923"&gt;a CLI tool&lt;/li&gt;
&lt;li data-section-id="12c0bb5" data-start="2924" data-end="2936"&gt;a REST API&lt;/li&gt;
&lt;li data-section-id="198xz7i" data-start="2937" data-end="2949"&gt;a cron job&lt;/li&gt;
&lt;li data-section-id="9ycnhq" data-start="2950" data-end="2966"&gt;a queue worker&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-start="2968" data-end="3006"&gt;…can all use the same underlying code.&lt;/p&gt;
&lt;p data-start="3008" data-end="3041"&gt;The interface layer becomes thin.&lt;/p&gt;
&lt;p data-start="3043" data-end="3116"&gt;The application itself becomes independent of how users interact with it.&lt;/p&gt;
&lt;p data-start="3118" data-end="3156"&gt;That’s a huge increase in flexibility.&lt;/p&gt;
&lt;h3 data-section-id="1pgnydl" data-start="3158" data-end="3184"&gt;Testing Becomes Easier&lt;/h3&gt;
&lt;p data-start="3186" data-end="3225"&gt;Testing CGI scripts was always awkward.&lt;/p&gt;
&lt;p data-start="3227" data-end="3262"&gt;Testing modules is straightforward.&lt;/p&gt;
&lt;p data-start="3264" data-end="3373"&gt;You can instantiate objects, call methods, and inspect results without needing a web server or HTTP requests.&lt;/p&gt;
&lt;p data-start="3375" data-end="3438"&gt;The easier code is to test, the more likely it is to be tested.&lt;/p&gt;
&lt;p data-start="3440" data-end="3480"&gt;And tested code tends to survive longer.&lt;/p&gt;
&lt;h3 data-section-id="1awrd8" data-start="3482" data-end="3510"&gt;Deployment Becomes Safer&lt;/h3&gt;
&lt;p data-start="3512" data-end="3621"&gt;Once the core behaviour is isolated from the interface layer, replacing the interface becomes far less risky.&lt;/p&gt;
&lt;p data-start="3623" data-end="3681"&gt;You can redesign the UI without rewriting the application.&lt;/p&gt;
&lt;p data-start="3683" data-end="3750"&gt;That separation is one of the foundations of maintainable software.&lt;/p&gt;
&lt;hr data-start="3752" data-end="3755" /&gt;
&lt;h2 data-section-id="4h31i2" data-start="3757" data-end="3779"&gt;The PSGI Revolution&lt;/h2&gt;
&lt;p data-start="3781" data-end="3894"&gt;The next big architectural leap in Perl web development came with PSGI and &lt;span class="hover:entity-accent entity-underline inline cursor-pointer align-baseline"&gt;&lt;span class="whitespace-normal"&gt;Plack&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p data-start="3896" data-end="3978"&gt;Younger developers may not fully appreciate how painful web deployment used to be.&lt;/p&gt;
&lt;p data-start="3980" data-end="4086"&gt;In the early 2000s, moving an application between hosting environments could require substantial rewrites.&lt;/p&gt;
&lt;ul&gt;
&lt;li data-start="4088" data-end="4121"&gt;A CGI application worked one way.&lt;/li&gt;
&lt;li data-start="4123" data-end="4165"&gt;A mod_perl application worked another way.&lt;/li&gt;
&lt;li data-start="4167" data-end="4194"&gt;FastCGI had its own quirks.&lt;/li&gt;
&lt;li data-start="4196" data-end="4247"&gt;Embedded Apache handlers behaved differently again.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-start="4249" data-end="4363"&gt;Many Perl developers spent years repeatedly rewriting applications simply because deployment environments changed.&lt;/p&gt;
&lt;p data-start="4365" data-end="4382"&gt;That was madness.&lt;/p&gt;
&lt;p data-start="4384" data-end="4431"&gt;The deployment model is an operational concern.&lt;/p&gt;
&lt;p data-start="4433" data-end="4479"&gt;It should not affect application architecture.&lt;/p&gt;
&lt;p data-start="4481" data-end="4571"&gt;PSGI fixed this by defining a standard interface between web applications and web servers.&lt;/p&gt;
&lt;p data-start="4573" data-end="4610"&gt;The core idea was beautifully simple:&lt;/p&gt;
&lt;blockquote data-start="4612" data-end="4703"&gt;
&lt;p data-start="4614" data-end="4703"&gt;A web application is just a function that receives an environment and returns a response.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-start="4705" data-end="4791"&gt;Once that abstraction existed, applications no longer cared whether they were running:&lt;/p&gt;
&lt;ul data-start="4792" data-end="4921"&gt;
&lt;li data-section-id="1843bvb" data-start="4792" data-end="4800"&gt;as CGI&lt;/li&gt;
&lt;li data-section-id="88tafm" data-start="4801" data-end="4817"&gt;under mod_perl&lt;/li&gt;
&lt;li data-section-id="yepid5" data-start="4818" data-end="4834"&gt;inside FastCGI&lt;/li&gt;
&lt;li data-section-id="15pdpy" data-start="4835" data-end="4850"&gt;under Starman&lt;/li&gt;
&lt;li data-section-id="12cjln6" data-start="4851" data-end="4865"&gt;behind nginx&lt;/li&gt;
&lt;li data-section-id="ytnv71" data-start="4866" data-end="4891"&gt;on a development laptop&lt;/li&gt;
&lt;li data-section-id="1tqpuce" data-start="4892" data-end="4921"&gt;or inside a cloud container&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-start="4923" data-end="4965"&gt;The deployment details moved down a layer.&lt;/p&gt;
&lt;p data-start="4967" data-end="4995"&gt;Exactly where they belonged.&lt;/p&gt;
&lt;p data-start="4997" data-end="5090"&gt;This was one of the most important architectural improvements Perl web development ever made.&lt;/p&gt;
&lt;p data-start="5092" data-end="5125"&gt;And it reflected a broader truth:&lt;/p&gt;
&lt;blockquote data-start="5127" data-end="5202"&gt;
&lt;p data-start="5129" data-end="5202"&gt;Good abstractions stop lower-level implementation details leaking upward.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2 data-section-id="141ej8e" data-start="477" data-end="526"&gt;&lt;span role="text"&gt;The Transitional Era: FatPacker and &lt;code data-start="516" data-end="526"&gt;cpanfile&lt;/code&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-start="528" data-end="640"&gt;There was also an interesting intermediate stage between traditional Perl deployments and full containerisation.&lt;/p&gt;
&lt;p data-start="642" data-end="735"&gt;For years, one of the hardest parts of deploying Perl applications was dependency management.&lt;/p&gt;
&lt;p data-start="737" data-end="792"&gt;You’d move an application to a new server and discover:&lt;/p&gt;
&lt;ul data-start="793" data-end="968"&gt;
&lt;li data-section-id="hphz5e" data-start="793" data-end="819"&gt;the wrong module version&lt;/li&gt;
&lt;li data-section-id="1t55rzy" data-start="820" data-end="842"&gt;missing XS libraries&lt;/li&gt;
&lt;li data-section-id="1dwhnmz" data-start="843" data-end="871"&gt;incompatible Perl versions&lt;/li&gt;
&lt;li data-section-id="s0gapw" data-start="872" data-end="968"&gt;or an entire dependency tree that worked perfectly on the developer’s machine and nowhere else&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-start="970" data-end="1049"&gt;Large parts of Perl deployment culture evolved around coping with this problem.&lt;/p&gt;
&lt;p data-start="1051" data-end="1138"&gt;Tools like &lt;code data-start="1062" data-end="1072"&gt;cpanfile&lt;/code&gt; improved things by making dependencies explicit and reproducible.&lt;/p&gt;
&lt;p data-start="1140" data-end="1233"&gt;Instead of vaguely documenting requirements in a README, applications could formally declare:&lt;/p&gt;
&lt;div class="relative w-full mt-4 mb-1"&gt;
&lt;div class=""&gt;
&lt;div class="relative"&gt;
&lt;div class="h-full min-h-0 min-w-0"&gt;
&lt;div class="h-full min-h-0 min-w-0"&gt;
&lt;div class="border border-token-border-light border-radius-3xl corner-superellipse/1.1 rounded-3xl"&gt;
&lt;div class="h-full w-full border-radius-3xl bg-token-bg-elevated-secondary corner-superellipse/1.1 overflow-clip rounded-3xl lxnfua_clipPathFallback"&gt;
&lt;div class="relative"&gt;
&lt;div class=""&gt;
&lt;div class="relative z-0 flex max-w-full"&gt;
&lt;div id="code-block-viewer" class="q9tKkq_viewer cm-editor z-10 light:cm-light dark:cm-light flex h-full w-full flex-col items-stretch ͼd ͼr" dir="ltr"&gt;
&lt;div class="cm-scroller"&gt;
&lt;pre class="urvanov-syntax-highlighter-plain-tag"&gt;requires 'Dancer2';
requires 'DBIx::Class';
requires 'Template';&lt;/pre&gt;&lt;br /&gt;
That may seem obvious now, but it was a major improvement in deployment reliability.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-start="1411" data-end="1541"&gt;Then tools like &lt;span class="hover:entity-accent entity-underline inline cursor-pointer align-baseline"&gt;&lt;span class="whitespace-normal"&gt;App::FatPacker&lt;/span&gt;&lt;/span&gt; went even further by packaging dependencies directly alongside applications.&lt;/p&gt;
&lt;p data-start="1543" data-end="1668"&gt;Instead of relying on the target server’s Perl environment, applications could carry much of their runtime context with them.&lt;/p&gt;
&lt;p data-start="1670" data-end="1729"&gt;These tools didn’t completely solve deployment portability:&lt;/p&gt;
&lt;ul data-start="1730" data-end="1840"&gt;
&lt;li data-section-id="1b7y3ls" data-start="1730" data-end="1763"&gt;system libraries still mattered&lt;/li&gt;
&lt;li data-section-id="wz1oqm" data-start="1764" data-end="1794"&gt;Perl versions still mattered&lt;/li&gt;
&lt;li data-section-id="9e0j1c" data-start="1795" data-end="1840"&gt;operating system differences still mattered&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-start="1842" data-end="1895"&gt;…but they represented an important shift in thinking.&lt;/p&gt;
&lt;p data-start="1897" data-end="1939"&gt;The industry was gradually realising that:&lt;/p&gt;
&lt;ul data-start="1940" data-end="2078"&gt;
&lt;li data-section-id="40bngv" data-start="1940" data-end="1994"&gt;deployment environments were part of the application&lt;/li&gt;
&lt;li data-section-id="u5r428" data-start="1995" data-end="2021"&gt;reproducibility mattered&lt;/li&gt;
&lt;li data-section-id="1eq5k9r" data-start="2022" data-end="2078"&gt;and infrastructure assumptions needed to be controlled&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-start="2080" data-end="2221"&gt;Containers eventually pushed this idea to its logical conclusion by packaging not just Perl dependencies, but the entire runtime environment.&lt;/p&gt;
&lt;p data-start="2223" data-end="2342"&gt;In hindsight, tools like &lt;code data-start="2248" data-end="2258"&gt;cpanfile&lt;/code&gt; and FatPacker were stepping stones toward modern container-based deployment models.&lt;/p&gt;
&lt;hr data-start="5204" data-end="5207" /&gt;
&lt;h2 data-section-id="avc5zh" data-start="5209" data-end="5246"&gt;Containers Are the Same Idea Again&lt;/h2&gt;
&lt;p data-start="5248" data-end="5339"&gt;Docker and containers are simply the same architectural principle repeated one layer lower.&lt;/p&gt;
&lt;p data-start="5341" data-end="5423"&gt;Before containers, deployments were often fragile and highly environment-specific.&lt;/p&gt;
&lt;p data-start="5425" data-end="5450"&gt;Applications depended on:&lt;/p&gt;
&lt;ul data-start="5451" data-end="5590"&gt;
&lt;li data-section-id="oqa14g" data-start="5451" data-end="5483"&gt;particular Linux distributions&lt;/li&gt;
&lt;li data-section-id="y8i1ze" data-start="5484" data-end="5508"&gt;specific Perl versions&lt;/li&gt;
&lt;li data-section-id="1rbybas" data-start="5509" data-end="5537"&gt;installed system libraries&lt;/li&gt;
&lt;li data-section-id="aqka3g" data-start="5538" data-end="5563"&gt;hand-configured servers&lt;/li&gt;
&lt;li data-section-id="3iagcb" data-start="5564" data-end="5590"&gt;undocumented setup steps&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-start="5592" data-end="5643"&gt;Developers became experts in “works on my machine”.&lt;/p&gt;
&lt;p data-start="5645" data-end="5689"&gt;Operations teams became experts in swearing.&lt;/p&gt;
&lt;p data-start="5691" data-end="5720"&gt;Containers changed the model.&lt;/p&gt;
&lt;p data-start="5722" data-end="5743"&gt;Instead of deploying:&lt;/p&gt;
&lt;ul data-start="5744" data-end="5757"&gt;
&lt;li data-section-id="10oh7ug" data-start="5744" data-end="5757"&gt;source code&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-start="5759" data-end="5771"&gt;…you deploy:&lt;/p&gt;
&lt;ul data-start="5772" data-end="5804"&gt;
&lt;li data-section-id="4cejjd" data-start="5772" data-end="5804"&gt;a complete runtime environment&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-start="5806" data-end="5858"&gt;Now the application no longer cares whether it runs:&lt;/p&gt;
&lt;ul data-start="5859" data-end="5950"&gt;
&lt;li data-section-id="113ihho" data-start="5859" data-end="5874"&gt;on bare metal&lt;/li&gt;
&lt;li data-section-id="1mrrym5" data-start="5875" data-end="5885"&gt;on a VPS&lt;/li&gt;
&lt;li data-section-id="149vzbh" data-start="5886" data-end="5901"&gt;in Kubernetes&lt;/li&gt;
&lt;li data-section-id="12u780q" data-start="5902" data-end="5910"&gt;in ECS&lt;/li&gt;
&lt;li data-section-id="4cz653" data-start="5911" data-end="5925"&gt;in Cloud Run&lt;/li&gt;
&lt;li data-section-id="suuk3c" data-start="5926" data-end="5950"&gt;or on someone’s laptop&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-start="5952" data-end="5958"&gt;Again:&lt;/p&gt;
&lt;ul data-start="5959" data-end="6033"&gt;
&lt;li data-section-id="s7lqvb" data-start="5959" data-end="5998"&gt;infrastructure concerns move downward&lt;/li&gt;
&lt;li data-section-id="hitqb" data-start="5999" data-end="6033"&gt;application concerns stay upward&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-start="6035" data-end="6065"&gt;The boundaries become cleaner.&lt;/p&gt;
&lt;hr data-start="6067" data-end="6070" /&gt;
&lt;h2 data-section-id="1fgmdxc" data-start="6072" data-end="6105"&gt;The Pattern Repeats Everywhere&lt;/h2&gt;
&lt;p data-start="6107" data-end="6180"&gt;Once you notice this pattern, you see it throughout software engineering.&lt;/p&gt;
&lt;h3 data-section-id="xbyhet" data-start="6182" data-end="6195"&gt;Templates&lt;/h3&gt;
&lt;p data-start="6197" data-end="6223"&gt;Template systems separate:&lt;/p&gt;
&lt;ul data-start="6224" data-end="6263"&gt;
&lt;li data-section-id="61p7qa" data-start="6224" data-end="6243"&gt;presentation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;from&lt;/p&gt;
&lt;ul data-start="6224" data-end="6263"&gt;
&lt;li data-section-id="1y7k1lo" data-start="6244" data-end="6263"&gt;application logic&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-start="6265" data-end="6303"&gt;HTML should not contain database code.&lt;/p&gt;
&lt;p data-start="6305" data-end="6359"&gt;Business logic should not contain giant blobs of HTML.&lt;/p&gt;
&lt;h3 data-section-id="6dh2fv" data-start="6361" data-end="6389"&gt;ORMs and Database Layers&lt;/h3&gt;
&lt;p data-start="6391" data-end="6440"&gt;DBI separates applications from database engines.&lt;/p&gt;
&lt;p data-start="6442" data-end="6492"&gt;ORMs separate applications from raw SQL structure.&lt;/p&gt;
&lt;p data-start="6494" data-end="6500"&gt;Again:&lt;/p&gt;
&lt;ul data-start="6501" data-end="6539"&gt;
&lt;li data-section-id="1lr5kvv" data-start="6501" data-end="6539"&gt;implementation details move downward&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-section-id="k34kmu" data-start="6541" data-end="6558"&gt;Configuration&lt;/h3&gt;
&lt;p data-start="6560" data-end="6595"&gt;Configuration belongs outside code.&lt;/p&gt;
&lt;p data-start="6597" data-end="6663"&gt;Deployment-specific values should not be embedded in applications.&lt;/p&gt;
&lt;h3 data-section-id="ynhw6l" data-start="6665" data-end="6673"&gt;APIs&lt;/h3&gt;
&lt;p data-start="6675" data-end="6723"&gt;Clients should not care whether data comes from:&lt;/p&gt;
&lt;ul data-start="6724" data-end="6802"&gt;
&lt;li data-section-id="6zn6pa" data-start="6724" data-end="6736"&gt;PostgreSQL&lt;/li&gt;
&lt;li data-section-id="179h5y9" data-start="6737" data-end="6744"&gt;Redis&lt;/li&gt;
&lt;li data-section-id="cg5dvi" data-start="6745" data-end="6762"&gt;another service&lt;/li&gt;
&lt;li data-section-id="1rclt94" data-start="6763" data-end="6772"&gt;a queue&lt;/li&gt;
&lt;li data-section-id="4lspky" data-start="6773" data-end="6785"&gt;flat files&lt;/li&gt;
&lt;li data-section-id="d24z0d" data-start="6786" data-end="6802"&gt;or magic elves&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-start="6804" data-end="6840"&gt;That’s the implementation’s problem.&lt;/p&gt;
&lt;hr data-start="6842" data-end="6845" /&gt;
&lt;h2 data-section-id="1i68abl" data-start="6847" data-end="6894"&gt;The Goal Is Not Abstraction for Its Own Sake&lt;/h2&gt;
&lt;p data-start="6896" data-end="6980"&gt;Of course, experienced developers also know that abstractions can become ridiculous.&lt;/p&gt;
&lt;p data-start="6982" data-end="7017"&gt;Some abstractions simplify systems.&lt;/p&gt;
&lt;p data-start="7019" data-end="7086"&gt;Others merely hide complexity behind six additional layers of YAML.&lt;/p&gt;
&lt;p data-start="7088" data-end="7196"&gt;Joel Spolsky’s “Law of Leaky Abstractions” remains painfully relevant.&lt;/p&gt;
&lt;p data-start="7198" data-end="7233"&gt;The goal is not abstraction itself.&lt;/p&gt;
&lt;p data-start="7235" data-end="7285"&gt;The goal is to isolate genuinely volatile details.&lt;/p&gt;
&lt;p data-start="7287" data-end="7333"&gt;Good abstractions protect systems from change.&lt;/p&gt;
&lt;p data-start="7335" data-end="7375"&gt;Bad abstractions merely obscure reality.&lt;/p&gt;
&lt;hr data-start="7377" data-end="7380" /&gt;
&lt;h2 data-section-id="1ja5yev" data-start="7382" data-end="7399"&gt;The Real Skill&lt;/h2&gt;
&lt;p data-start="7401" data-end="7480"&gt;The deeper lesson here is that software architecture is largely about deciding:&lt;/p&gt;
&lt;blockquote data-start="7482" data-end="7505"&gt;
&lt;p data-start="7484" data-end="7505"&gt;“What belongs where?”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-start="7507" data-end="7554"&gt;Experienced developers develop an instinct for:&lt;/p&gt;
&lt;ul data-start="7555" data-end="7675"&gt;
&lt;li data-section-id="ost2yq" data-start="7555" data-end="7591"&gt;which details are likely to change&lt;/li&gt;
&lt;li data-section-id="cpoyga" data-start="7592" data-end="7639"&gt;which layers should know about which concerns&lt;/li&gt;
&lt;li data-section-id="1slr97u" data-start="7640" data-end="7675"&gt;and where boundaries should exist&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-start="7677" data-end="7770"&gt;That instinct is often more important than language choice, frameworks, or technology stacks.&lt;/p&gt;
&lt;p data-start="7772" data-end="7901" data-is-last-node="" data-is-only-node=""&gt;And if you spent the early 2000s rewriting CGI applications to run under mod_perl, you probably learned that lesson the hard way.&lt;/p&gt;
&lt;figure id="attachment_2442" aria-describedby="caption-attachment-2442" style="width: 300px" class="wp-caption aligncenter"&gt;&lt;a href="https://perlhacks.com/wp-content/uploads/2026/05/perl-web-dev-infographic.png"&gt;&lt;img fetchpriority="high" decoding="async" class="size-medium wp-image-2442" src="https://perlhacks.com/wp-content/uploads/2026/05/perl-web-dev-infographic-300x200.png" alt="Perl Web Development Over Time" width="300" height="200" srcset="https://perlhacks.com/wp-content/uploads/2026/05/perl-web-dev-infographic-300x200.png 300w, https://perlhacks.com/wp-content/uploads/2026/05/perl-web-dev-infographic-1024x683.png 1024w, https://perlhacks.com/wp-content/uploads/2026/05/perl-web-dev-infographic-768x512.png 768w, https://perlhacks.com/wp-content/uploads/2026/05/perl-web-dev-infographic.png 1536w" sizes="(max-width: 300px) 100vw, 300px" /&gt;&lt;/a&gt;&lt;figcaption id="caption-attachment-2442" class="wp-caption-text"&gt;Perl Web Development Over Time&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;The post &lt;a href="https://perlhacks.com/2026/05/the-long-road-from-cgi-to-containers/"&gt;The Long Road from CGI to Containers&lt;/a&gt; first appeared on &lt;a href="https://perlhacks.com"&gt;Perl Hacks&lt;/a&gt;.&lt;/p&gt;</content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml"><p>One of the defining characteristics of a good programmer is an instinct for keeping implementation details in the correct layer of an application. That sounds abstract, but it turns out to explain a huge amount of the progress we’ve made in software development over the last twenty-five years. And nowhere is that clearer than in […]</p>
<p>The post <a href="https://perlhacks.com/2026/05/the-long-road-from-cgi-to-containers/">The Long Road from CGI to Containers</a> first appeared on <a href="https://perlhacks.com">Perl Hacks</a>.</p></div>
    </summary>
    <author>
      <name>Dave Cross</name>
    </author>
    <id>https://perlhacks.com/?p=2437</id>
    <published>2026-05-18T15:36:11Z</published>
    <updated>2026-05-18T15:36:11Z</updated>
    <category term="Programming"/>
    <category term="cgi"/>
    <category term="docker"/>
    <category term="perl"/>
    <category term="psgi"/>
    <category term="softwarearchitecture"/>
  </entry>
  <entry>
    <title>Why Your Students Should Be Adding Fractions in Perl — Yes, Really</title>
    <link rel="alternate" href="https://medium.com/@iniobong.okpokpo/why-your-students-should-be-adding-fractions-in-perl-yes-really-1ce7be572e4b?source=rss------perl-5" type="text/html"/>
    <content type="html">&lt;div class="medium-feed-item"&gt;&lt;p class="medium-feed-image"&gt;&lt;a href="https://medium.com/@iniobong.okpokpo/why-your-students-should-be-adding-fractions-in-perl-yes-really-1ce7be572e4b?source=rss------perl-5"&gt;&lt;img src="https://cdn-images-1.medium.com/max/1536/1*wH5g35Mtn6ZA5vRYxpcHeQ.png" width="1536"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p class="medium-feed-snippet"&gt;The unexpected intersection of maths literacy and coding confidence that every secondary educator should know about&lt;/p&gt;&lt;p class="medium-feed-link"&gt;&lt;a href="https://medium.com/@iniobong.okpokpo/why-your-students-should-be-adding-fractions-in-perl-yes-really-1ce7be572e4b?source=rss------perl-5"&gt;Continue reading on Medium »&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;</content>
    <author>
      <name>Iniobong Okpokpo</name>
    </author>
    <id>https://medium.com/p/1ce7be572e4b</id>
    <published>2026-05-17T20:13:50Z</published>
    <updated>2026-05-17T20:13:50.067000Z</updated>
    <category term="mathematics-education"/>
    <category term="perl"/>
    <category term="secondary-education"/>
    <category term="stem"/>
    <category term="coding"/>
  </entry>
  <entry xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0">
    <id>tag:blogger.com,1999:blog-5910101498857524639.post-1351758505306644571</id>
    <published>2026-05-16T16:31:28.394+02:00</published>
    <updated>2026-05-16T16:31:28.394+02:00</updated>
    <category scheme="http://www.blogger.com/atom/ns#" term="cpan"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="perl"/>
    <title type="text">(dc) 17 great CPAN modules released last week</title>
    <content type="html">Updates for &lt;i&gt;great CPAN modules&lt;/i&gt; released last week. A module is considered &lt;i&gt;great&lt;/i&gt; if its favorites count is greater or equal than 12.&lt;br/&gt;&lt;br/&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/KUERBIS/App-DBBrowser-2.441' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;App::DBBrowser&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Browse SQLite/MySQL/PostgreSQL databases and their tables interactively.
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;2.441&lt;/strong&gt; on 2026-05-15, with 18 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 2.440 was released 1 month, 3 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/KUERBIS'&gt;KUERBIS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/OLIVER/App-Netdisco-2.098005' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;App::Netdisco&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - An open source web-based network management tool.
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;2.098005&lt;/strong&gt; on 2026-05-10, with 865 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 2.098004 was released 1 day before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/OLIVER'&gt;OLIVER&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/PMQS/App-zipdetails-4.006' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;App::zipdetails&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Display details about the internal structure of Zip files
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;4.006&lt;/strong&gt; on 2026-05-16, with 66 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 4.005 was released 2 months, 7 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/PMQS'&gt;PMQS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/BINGOS/Archive-Tar-3.06' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Archive::Tar&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Manipulates TAR archives
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;3.06&lt;/strong&gt; on 2026-05-10, with 16 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 3.04 was released 1 year, 2 months, 12 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/BINGOS'&gt;BINGOS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/MIK/Crypt-JWT-0.038' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Crypt::JWT&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - JSON Web Token
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;0.038&lt;/strong&gt; on 2026-05-16, with 54 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 0.037_2 was released 5 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/MIK'&gt;MIK&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/LEONT/Crypt-Passphrase-0.023' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Crypt::Passphrase&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - A module for managing passwords in a cryptographically agile manner
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;0.023&lt;/strong&gt; on 2026-05-15, with 17 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 0.022 was released 1 month, 24 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/LEONT'&gt;LEONT&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/MIK/CryptX-0.089' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;CryptX&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Cryptographic toolkit
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;0.089&lt;/strong&gt; on 2026-05-10, with 53 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 0.088_005 was released 3 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/MIK'&gt;MIK&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/CHEVALIER/Google-Ads-GoogleAds-Client-32.1.0' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Google::Ads::GoogleAds::Client&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Google Ads API Client Library for Perl
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;v32.1.0&lt;/strong&gt; on 2026-05-13, with 20 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: v32.0.0 was released 20 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/CHEVALIER'&gt;CHEVALIER&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/TONYC/Imager-1.031' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Imager&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Perl extension for Generating 24 bit Images
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;1.031&lt;/strong&gt; on 2026-05-15, with 68 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 1.030 was released 1 month, 1 day before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/TONYC'&gt;TONYC&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/PEVANS/IO-Socket-IP-0.44' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;IO::Socket::IP&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Family-neutral IP socket supporting both IPv4 and IPv6
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;0.44&lt;/strong&gt; on 2026-05-13, with 22 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 0.43 was released 1 year, 5 months, 17 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/PEVANS'&gt;PEVANS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/ETHER/JSON-Schema-Modern-0.639' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;JSON::Schema::Modern&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Validate data against a schema using a JSON Schema
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;0.639&lt;/strong&gt; on 2026-05-09, with 16 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 0.638 was released 21 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/ETHER'&gt;ETHER&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/OALDERS/libwww-perl-6.83' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;LWP&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - The World-Wide Web library for Perl
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;6.83&lt;/strong&gt; on 2026-05-12, with 211 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 6.82 was released 1 month, 13 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/OALDERS'&gt;OALDERS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/OALDERS/LWP-ConsoleLogger-1.000002' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;LWP::ConsoleLogger&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - LWP tracing and debugging
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;1.000002&lt;/strong&gt; on 2026-05-12, with 12 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 1.000001 was released 2 years, 10 months, 21 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/OALDERS'&gt;OALDERS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/SRI/Mojo-Pg-5.0' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Mojo::Pg&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Mojolicious ♥ PostgreSQL
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;5.0&lt;/strong&gt; on 2026-05-12, with 98 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 4.29 was released 1 month, 19 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/SRI'&gt;SRI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/KIMOTO/SPVM-0.990172' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;SPVM&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - The SPVM Language
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;0.990172&lt;/strong&gt; on 2026-05-13, with 36 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 0.990171 was released 2 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/KIMOTO'&gt;KIMOTO&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/JDB/Win32-0.62' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;Win32&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Interfaces to some Win32 API Functions
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;0.62&lt;/strong&gt; on 2026-05-11, with 13 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: 0.61 was released the same day&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/JDB'&gt;JDB&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href='https://metacpan.org/release/TINITA/YAML-LibYAML-v0.907.0' target='_blank'&gt;&lt;b&gt;&lt;span style='font-family: Courier New, Courier, monospace;'&gt;YAML::LibYAML&lt;/span&gt;&lt;/b&gt;&lt;/a&gt; - Perl YAML Serialization using XS and libyaml
&lt;ul&gt;
  &lt;li&gt;Version: &lt;strong&gt;v0.907.0&lt;/strong&gt; on 2026-05-10, with 60 votes&lt;/li&gt;
  &lt;li&gt;Previous CPAN version: v0.906.1 was released 14 days before&lt;/li&gt;
  &lt;li&gt;Author: &lt;a href='https://metacpan.org/author/TINITA'&gt;TINITA&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content>
    <link rel="replies" type="application/atom+xml" href="https://niceperl.blogspot.com/feeds/1351758505306644571/comments/default" title="Enviar comentarios"/>
    <link rel="replies" type="text/html" href="https://niceperl.blogspot.com/2026/05/dc-17-great-cpan-modules-released-last.html#comment-form" title="0 comentarios"/>
    <link rel="edit" type="application/atom+xml" href="https://www.blogger.com/feeds/5910101498857524639/posts/default/1351758505306644571"/>
    <link rel="self" type="application/atom+xml" href="https://www.blogger.com/feeds/5910101498857524639/posts/default/1351758505306644571"/>
    <link rel="alternate" type="text/html" href="https://niceperl.blogspot.com/2026/05/dc-17-great-cpan-modules-released-last.html" title="(dc) 17 great CPAN modules released last week"/>
    <author>
      <name>prz</name>
      <uri>http://www.blogger.com/profile/17989445983340548566</uri>
      <email>noreply@blogger.com</email>
      <gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="https://img1.blogblog.com/img/b16-rounded.gif"/>
    </author>
    <thr:total>0</thr:total>
  </entry>
  <entry>
    <title>Building a Lightweight Debugging Agent</title>
    <link rel="alternate" href="https://dhirajpatra.medium.com/building-a-lightweight-debugging-agent-63da3215c7db?source=rss------perl-5" type="text/html"/>
    <content type="html">&lt;div class="medium-feed-item"&gt;&lt;p class="medium-feed-image"&gt;&lt;a href="https://dhirajpatra.medium.com/building-a-lightweight-debugging-agent-63da3215c7db?source=rss------perl-5"&gt;&lt;img src="https://cdn-images-1.medium.com/max/810/1*6-gibEQ8uOpoKdR20W7dUA.jpeg" width="810"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p class="medium-feed-snippet"&gt;Building a Lightweight Debugging Agent: Python, Perl, and Awk&lt;/p&gt;&lt;p class="medium-feed-link"&gt;&lt;a href="https://dhirajpatra.medium.com/building-a-lightweight-debugging-agent-63da3215c7db?source=rss------perl-5"&gt;Continue reading on Medium »&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;</content>
    <author>
      <name>Dhiraj Patra</name>
    </author>
    <id>https://medium.com/p/63da3215c7db</id>
    <published>2026-05-14T15:26:33Z</published>
    <updated>2026-05-14T15:26:33.481000Z</updated>
    <category term="agentic-ai"/>
    <category term="awk"/>
    <category term="perl"/>
    <category term="python"/>
    <category term="ai-agent"/>
  </entry>
</feed>
