PDL Advent Calendar Day 21: Fun and Games with Images

r/perl

Published by /u/briandfoy on Saturday 21 December 2024 06:00

Perl Advent Calendar 2024 - Day 21 - That Time Perl+OpenMP Saved Christmas

r/perl

Published by /u/briandfoy on Saturday 21 December 2024 05:57

ack 3.8.0 released with --and, --or and --not options

r/perl

Published by /u/petdance on Saturday 21 December 2024 04:55

grep-like code search tool ack has been updated to v3.8.0. It's available on CPAN as App::Ack, or at https://beyondgrep.com/

The big new feature is that you can have boolean matches on the line.

bash ack this --and that --and other and this --or that --or other ack this --not that --not other

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

That Time Perl+OpenMP Saved Christmas

Perl Advent Calendar 2024

Published by oodler on Saturday 21 December 2024 00:00

It was Christmas Eve, and Santa was facing a nightmare. The sleigh’s new GPS system, upgraded for the first time in centuries from following the Star of Bethlehem, was malfunctioning. As Santa checked the screen, the map was a chaotic mess — locations were wrong, some coordinates did not make sense, and the sleigh was heading straight into the mountains instead of over the City of New Orleans!

Santa's CURRENT position read-out indicated he was over the Appalachians at the following coordinates:

  Sleigh Latitude  Sleigh Longitude  Sleigh Altitude (ft)
       38.0000° N        -81.500° W              300

When he should be nearly exactly at,

  Sleigh Latitude  Sleigh Longitude  Sleigh Altitude (ft)
       29.9500° N        -90.070° W              300

"We can't afford this!" Santa shouted. "We’ve got billions of presents to deliver, and the system's down. And I want some gumbo!"

"Santa, we can fix it," Jingles, the lead elf, said with a frantic smile. "We just need more computing power. If we use OpenMP, we can parallelize the calculations and solve this quickly."

Santa stared. “What are you talking about, Jingles? I'm a giant elf, not a Scottish engineer on a television show for nerds!”

“We’ll solve the GPS problem by recalculating the distances to each delivery location. The sleigh’s GPS relies on triangulating data from multiple satellites. Right now, it's too slow to process the data for each location one by one. We can use OpenMP to divide the problem into smaller parts, calculate distances in parallel, and get this fixed fast!”

The data format of the positional satellites consisted of their positions in latitude, longitude, with an altitude; so the computations are necessarily in 3D space, and could contain any number of lines:

The distance formula was computationally expensive, involving square roots and trigonometry. But by using OpenMP, the task could be split into multiple OS threads, each calculating the distance to one satellite at the same time. The results would then be aggregated, and the sleigh's GPS would know exactly where to direct its heading.

The code would parallelize the work by dividing the list of satellites among a number of pthreads using OpenMP's #pragma omp for construct! OpenMP::Simple handles the required #include <omp.h> and makes it easy to query the environment for information, such as OMP_NUM_THREADS.

Jingles quickly typed up a solution in Perl, his favorite programming language. The solution was simple but critically offloaded the triangulation computations to Inline::C code containing OpenMP directives, using the OpenMP module on CPAN.

use strict;
use warnings;

use OpenMP;

use Inline (
    C => 'DATA',
    with => qw/OpenMP::Simple/,
);

my $omp = OpenMP->new;

$omp->env->omp_num_threads($ENV{OMP_NUM_THREADS} // 8); # accept number of threads via commandline

# Sleigh's CURRENT position (latitude, longitude, altitude)
my $sleigh_lat = 38.0000;
my $sleigh_lon = -81.500;
my $sleigh_alt = 300.0; # in meters

# Satellite positions in tab-delimited format
my @satellites = ();
open my $FH, "<", "./satellite-data.txt" || die $!;

foreach my $line (<$FH>) {
  chomp $line;
  push @satellites, [split(/[\s\t]+/, $line)];
}

# Function to calculate distance from sleigh to each satellite using OpenMP::Simple,
# a subclass of Inline::C!
my $distances = calculate_distances($sleigh_lat, $sleigh_lon, $sleigh_alt, \@satellites);

# Print the calculated distances
foreach my $distance (@$distances) {
    print "Distance: $distance meters\n";
}

Santa watched as Jingles split up the computational load. Each satellite’s data was handled in parallel by different threads, and within seconds, the recalculations were done. The GPS latency issues were fixed. Jingles already had some thoughts of improvements he could make using OpenMP's ability to target GPUs directly, but was quite happy with the current resolution.

Just as the final calculations finished, a gentle voice spoke, “When Faith sanctifies morally neutral technology, Good things are possible at Internet scale.”

Santa turned to see the Holy Family - Baby Jesus in the arms of His Virgin Mother accompanied by His foster father, Joseph; by the sleigh, smiling serenely. “Thank you,” Santa whispered. “Merry Christmas.”

With the sleigh back on track, Santa soared into the night sky.

When things settled down, Santa was able to look at Jingles' full code, and it was something to behold!

use strict;
use warnings;

use OpenMP;

use Inline (
    C => 'DATA',
    with => qw/OpenMP::Simple/,
);

my $omp = OpenMP->new;

$omp->env->omp_num_threads($ARGV[0] // 8); # accept number of threads via commandline

# Sleigh's CURRENT position (latitude, longitude, altitude)
my $sleigh_lat = 38.0000;
my $sleigh_lon = -81.500;
my $sleigh_alt = 300.0; # in meters

# Satellite positions in tab-delimited format
my @satellites = ();
open my $FH, "<", "./satellite-data.txt" || die $!;

foreach my $line (<$FH>) {
  chomp $line;
  push @satellites, [split(/[\s\t]+/, $line)];
}

# Function to calculate distance from sleigh to each satellite using Inline::C
my $distances = calculate_distances($sleigh_lat, $sleigh_lon, $sleigh_alt, \@satellites);

# Print the calculated distances
foreach my $distance (@$distances) {
    print "Distance: $distance meters\n";
}

__DATA__
__C__

#include <math.h>

// Function to convert geographic coordinates to Cartesian (x, y, z)
void geo_to_cartesian(double lat, double lon, double alt, double *x, double *y, double *z) {
  double R = 6371000; // Earth's radius in meters
  double lat_rad = lat * M_PI / 180.0;
  double lon_rad = lon * M_PI / 180.0;

  *x = (R + alt) * cos(lat_rad) * cos(lon_rad);
  *y = (R + alt) * cos(lat_rad) * sin(lon_rad);
  *z = (R + alt) * sin(lat_rad);
}

// Function to calculate Euclidean distance between two points (x1, y1, z1) and (x2, y2, z2)
double calculate_distance(double x1, double y1, double z1, double x2, double y2, double z2) {
  return sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2) + pow(z2 - z1, 2));
}

/* C function parallelized with OpenMP */

// Main function to calculate the distances from the sleigh to each satellite
AV* calculate_distances(double sleigh_lat, double sleigh_lon, double sleigh_alt, AV *satellites) {
    int satellite_count = av_len(satellites) + 1; // The number of satellites
    AV* distances = newAV(); // Create a new Perl array (AV) to hold the distances

    double sleigh_x, sleigh_y, sleigh_z;

    // Convert sleigh's geographic coordinates to Cartesian coordinates
    geo_to_cartesian(sleigh_lat, sleigh_lon, sleigh_alt, &sleigh_x, &sleigh_y, &sleigh_z);

    // Fetch satellite data into local arrays
    double *sat_latitudes = malloc(satellite_count * sizeof(double));
    double *sat_longitudes = malloc(satellite_count * sizeof(double));
    double *sat_altitudes = malloc(satellite_count * sizeof(double));

    // Populate satellite data into local arrays (from the Perl array)
    for (int i = 0; i < satellite_count; i++) {
      AV *satellite = (AV*) SvRV(*av_fetch(satellites, i, 0)); // Fetch the satellite at index i
      sat_latitudes[i] = ((double) SvNV(*av_fetch(satellite, 0, 0))); // Latitude
      sat_longitudes[i] = ((double) SvNV(*av_fetch(satellite, 1, 0))); // Longitude
      sat_altitudes[i] = ((double) SvNV(*av_fetch(satellite, 2, 0))); // Altitude
    }

    // Declare a temporary array to hold distances for each thread
    double *_distances = malloc(satellite_count * sizeof(double));

    PerlOMP_GETENV_BASIC // read common environmental variables, provided by OpenMP::Simple

    // Start parallel region
    #pragma omp parallel shared(_distances)
    {
      // Parallel for loop to compute distances in parallel
      #pragma omp for
      for (int i = 0; i < satellite_count; i++) {
          _distances[i] = 0.0; // Initialize

          double sat_x, sat_y, sat_z;

          // Convert satellite's geographic coordinates to Cartesian coordinates
          geo_to_cartesian(sat_latitudes[i], sat_longitudes[i], sat_altitudes[i], &sat_x, &sat_y, &sat_z);

          // Calculate the distance from the sleigh to this satellite
          _distances[i] = calculate_distance(sleigh_x, sleigh_y, sleigh_z, sat_x, sat_y, sat_z);
      }
    }

    // Combine the results from all threads into the main distances array inside the parallel region
    for (int i = 0; i < satellite_count; i++) {
      av_push(distances, newSVnv(_distances[i]));
    }

    // Free the private distance arrays and satellite data arrays
    free(_distances);
    free(sat_latitudes);
    free(sat_longitudes);
    free(sat_altitudes);

    // Return the AV containing the distances to Perl
    return distances;
}

__END__

See More:

https://metacpan.org/pod/OpenMP
https://metacpan.org/pod/OpenMP::Simple
https://metacpan.org/pod/OpenMP::Environment
Everyone is welcome to join the Perl+OpenMP Project at https://github.com/Perl-OpenMP/!

Day 21: Fun and Games with Images

PDL Advent calendar 2024

Published on Saturday 21 December 2024 00:00

If you are manipulating images, you need PDL!

For years, I've had this urge to use PDL to take a bitmap image and trace the outlines to make an SVG file that I could scale up to A0 poster size without the resulting pixelation. Yes, there are already tools that do that, but where's the fun in that? It's Christmas, the time for Fun and Games!

Continue reading...

Tags: image manipulation broadcasting

Cosmoshop supports the German Perl/Raku-Workshop

blogs.perl.org

Published by Max Maischein on Friday 20 December 2024 21:22

We are happy to announce that CosmoShop supports the German Perl/Raku-Workshop.

CosmoShop is the largest pure Perl based shop system.

Since 1997, we have been implementing sophisticated and individual eCommerce projects in the B2B sector with our specially developed store software. We are the central point of contact for the entire spectrum.

CosmoShop ist das weltweit größte rein perlbasierte Shopsystem.

Mit unserer eigens entwickelten Shopsoftware realisieren wir seit 1997 anspruchsvolle und individuelle eCommerce Projekte im B2B Umfeld. Dabei sind wir zentraler Ansprechpartner des gesamten Spektrums.

Randal Schwartz / Half My Life with Perl

The Perl and Raku Conference YouTube channel

Published by The Perl and Raku Conference - Greenville, SC 2025 on Friday 20 December 2024 16:58

I am trying to install the CPAN module DBD::SQLite and I am getting a strange failure. The compilation of several C files into object code goes fine, and then when we hit sqlite3.c the compilation just hangs. The abbreviated command is:

i686-linux-gnu-gcc -c  [...]  sqlite3.c

I'd like confirmation if anyone else could try it; maybe someone using perlbrew?

Here is some version information:

  • gcc version 8.3.0 (Debian 8.3.0-6)
  • DBD-SQLite-1.76
  • Perl v5.40.0

Update Module::CoreList for 5.41.8

Perl commits on GitHub

Published on Friday 20 December 2024 15:09

Update Module::CoreList for 5.41.8
Bump the perl version in various places for 5.41.8

New perldelta for 5.41.7

Perl commits on GitHub

Published on Friday 20 December 2024 14:53

New perldelta for 5.41.7
Perl 5.41.7 was released, update release schedule

Update epigraphs.pod for 5.41.7

Perl commits on GitHub

Published on Friday 20 December 2024 14:39

Update epigraphs.pod for 5.41.7

Use of uninitialized value in pattern match (m//) message

Perl questions on StackOverflow

Published by user12090504 on Friday 20 December 2024 11:56

I have a statement in Perl like

if (($hh, $mm) = ($info{$item}{$p_expectedtime} =~ /(\d+):(\d+)/))

but when compiling, I get the message:

Use of uninitialized value in pattern match (m//)

Tried to add a define() like

if (define($hh, $mm) && ($hh, $mm) = ($info{$item}{$p_expectedtime} =~ /(\d+):(\d+)/))

which is incorrect.

Announcing the 2024 White Camel Award recipient - Olaf Alders

r/perl

Published by /u/davorg on Friday 20 December 2024 09:34

Foswiki 2.1.9 is released

blogs.perl.org

Published by Michael Daum on Friday 20 December 2024 07:56

We are delighted to announce the new release, which includes 57 significant bug fixes compared to the previous 2.1.8 version. This update addresses a range of important issues and enhances the overall stability and performance.

FoswikisLatest_8.png

More details at https://blog.foswiki.org/Blog/Foswiki219IsReleased

PDL Advent Calendar Day 20: Perl Data Language internals

r/perl

Published by /u/briandfoy on Friday 20 December 2024 03:45

PCC Winter '24 Follow-Up - Summer PCC Dates Announced!

blogs.perl.org

Published by Brett Estrade on Friday 20 December 2024 03:26

coffee2_e836892a-6431-40cf-aebf-d0b4eea57547-2852573895.png

Next PCC: July 3-4, 2025 in Austin, Texas USA

See entire the post to learn about our future plans, in perpetuity.

The very first Perl Community Conference was a tremendous success thanks to everyone of you authors and speakers. Many thanks to PCC Co-Organizer Will "The Chill" Braswell, our friends at the Diogenes Hackerspace (in Austin, Texas), and all the participants both online and in person! We'll be following up soon about posting the videos. The next stage will be editing and publishing Issue #2 of the Science Perl Journal. The schedule from the Winter'24 PCC should be a clue about some of its contents. We have discussed offering a "Letters to the Editor" section to address feedback from friends and foes alike. More on this will be announced in future posts.

Future Plans in Perpetuity

Please mark your calendars for both July 3rd/4th (USA's birthday) and December 17th/18th (Perl's birthday), starting in 2025 and going forward every year from now on. Our current plan is to continue meeting in Austin until further notice, as it is a central location and we already have all of the conference equipment there.

As you can see from the dates above, we are expanding to a 2-day format starting with our upcoming PCC Summer 2025, which will begin on July 3rd and run through July 4th, finishing in time for people to get home for fireworks if they so choose. Likewise, we will start our PCC Winter 2025 one day early on December 17th and run through December 18th, giving people enough time to get home for their Christmas holiday travel plans etc.

The 2-day format will give us an opportunity to have more talks, as well as more extra-curricular activities. We want to offer things like Perl job fairs, Perl code hackathons, Perl training courses, and also official group activities on the evenings of July 3rd and December 17th, such as a lake cruise or live theater or dinner-and-a-show etc.

So, please set a permanent annual reminder in your calendar now, repeating every July 3-4 and Dec 17-18 - forever. It is safe to assume the location will be Austin, Tx indefinitely. Together we will put Perl back on top!

Sincerely, Brett Estrade (OODLER) Chairman, Science Perl Committee Co-Editor, Science Perl Journal Co-Organizer, Perl Community Conference

Christmas eve was quickly approaching, and Santa was trying to decide whether to purchase masks for all of the reindeer again this year (he was aware that there were documented cases of SARS-CoV-2 infecting White-Tail Deer (O.virginianaus), and he knew that Reindeer (R.tarandus) were closely related), when the Chief Elf interrupted his train of thought to inform him that two of the elves in workshop were in the infirmary with respiratory distress. Testing had revealed that they were both infected with Respiratory Syncitial Virus (RSV), specifically with the RSVA subtype.

Santa asked "Do we know where they were exposed, or if one of them transmitted it to the other? We may need to require everyone at the North Pole to mask again until after Christmas eve . . . "

"The diagnostic lab says the two viruses are similar but not identical. Also they are not confident of the lineage calls and the clade assignments because we are using a new set of PCR primers designed in Edinburgh, which are based on a newer RSVA reference sequence (RefSeq). The problem is that we are using the RSVA phylogenetic tree available at usher.bio and that tree was built using the NCBI RefSeq as the root. You can see where the problem arises . . . "

Santa thought for a moment and said "Oh, blast! We aligned our fastq reads to the other RefSeq, and at the primer trimming step we are using the genomic coordinates from that different virus strain. So if we first align against the NCBI RefSeq genome (to get more accurate lineage calls and clade assignments) then the primer trimming step will not work as intended. Huh! Hmmm, do you think we could align those two different RSVA RefSeqs to each other and then modify the coordinates in the primer bed file so it uses the NCBI RefSeq's genomic coordinates instead?!?"

The Chief Elf sketched this out on the iceboard and said, "I think this could work. I will ask our bioinformatic software developers to tackle the problem."

And so gentle reader that is how we arrived at a simple, but tedious task of converting the genomic coordinates in this bed file:

  RS20000581      44      66      RSVA_1_LEFT     1       +
  RS20000581      434     464     RSVA_1_RIGHT    1       -
  RS20000581      359     385     RSVA_2_LEFT     2       +
  RS20000581      749     773     RSVA_2_RIGHT    2       -
  RS20000581      669     699     RSVA_3_LEFT     1       +
  RS20000581      1057    1083    RSVA_3_RIGHT    1       -
  RS20000581      990     1016    RSVA_4_LEFT     2       +
  RS20000581      1366    1389    RSVA_4_RIGHT    2       -

So that it would contain the correct coordinates from a different RSVA subtype RefSeq. It quickly became apparent that this problem could be solved much more quickly using the Awesome Power of Perl, unfortunately there was no out-of-the-box solution available in the existing base of Perl code. But how to proceed?

Using the Awesome Power of Perl in Bioinformatics

Each of the two genome files are simple text files consisting of an alphabet of five letters (A, C, G, and T (occasionally an N)) (technically RSV, similar to SARS-CoV-2 is an RNA virus, but life is simpler if we use 'T' instead of 'U'), all we need is a so-called "Global Alignment" of the two full-length sequences (they are each just over 15,000 bases in length). What we really want to know is where all of the longest stretches of identical sequences are located in the viral chromosomes. Fortunately an algorithm to calculate this was published by Needleman and Wunsch back in 1970; it is considered a classic example of dynamic programming (which builds up the answer without consuming vast amounts of memory). Furthermore, the National Center of Biotechnology Information (NCBI) maintains a server we can use to upload any two closely related nucleotide sequences.

The output from the N-W Global Alignment looks like this:

  Query  2177   GTGTGATTAACTACAGTGTATTAGATTTGACAGCAGAAGAACTAGAGGCTATCAAACATC  2236
                |||||||||||||||||||| |||| ||||||||||||||||||||||||||||||||||
  Sbjct  2221   GTGTGATTAACTACAGTGTACTAGACTTGACAGCAGAAGAACTAGAGGCTATCAAACATC  2280

  Query  2237   AGCTTAATCCAAAAGATAATGATGTAGAGCTTTGAGTTAATAAAAAGGTGGGGCAAATAA  2296
                ||||||||||||||||||||||||||||||||||||||||||||||  ||||||||||||
  Sbjct  2281   AGCTTAATCCAAAAGATAATGATGTAGAGCTTTGAGTTAATAAAAAA-TGGGGCAAATAA  2339

Where the the top sequence in each pair is a stretch of 60 bases from the Edinburgh RefSeq (Labeled 'Query') and the bottom sequence in each pair is the matching stretch from the NCBI RefSeq (Labeled 'Sbjct'). The unix pipe symbols denote a perfect match between the sequences at that base.

Notice that the numbering systems are slightly offset, AND that there is a gap introduced with a hyphen in-between the A at 2327, and the T at 2328 in the Sbjct, directly across from the G at position 2384 in the Query. That can be interpreted as a single nucleotide insertion in the Query genome. So creating the mapping table between the two coordinate systems is not trivial. The sequences only share 94 percent identity over about 15,200 nucleotides, which means they diverge 6 percent of the time.

To simplify the construction of our lookup table we can use grep to filter the starting alignment into two different subsets,

grep ^Query nw_alignment.txt > just_rows_from_edinburgh_refseq.txt
grep ^Sbjct nw_alignment.txt > just_rows_from_ncbi_refseq.txt

N.B. you will have to go in and manually remove the first extraneous Query line from the first file. These become the first two input files to our script, the third file is the primer bed file we are starting with.

Our Script that Creates a Lookup Table, and then Swaps Coordinates in a bed File

#!/usr/bin/env perl
use strict;
use warnings;

my $query_input = $ARGV[0];
my $subject_input = $ARGV[1];
my $input_bed = $ARGV[2];

open my ($FH1), '<', $query_input or die "Could not open $query_input for reading\n";
open my ($FH2), '<', $subject_input or die "Could not open $subject_input for reading\n";

my @global_array = ();
$global_array[0] = { query => undef,
       sbjct => undef,
     };

# This global counter serves as the index for the first data structure
# that captures the information at each place in the aligned sequences
my $counter = 0;

# Parse the rows of the first file
while ( <$FH1> ) {
    chomp;
# Each of these filtered rows has the same structure, in addition to
    # A, C, G, and T, the N-W output can also contain hyphens (dashes), so
    # our regex has to include that in the string we are capturing
my ($seq) = $_ =~ m/Query\s+\d+\s+([\w\-]+)\s+\d+/;
# Parse the 60 nucleotide string into individual characters
my @qchars = split(//, $seq);
    foreach my $q ( @qchars ) {
        $counter++;
# Load up the array of hashrefs with the symbols
$global_array[$counter]{query} = $q;
    }
}
close $FH1;


$counter = 0;
while ( <$FH2> ) {
    chomp;
    my ($seq) = $_ =~ m/Sbjct\s+\d+\s+([\w\-]+)\s+\d+/;
    my @schars = split(//, $seq);
    foreach my $s ( @schars ) {
        $counter++;
 $global_array[$counter]{sbjct} = $s;
    }
}
close $FH2;

# Now we process the information in each element of the
# @global_array, and store that in this global hash
# the keys of this hash are genomic coordinates for the
# Edinburgh RSV-A RefSeq and the values are the genomic
# coordinates of the NCBI RSV-A RefSeq
my %ncbi_coordinates_of = ();

my $qcounter = 0;
my $scounter = 0;

# There is nothing useful in the [0] element
foreach my $i ( 1..$#global_array ) {
    my $key = undef;
    my $value = undef;
# If the string from the N-W output contains a '-' then we
    # need to handle those differently. We only increment the
    # $qcounter when the value in 'query' matches a letter
if ( $global_array[$i]{query} =~ m/\w/ ) {
        $qcounter++;
        $key = $qcounter;
        if ( $global_array[$i]{sbjct} =~ m/\w/ ) {
            $scounter++;
     $value = $scounter;
 }
        $ncbi_coordinates_of{$key} = $value;
    }
    else {
 $scounter++;
 next;
    }
}

# After all of that manipulation and data wrangling, the problem now becomes
# very simple. We read in the starting primer bed file and iterate over each
# TSV record. We use the information in columns 2 and 3 to query the
# %ncbi_coordinates_of hash, and insert the coordinates we want from the hash
# values. The modified record is immediately printed to STDOUT

open my ($FH3), '<', $input_bed or die "Could not open $input_bed for reading\n";

while ( <$FH3> ) {
    my @fields = split(/\t/, $_);
# Change the sequence name in column 1
$fields[0] = 'NC_038235.1';
# It is formally possible that either the 'start' or the 'end' of the
    # Query sequence is NOT in the %ncbi_coordinates_of hash, so check for this
unless ( exists $ncbi_coordinates_of{$fields[1]} and exists $ncbi_coordinates_of{$fields[2]} ) {
        $fields[1] = $fields[2] = 'undef';
        print join("\t", @fields);
        next;
    }
# Sometimes the 'start' and 'end' coordinates from the Query sequence ARE keys in the
    # %ncbi_coordinates_of hash, but the corresponding values from the Sbjct sequence are undef
    # so continue processing gracefully when this occurs
$fields[1] = $ncbi_coordinates_of{$fields[1]} //= 'undef';
    $fields[2] = $ncbi_coordinates_of{$fields[2]} //= 'undef';
    print join("\t", @fields);
}
close $FH3;

exit;

Conclusion

When you run the script, save the output to file, and then use grep undef to see if there were any coordinates which could NOT be successfully mapped. If there are any then you can use grep -v undef to save a copy without those lines.

What did we learn? After running this script to create the new primer bed file for the NCBI RSV-A RefSeq, and then rerunning their viral sequencing pipeline to align the amplified reads to the NCBI RefSeq, the bioinformaticians working with the infirmary could see that the two isolates from the workshop elves were more closely related than they had previously thought, but since the viruses still had many mutations separating them, it seemed like these were two separate exposures (or introductions) of RSV-A to the North Pole compound.

You can see that for yourself in this image:

N.B.: In accordance with the laws of Canada, Denmark, and Russia, the clinical metadata and any other personal health information (PHI) for these samples has been de-identified.

These are two versions of the RSV-A Global phylogenentic tree, showing a subtree of the samples that the most highly related to the two sequences from Santa's workshop. The trees are shown rotated 90 degrees, so the "root" of the tree (which is not shown), is on the LEFT. You can see the "branches" as horizontal lines; and at the tips of each branch is a "leaf" (or a node). The leaves represent the sequences from different individual viruses in the database. Each tip is labeled with the name of the sample, and the two samples from the North Pole are colored black. The Y-axis has no units, and is arbitrary. The data depicting similarity is contained in the pattern of the branches (which are technically internal nodes), and in the LENGTH of the branches. The X-axis conveys information about the number of mutations in one sample, which is the number of nucleotide sequence changes that it takes to "get back" to the root of the tree.

Panel A. shows where the UShER program placed the two samples from the North Pole, using the Edinburgh RefSeq genome, whereas Panel B. shows where they were placed after the same samples were aligned to the NCBI RefSeq genome, and the new Primer bed file created with our script was used to remove (or trim) the primers from the end of the reads. You can see that the placement of the Elf_0001 sample is almost the same in the two trees, whereas the placement of the Elf_0002 sample has moved. It is now forking off at a different branch of the tree and is closer (and therefore more similar, or more related) to Elf_0001.

In principal, the flow and the steps used here could work with any paired RefSeqs for a pathogenic virus where you have created DNA sequencing amplicons with PCR primers from one coordinate system, but you want to be able to use your regular pipelines to align the fastq reads to a different RefSeq.

If you have some paired-end fastq files from RSV (or another RNA virus) you can get an idea of the processing steps to use to generate consensus.fasta files here.

During the COVID19 Global Pandemic these consensus.fasta files were essential for constructing the phylogenetic trees used by Epidemiologists to identify outbreaks of new strains.

THM: Best to wear masks at the North Pole until after DEC-24.

Day 20: Perl Data Language internals

PDL Advent calendar 2024

Published on Friday 20 December 2024 00:00

PDL is powerful and has many features. But as with any complex software system, bugs can happen. Let's learn about two!

Continue reading...

Tags: internals implementation dataflow

Why Perl Is a Favorite for Scripting and Automation

Perl on Medium

Published by Mayur Koshti on Thursday 19 December 2024 17:33

Best For Scripting & Automation.

Announcing the 2024 White Camel Award recipient

Perl Foundation News

Published by Makoto Nozaki on Thursday 19 December 2024 17:30

We are pleased to announce Olaf Alders as the White Camel Award 2024 recipient.

Most likely people recognize Olaf as the guy behind MetaCPAN. He co-founded the project in late 2010 as a means to aggregate data for an iOS application. The phone app fizzled, but MetaCPAN took on a life of its own. Olaf has been part of the team working on it ever since. MetaCPAN is a user-friendly search and discovery platform for Perl modules and distributions, based on CPAN (Comprehensive Perl Archive Network).

Olaf is also the person responsible for perl.com’s revival. After the site became inactive for several years, Olaf brought the site back to life. He’s always looking for new contributions. Anyone can submit an article via GitHub.

In 2023, Olaf also took over the Perl Advent Calendar, a long-running tradition previously managed by Mark Fowler, whom we would like to acknowledge for his 20+ years of dedication.

When Olaf is not working on websites, he is spending time with his family and his dog. He enjoys open-water swimming, biking, and running. He is in the pool regularly with his local Masters Swim Club. He is currently recording guitar parts for a post-punk song cycle about Ragnarök.

In his technical work, Olaf also helps to maintain the modules in the libwww-perl organization. He is the author of “perlimports” and several other modules. Olaf is a regular attendee of the Perl Toolchain Summit.

For the award details, see https://whitecamel.org/.

Perl's glob doesn't find a file when I think it should

Perl questions on StackOverflow

Published by AskQuestionsP on Thursday 19 December 2024 17:18

Below is the code which does the processing of lines written in new.txt file.

my $bankNameTest;
my $bankName;
my @lines;

my $document = do {
    local $/ = undef;
    open my $fh, "<", "new.txt"
        or die "could not open $file: $!";
    <$fh>;
};

chomp ($document);
print "$document is doc\n";
@lines = split (/\n/,$document);


foreach my $test (@lines) {
    $bankNameTest=glob ("${test}/wint_nightly_nfarm_*.main.20241216.4262507") ;
    chomp ($bankNameTest);
    print "$bankNameTest is testbankname\n";
    $bankName=`ls -d $bankNameTest | sed -r "s?${var}/??g" | sed -r "s/wint_nightly_nfarm_//g" | sed -r "s/.main.20241216.4262507//g"`;
    chomp ($bankName);
    print "$bankName is the bankName\n";
}

Content of new.txt is :

_qa/SERVFARM/CAPTURE_DB/CaptureViewer/2487964_brd_launch/cap_allegro_view
_qa/SERVFARM/CAPTURE_DB/CaptureViewer/FIND/enh_find/DRC_MARKERS/hierdsn_incomp_entry
_qa/SERVFARM/CAPTURE_DB/CaptureViewer/crossprobe/03_between_cap_allegroviewer/dsn_schm_page

Output coming is:

_qa/SERVFARM/CAPTURE_DB/CaptureViewer/2487964_brd_launch/cap_allegro_view/wint_nightly_nfarm_capture_viewer.main.20241216.4262507 is testbankname
capture_viewer is the bankName
 is testbankname
 is the bankName
_qa/SERVFARM/CAPTURE_DB/CaptureViewer/crossprobe/03_between_cap_allegroviewer/dsn_schm_page_and_part_name_with_special_chars/wint_nightly_nfarm_capture_viewer.main.20241216.4262507 is testbankname
capture_viewer is the bankName

Here, 2nd line of new.txt is not getting processed correctly.

Expected Output:

_qa/SERVFARM/CAPTURE_DB/CaptureViewer/2487964_brd_launch/cap_allegro_view/wint_nightly_nfarm_capture_viewer.main.20241216.4262507 is testbankname
capture_viewer is the bankName
_qa/SERVFARM/CAPTURE_DB/CaptureViewer/FIND/enh_find/DRC_MARKERS/hierdsn_incomp_entry/wint_nightly_nfarm_capture_viewer.main.20241216.4262507 is testbankname
capture_viewer is the bankName
_qa/SERVFARM/CAPTURE_DB/CaptureViewer/crossprobe/03_between_cap_allegroviewer/dsn_schm_page_and_part_name_with_special_chars/wint_nightly_nfarm_capture_viewer.main.20241216.4262507 is testbankname
capture_viewer is the bankName

Not sure what's the issue? Seems to be some character related issue in new.txt. Need to have the output as mentioned in "Expected Output".

Catalyst app UTF-8 encoding doesn't seem to be working

Perl questions on StackOverflow

Published by Chris on Thursday 19 December 2024 16:54

I've noticed that my Catalyst app doesn't seem to be handling non-standard characters correctly - I first noticed this when the RTF text editor app I was using replaced " characters with the “angled” kind at the start / end of a string. I've agonised over this, and have thrown up a new blank Catalyst app with the following index page:

sub index :Path :Args(0) {
    my ( $self, $c ) = @_;

    # Hello World
    #$c->response->body( $c->welcome_message );
    $c->response->body("<h1>Hello World, where's the nearest café</h1>");
    $c->log->debug(sprintf("encoding: %s", $c->encoding->mime_name));
}

This gives the following in my browser:

Browser output

However my Catalyst is version 5.90131, which should be encoding UTF-8 by default, in fact the debug message in the routine gives me: [debug] encoding: UTF-8

Browser shows UTF-8 too in the headers:

Browser encoding

Started pulling my hair out a bit - I'm sure I'm missing something totally obvious, please could someone point me in the right direction! Thanks so much.

I have added use utf8 to the controller, which fixed the page text:

Browser with accented character However, input form fields are still not encoding:

Browser page with filled out form field Entering that form gives:

Form submission result

Half My Life with Perl

Perl Advent Calendar 2024

Published by Randal Schwartz on Thursday 19 December 2024 00:00

I had never met Randal Schwartz before, but when I reached out to him about contributing to year 25 of the Perl Advent Calendar, he immediately agreed. This year I wanted to try some new things and Randal suggested giving a Perl-specific talk which he had given once before, but which was lacking in recording quality. This gave Randal a chance to re-record his talk and it gave the Perl communities a chance to watch in real time. We've never before had a video recording as a Perl Advent article, but I believe quite strongly that this is in the spirit of the Advent Calendar project, which is about giving something back. Also, when I mentioned it to Mark Fowler back in October, he didn't object, so I'll take that as a seal of approval.

-- Olaf Alders

Randal's advance summary of this talk:

    Having been there, at the beginning with Perl, I will recount the early
    days through the modern era (or as much as I can cover in the time
    provided). I’ll deliver first-hand experience of the creation of the Camel
    Book, the Llama book, and the way I invaded comp.unix.questions with Perl 2
    answers so often that people would post “no Perl please”. Oh, and my
    version of the story of the Schwartzian Transform.

If you enjoyed the video below, you may also enjoy the next in the series, which will be presented by Dave Cross: Still Munging Data with Perl. If you are at all interested, please register now, even if you cannot attend, as that will allow us to share the recording URL with you after the fact.

Now, please enjoy Randal Schwartz's "Half My Life with Perl":

Day 19: Twinkle, Twinkle Little Star

PDL Advent calendar 2024

Published on Thursday 19 December 2024 00:00

If you're tracing rays or transforming coordinates, you could be using PDL!

A little knowledge is a dangerous thing. Having seen how to do matrix multiplication on 16 December, the Elf R&D department, headed by Rudolf and Dancer, decided to calculate the sparkle from their baubles. In optics, tracing light rays through bits of glass that act as mirrors and lenses can be done by working through a series of equations or by multiplying matrices and vectors!

Continue reading...

Tags: matrix operations optics thin lenses

Objective Decisions

blogs.perl.org

Published by Saif on Wednesday 18 December 2024 21:11

Prioritisation of Panic

Let me start off by asking the folk on this platform one question. Imagine a scenario that you had lost something important with multiple potential negative consequences. For instance losing a bunch of keys including your car keys, your house keys, your changing room locker keys and a USB stick. What would be the greatest cause for alarm? I suspect that while there may be many possible answers aligned with each individual’s life priorities, the real men in this group know that the most feared is the reaction following the revelation to the wife. For while any calamitous occurrence may be approached objectively, with rationality, reflection and hopefully recovery, this particularly troublesome phase involves heightened emotions, reactivating Mrs Saif’s indelible memories of my many past failings. Objectivity, while desirable in principle, has to deal with such a tainted history.

I won’t elaborate further on my survival. I have survived. Barely. Indeed, over the years I must have acquired as poor an ability to remember traumas, as Mrs Saif is good at recollecting them. I haven’t figured out whether it is a natural self defence mechanism shielding me from PTSD, or whether it is a blessing that with age comes a little deafness, poorer eyesight, slower reactions and a reduced residual capacity of my intra-cranial hard-drive. But either way my poor wife’s vain attempts at reforming me, making me a better me, is met with the resistance caused by my irritatingly chilled attitude, constantly in perpetual denial of any need to change, and being so easily distracted.

This experience may help understand the general antipathy or indeed apathy towards any radical change from that which had been established over years. Objectively, a modern object orientated infrastructure within the core appears desirable. But such a goal is not a well defined endpoint. While there are a number of excellent bolted-on frameworks in CPAN, there are differences in priorities and performances. Entry of this form of modernisation into the core without upsetting core values is always going to difficult.

But this work is even more difficult for the poor core developer working on this task. He relies on feedback, without which he finds himself providing a valuable community service without any indication of what the value of his efforts is to that community.

So I decided, while watching a rubbish, inane but ludicrously popular game show, that for once I will make an effort. Not a personal resolution to be more responsible (apologies to Mrs Saif). I am too old for that malarkey. I will use Object::Pad. I will try and replicate this game in an attempt to learn this new way of programming. I will try two things…Firstly by emulating this game using easily identifiable objects, secondly converting a module I have been using into one using Object::Pad. Then I will report back my personal experience of this style of coding. As a disclaimer, I have only ever used classical packages in Perl so am unable to compare with Moose, Moo, Venus etc. I am also as messy at coding as I am in my head.

Deal or No Deal

Version001.png

A simple game where the player has to only answer one question to win money, while captivating one half of the audience, and mystifying the other half at how this could possibly be called entertainment. It seems simple enough to code. We have a “Game Board” object, containing a series of “Box” objects. The boxes each contain a random “Money” Object. A “Banker” object and the game board interact with the player via Objects representing the “Display” and the keyboard “UI” derived from old packages I have lying around. These objects may each have methods for drawing or undrawing themselves, or sending a message to the player, and responding to the players choices.

My effort has been so far remarkably smooth. Using signatures, auto-magically generated setters and getters has made this a remarkably straight forward and efficient process. The game is not yet complete…the biggest attraction of this game is not the challenges it poses but the “banter” and the suggestion that there is any skill or strategy involved. A reasonable algorithm for identifying what the banker should offer would also be interesting. My next post, once this game is completed, is a little review of how the whole experience has been for me, the visible benefits and drawbacks if any.

“`

Santa will be watching

Perl Advent Calendar 2024

Published by José Joaquín Atria on Wednesday 18 December 2024 00:00

Another busy Christmas period loomed, and the North Pole was tirelessly working to get the final preparations ready. Inside a brightly lit meeting room Santa cleared his throat.

"This is all very interesting, very... *yawn* ...stimulating", he said, picking at some cookie crumbs that fell from his beard to the table. "But how is that going to help us? How does ... absorbability help us deliver gifts?"

"Observability", corrected Ada Slashdóttir, the team's senior elf.

"Yeah, that's what I said", said Santa. "What does it do for us?"

As their platform had started to grow, the elves had struggled to keep track on where the bottlenecks were. And now that they had migrated parts of it to microservices and their platform was becoming more distributed, even the tools they were familiar were starting to become unwieldy.

"We need to have a way to see from the outside how our system behaves internally, Santa", said Ada. "That's observability. So it doesn't directly help us send gifts, but it helps us keep things running smoothly, and that helps us send gifts".

"Isn't that what logs do?", asked Duende Juniorsson, the team's junior elf, who was trying to catch up. "We already have logs in our services. Can't we use those?"

Santa liked logs. Yule logs in particular.

"We can, for sure", said Gnomo Knullpointer, who had recently joined Santa's workshop as a coding elf. "Logs are useful because they have been around forever, so they are well supported. But they have their limitations, specially now that a single request can touch several separate microservices before we are done with it. We'd have to correlate logs across services, which is not easy."

"Correlating logs is difficult, but there are other kinds of telemetry we can use", said Ada. "In particular, we can uses traces to track a request across services. This is called 'distributed tracing'. Let me show you how it works."

Integrating with Mojolicious

Ada then opened the code for the Naught-or-Not service, a Mojolicious application that checked whether a specific child has been naughty or nice:

# Naught-or-Not: the 'naughty or nice' service
use Mojolicious::Lite -signatures;
use Mojo::SQLite;

helper sql => sub { state $sql = Mojo::SQLite->new };

app->sql->migrations->name('santa')->from_string(<<'EOF')->migrate;
-- 1 up
create table naughty (id integer unique, naughty bool);
-- 1 down
drop table naughty;
EOF

get '/is-naughty/:id' => sub ($c) {
    my $id = $c->param('id');
    my $db = app->sql->db;

# If we have a value for this ID, return it

    my $row = $db
      ->select( naughty => ['naughty'] => { id => $id } )
      ->hashes
      ->first;

    return $c->render( json => { naughty => $row->{naughty} } ) if $row;

# Otherwise, generate one and store it before returning

    my $naughty = !!( int rand 2 ); # Randomised naughtiness!

    $db->insert( naughty => { id => $id, naughty => $naughty } );

    $c->render( json => { naughty => $naughty } );
};

"The first thing we'll need to do", said Ada, "is get this code to start generating telemetry data. Traces in particular."

"Wait a second", said Gnomo. "If we start touching the code to generate this telemetry, we run the risk of introducing bugs. Not to mention that we have a lot of code, we'll never be able to do it all by hand..."

Santa was starting to sweat.

"We won't have to. We can use OpenTelemetry to do what is called 'zero code instrumentation', which will get us most of the way there. The first thing we'll need to do is load up the OpenTelemetry::SDK in our application. This will read the configuration from the environment and set things up internally so any telemetry we generate gets exported correctly. And since we are using Mojolicious we can use Mojolicious::Plugin::OpenTelemetry to actually generate telemetry data from our routes, all without actually touching any of the controller code."

use Mojolicious::Lite -signatures;
use OpenTelemetry::SDK;
use Mojo::SQLite;

plugin 'OpenTelemetry';

...

"And that's it?", asked Duende a little disappointed. He was already looking forward to touching a lot of code.

"Pretty much. The rest is just configuration. You can already see this in motion by running the code and telling it to export the traces to the console", said Ada, feeling pedagogic.

$ OTEL_TRACES_EXPORTER=console ./server get '/is-naughty/123'
[2024-12-16 23:24:29.37268] [821150] [trace] [nLc70JabTxup] GET "/is-naughty/123"
[2024-12-16 23:24:29.37288] [821150] [trace] [nLc70JabTxup] Routing to a callback
{
    'attributes' => {
        'client.address' => '127.0.0.1',
        'client.port' => '47534',
        'http.request.method' => 'GET',
        'http.response.status_code' => 200,
        'http.route' => '/is-naughty/:id',
        'network.protocol.version' => '1.1',
        'server.address' => '127.0.0.1',
        'server.port' => '36703',
        'url.path' => '/is-naughty/123',
        'user_agent.original' => 'Mojolicious (Perl)'
    },
    'dropped_attributes' => 0,
    'dropped_events' => 0,
    'dropped_links' => 0,
    'end_timestamp' => '1734391469.37503',
    'events' => [],
    'instrumentation_scope' => {
        'name' => 'server',
        'version' => ''
    },
    'kind' => 2,
    'links' => [],
    'name' => 'GET /is-naughty/:id',
    'parent_span_id' => '0000000000000000',
    'resource' => {
        'process.command' => './server',
        'process.command_args' => [
            'get',
            '/is-naughty/123'
        ],
        'process.executable.name' => 'perl',
        'process.executable.path' => '/home/user/.perl/perls/perl-5.40.0/bin/perl',
        'process.pid' => 821150,
        'process.runtime.name' => 'perl',
        'process.runtime.version' => 'v5.40.0',
        'telemetry.sdk.language' => 'perl',
        'telemetry.sdk.name' => 'opentelemetry',
        'telemetry.sdk.version' => '0.024'
    },
    'span_id' => '3823100b9ca26a91',
    'start_timestamp' => '1734391469.3732',
    'status' => {
        'code' => 0,
        'description' => ''
    },
    'trace_flags' => 1,
    'trace_id' => '795c45630d3615ba1ebf524661bf01ac',
    'trace_state' => ''
}

A wall of text (pretty printed here for clarity) appeared in front of the elves. Santa seized the opportunity to look like he knew what was going on by looking at the text in silence while thinking about what to have for lunch.

After a couple of seconds Gnomo and Duende had pieced it together. It was all there! Data about the request itself, how long it took, where it came from, and even details about what code had generated it... and all of that without having to touch any of the core logic!

"This is very cool", said Gnomo, who had been reading through OpenTelemetry::Guides::Quickstart and was already making sense of things. "And it seems we can get even more data if we load some of the instrumentation libraries that are already out there. This route uses a database, so we could use the OpenTelemetry::Instrumentation::DBI to get DBI to also generate telemetry".

use Mojolicious::Lite -signatures;
use OpenTelemetry::SDK;
use OpenTelemetry::Instrumentation 'DBI';
use Mojo::SQLite;

plugin 'OpenTelemetry';

...

Now running the test command printed even more output, this time including traces for all the DB operations, including the ones that executed when the service initially came up and ran the database migrations, etc.

"What about our other services? Not all of them are using Mojolicious", said Duende, thinking that maybe then he'd have the chance to touch some code.

Integrating with Dancer2

Ada loaded up the code for the Gift Allocation service, which was implemented in Dancer2. This service made a call to Naught-or-Not to check whether this child had been naughty, and allocated either a lump of coal or one of the gifts from the child's wishlist.

package Gift::Assignment;

use Dancer2;
use HTTP::Tiny;

set serializer => 'JSON';

my $ua = HTTP::Tiny->new;

post '/gift/assign' => sub {
    my $id = body_parameters->get('id');
    my $res = $ua->get("$ENV{NAUGHT_OR_NOT_HOST}/is-naughty/$id");

    unless ( $res->{success} ) {
        status $res->{status};
        return { error => $res->{reason} };
    }

    my $body = decode_json $res->{content};
    return { gift => 'coal' } if $body->{naughty};

    my @wants = body_parameters->get_all('wants');
    { gift => $wants[ int rand @wants ] };
};

"Like with the Mojolicious service, integrating this with OpenTelemetry requires no code changes", said Ada. Duende's heart sank. Was he going to get to touch any code? "All we need to do is load the Dancer2::Plugin::OpenTelemetry plugin".

"And like with the DBI instrumentation, since this route is using an HTTP client, we can load OpenTelemetry::Instrumentation::HTTP::Tiny to get telemetry for the requests it makes!", chimed in Gnomo, who was neck-deep in the documentation for instrumentation libraries and getting very excited.

The import list now looked like this:

package Gift::Assignment;

use Dancer2;
use Dancer2::Plugin::OpenTelemetry;
use OpenTelemetry::Instrumentation 'HTTP::Tiny';

set serializer => 'JSON';

...

"Hold on a second... what happened to the HTTP::Tiny import?", asked Duende, who was trying to follow along to find ways to contribute.

"Oh, well that's done automatically when we load the instrumentation library, so we don't need to write that twice", said Ada".

"And what about the OpenTelemetry::SDK import? Don't we need it here as well?", continued Duende.

"Ah, well spotted, Duende!", replied Ada. "We do need it, but we only need to load it once. Since this service will have more controllers once it's finished, loading it in each one would be a hassle, so it's better to load it once at the entry point. In this case, since we are using Plack to mount it, we can load that in the top-level PSGI file".

#!/usr/bin/env perl

use strict;
use warnings;
use lib 'lib';

use Gift::Assignment;
use OpenTelemetry::SDK;
use Plack::Builder;

builder {
    Gift::Assignment->psgi_app;
}

Once again they tested it. They brought up the server configured to send traces to the terminal, and made a request:

$ curl -X POST \
    -H 'Content-Type: application/json' \
    -d '{"id":123, "wants":["teddy_bear", "crochet"]}' \
    http://localhost:5000/gift/assign

As the traces appeared in the logs now for both services, Gnomo spotted something. "Hey look! Ignore everything in the traces except for those span and trace IDs". Pretty printed for your convenience, this is what he was looking at:

    naught-or-not  | {
      'name' => 'SELECT "naughty" FROM "naughty" WHERE "id" = ?',
      'parent_span_id' => '88b066b24f372f39',
      'span_id' => '932cf74c171b705e',
      'trace_id' => '16073bf43d281a0693ec7d5a9f4860a4',
    }
    naught-or-not  | {
      'name' => 'GET /is-naughty/:id',
      'parent_span_id' => '7bd198e5a6ddd5fd',
      'span_id' => '88b066b24f372f39',
      'trace_id' => '16073bf43d281a0693ec7d5a9f4860a4',
    }
    gifts          | {
      'name' => 'GET',
      'parent_span_id' => 'd9718758cefd39d4',
      'span_id' => '7bd198e5a6ddd5fd',
      'trace_id' => '16073bf43d281a0693ec7d5a9f4860a4',
    }
    gifts          | {
      'name' => 'POST /gift/assign',
      'parent_span_id' => '0000000000000000',
      'span_id' => 'd9718758cefd39d4',
      'trace_id' => '16073bf43d281a0693ec7d5a9f4860a4',
    }

Santa wondered if this is what it felt like to see the woman in the red dress.

"What are we looking at?", said Duende.

"They are all linked!", replied Gnomo excitedly. "They have the same trace_id, and the parent_span_id in each one is the same as the span_id of the one that came before it, which appears lower in the logs".

"Well, except for that one at the bottom. That one just has a bunch of zeroes as the parent_span_id", commented Duende.

"Yes, that is called the root span", said Ada. "The fact that it has a null parent_span_id tells us that this is the span that initiated the trace".

"We could write something that would aggregate these data and present them in a neater way", said Gnomo. "Maybe something using a kind of flamegraph like the ones from Devel::NYTProf, which are great".

"We don't have to!", said Ada. "The OpenTelemetry project has already done that for us. We can use the OpenTelemetry Collector to aggregate all sorts of telemetry data generated via OpenTelemetry and then configure it to send that data to whatever external service or platform we want".

"Oh, so it's vendor agnostic too?", said Gnomo. "That's very good".

Santa's eye twitched at the mention of "agnostic". This was a touchy subject in the North Pole. He looked at Helga Hakrniüs, the Public Relations elf in the corner of the room who quietly shook their head. Santa let his breath out and wiped his brow.

"Yes, that's one of OpenTelemetry's key selling points", said Ada. "Vendor agnostic on the consumer side, and platform agnostic on the producer side, so you can use it in services written not only in all sorts of frameworks like we just saw, but also in all sorts of languages. They even have a demo application where you can see this in motion".

"Is this true for Perl as well?", said Gnomo. "We can obviously use it in Mojolicious and Dancer2, but what about other frameworks, like Catalyst? I heard that's what the Milk-and-Cookies team was using for their service. Or plain CGI? We still have a bunch of those in the older parts of the code".

"Yes!", said Ada. "The Perl implementation is relatively new, so there's still work to do, but we do have Plack::Middleware::OpenTelemetry that we can use for any server that uses Plack. The integration might not be as close, but it does work. And it's only a matter of time before more instrumentation libraries get released".

"So how do we use this Collector?", asked Duende.

"I'm glad you asked", replied Ada.

From the terminal to the browser

"The OpenTelemetry distribution on CPAN has an example collector stack that we can use to see how things go together", continued Ada. "There is also a similar example managed by the developers of the collector itself, and a more realistic example in the OpenTelemetry demo I mentioned before. We can use the one from CPAN to illustrate things for now".

git clone https://github.com/jjatria/perl-opentelemetry
cd perl-opentelemetry/examples/collector
docker compose up --build

"And then we tell the services to talk to it?", asked Gnomo.

"Yes", said Ada. "We need to set a couple of environment variables for each deployment so that they can talk to the collector. It's probably easier to show this with a docker compose file".

services:
  naught-or-not:
    build:
      context: mojo
    container_name: naught-or-not
    volumes:
    - ./mojo:/app
    command:
    - hypnotoad
    - ./server
    - --foreground
    environment:
      IO_ASYNC_LOOP: Mojo
      OTEL_BSP_MAX_EXPORT_BATCH_SIZE: 1
      OTEL_EXPORTER_OTLP_ENDPOINT: http://localhost
      OTEL_SERVICE_NAME: naught-or-not
      OTEL_TRACES_EXPORTER: otlp
    network_mode: host

  gifts:
    build:
      context: dancer
    container_name: gifts
    volumes:
    - ./dancer:/app
    command:
    - plackup
    - --server
    - Net::Async::HTTP::Server
    - ./server.psgi
    environment:
      NAUGHT_OR_NOT_HOST: http://localhost:8080
      OTEL_BSP_MAX_EXPORT_BATCH_SIZE: 1
      OTEL_EXPORTER_OTLP_ENDPOINT: http://localhost
      OTEL_SERVICE_NAME: gifts
      OTEL_TRACES_EXPORTER: otlp
    network_mode: host

"In both cases we need to set OTEL_SERVICE_NAME to something meaningful so we can identify where the traces come from. We also need to set OTEL_TRACES_EXPORTER to otlp, which is the protocol used by the collector, and OTEL_EXPORTER_OTLP_ENDPOINT to the host that we are sending the telemetry to. In this case, both of these are set to their default values, but it's good for now to be explicit".

"What about that OTEL_BSP_MAX_EXPORT_BATCH_SIZE?", asked Duende. He had already learned the hard way that a batch of one was a little pointless.

"Oh, that's only for testing. In a realistic scenario we can increase that to limit the number of requests that we make to the collector", said Ada.

"So the communication with the collector happens off-band?", asked Gnomo.

"Yes. When exporting to the console we got each span as it was produced, but in a production environment you'd expect many times more spans to be produced, and it would be very expensive to export each one as it came. It's more efficient to batch them and send them all together when enough of them are ready. The Perl OpenTelemetry implementation uses a batch span processor written on top of IO::Async to do this".

Santa wondered if his elves lived in the same planet as he did. He was glad there were people in the room who knew about this so he didn't have to.

"Is that why we need the IO_ASYNC_LOOP variable in the Mojolicious environment?", asked Gnomo.

"Yes", said Ada. "We need that because Mojolicious has its own event loop, so we need to tell IO::Async to use it".

"I see. And that's why in the Dancer2 environment we use Net::Async::HTTP::Server, because Dancer2 doesn't have an event loop, and this gives it one", said Gnomo.

"Exactly", said Ada. "And now, if we run this so it talks to the collector stack, and make some queries, we can see the traces in our browser. That stack connects the collector to a Jaeger instance, which we should be able to see at http://localhost:16686".

"Incidentally", said Ada, "I've put all the files for what we've been talking about in a repository you can check out if you want to run things yourself".

Santa was happy to finally be able to see some pretty pictures. And as he looked at his elves, all excitedly looking around and exploring the data, he felt a warm sense of pride and joy to see them learning and growing and getting things done.

With this out of the way, he could finally get back to what mattered most: having those milk and cookies.

Day 18: How to use PDL to draw a Mandelbrot Set

PDL Advent calendar 2024

Published on Wednesday 18 December 2024 00:00

How to use PDL to draw a Mandelbrot Set

Introduction

The Mandelbrot set is a popular fractal plot that makes for great visualizations and animations, besides its scientific uses.

I will not delve into it deeply, but the link above points to a computer algorithm that is written in Python on Wikipedia. However, if you want to make that algorithm actually intuitive and more identical to the mathematical equations, you want to use PDL for it.

PDL allows for n-dimensional arrays to be created out of the box and manipulated on, as you would do in more mathematical but slower tools like MATLAB or Mathematica.

In this post, I demonstrate how to go about implementing a Mandelbrot visualization, including multibrot ones.

Continue reading...

Tags: mandelbrot visualization

Perl DBI with Mariadb Maxscale

Perl questions on StackOverflow

Published by gatorreina on Tuesday 17 December 2024 21:23

I have set up a Mariadb Maxscale (1 Primary and 2 Replicas) replication cluster for experimentation purposes. As I understand it the main purpose for using Maxscale is that it decides what server to query. Accordingly, I am unsure how to direct my DBI query to Maxscale instead of a specific server.

I usually use Perl DBI to connect to databases in the following manner;

my $dbh = DBI->connect("DBI:mysql:database=$db_name};$server",$user,$passwd);

Can someone tell me how to do this with Maxscale?

maxctrl list servers
┌─────────┬─────────────┬──────┬─────────────┬─────────────────┬──────────┬─────────────────┐
│ Server  │ Address     │ Port │ Connections │ State           │ GTID     │ Monitor         │
├─────────┼─────────────┼──────┼─────────────┼─────────────────┼──────────┼─────────────────┤
│ server1 │ 192.168.0.2 │ 3306 │ 0           │ Master, Running │ 0-2-1438 │ MariaDB-Monitor │
├─────────┼─────────────┼──────┼─────────────┼─────────────────┼──────────┼─────────────────┤
│ server2 │ 192.168.0.3 │ 3306 │ 0           │ Slave, Running  │ 0-2-1438 │ MariaDB-Monitor │
├─────────┼─────────────┼──────┼─────────────┼─────────────────┼──────────┼─────────────────┤
│ server3 │ 192.168.0.4 │ 3306 │ 0           │ Slave, Running  │ 0-2-1438 │ MariaDB-Monitor │
└─────────┴─────────────┴──────┴─────────────┴─────────────────┴──────────┴─────────────────┘

I seem to be able to connect as I can do:

$ mysql -h 192.168.0.1 -umaxscale -ppasswd -P4006 -e 'SHOW DATABASES;'
+--------------------+
| Database           |
+--------------------+
| admin              |
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| test               |
+--------------------+

I just can't figure out how to successfully query via Perl DBI.

My Python Language Solution to Task 2: Nested Array from The Weekly Challenge 300

dev.to #perl

Published by Robert McIntosh on Tuesday 17 December 2024 20:53

1. Introduction

The Weekly Challenge, organized by Mohammad S. Anwar, is a friendly competition in which developers compete by solving a pair of tasks. It encourages participation from developers of all languages and levels through learning, sharing, and having fun.

Task 2: Nested Array from The Weekly Challenge 300 prompts developers to find the longest nested array length.

The Weekly Challenge 300 deadline is Sunday, December 23, 2024 at 23:59 (UK Time). To avoid bias, please consider reading this post after competing.

2. Task 2: Nested Array

You are given an array of integers, @ints of length n containing permutation of the numbers in the range [0, n-1].

Write a script to build a set, set[i] = ints[i], ints[ints[i]], ints[ints[ints[i]]], ... subjected to the following rules:

  1. The first element in set[i] starts with the selection of elements ints[i].
  2. The next element in set[i] should be ints[ints[i]], and then ints[ints[ints[i]]], and so on.
  3. We stop adding right before a duplicate element occurs in set[i].

Return the longest length of a set set[i].

The Weekly Challenge 300, Task 2: Nested Array

Example 1 and Example 2 present the expected outputs for given inputs.

Example 1

Input: @ints = (5, 4, 0, 3, 1, 6, 2)
Output: 4

Here one of the longest sets is set[0]:

set[0] = {ints[0], ints[5], ints[6], ints[2]} = {5, 6, 2, 0}

Example 2

Input: @ints = (0, 1, 2)
Output: 1

3. My solution

def build_set_from_index(ints, starting_index):
    iset = [
            ints[starting_index],
            ]
    for ints_index in range(1, len(ints)):
        pindex = iset[ints_index - 1]
        value = ints[pindex]
        if value in iset:
            break
        iset.append(value)
    return iset

def return_longest_length(ints):
    max_length = 0
    for i in range(0, len(ints)):
        iset = build_set_from_index(ints, i)
        iset_length = len(iset)
        if iset_length > max_length:
            max_length = iset_length
    return max_length

My solution utilizes two functions build_set_from_index and return_longest_length.

build_set_from_index

build_set_from_index returns the set[starting_index] constructed from the parameters ints and starting_index. I used an iterative approach to construct set[].

My approach emerged from an early morning and a subsequent paraphrasing of the set[] construction rules. Initially, these rules seemed complex. But, after re-reviewing Example 1 after a decent breakfast and caffeine, I better understood these rules. I was also able to formulate the following paraphrase.

  • set[i] is a set with k elements.
    • Rule 3 bounds the value of k.
    • Rule 3 dictates when to stop adding elements to set[i].
  • The value of set[i] at k = 0 is equal to ints[i].
  • For k > 0, the k-th element of set[i] is equal to value of ints[] indexed using the (k-1)-th element of set[i].

Using the paraphrased approach, interatively constructing set[0] from @ints, as in Example 1, became even more straightforward!

  • At k = 0, the value of set[0] is equal to ints[0] = 5. set[0] contains {5}.
  • At k = 1, the value of set[0] is equal to ints[5] = 6. set[0] contains {5, 6}.
  • At k = 2, the value of set[0] is equal to ints[6] = 2. set[0] contains {5, 6, 2}.
  • At k = 3, the value of set[0] is equal to ints[2] = 0. set[0] contains {5, 6, 2, 0}
  • At k = 4, STOP because set[0] contains ints[0] = 2.

return_longest_length

return_longest_length finds the maximum length of all set[] constructed from ints. It utilizes build_set_from_index to generate set[k] for each 0 <= k < len(ints) and then indentifies the set[k] with the longest length.

4. Conclusion

In this post I discussed Task 1: Nested Array and I presented my solution. My solution is straightforward, was largely informed by how I paraphrased the original task, and highlights the importance of a good breakfast.

1. Introduction

The Weekly Challenge, organized by Mohammad S. Anwar, is a friendly competition in which developers compete by solving a pair of tasks. It encourages participation from developers of all languages and levels through learning, sharing, and having fun.

Task 1: Beautiful Arrangement from The Weekly Challenge invites developers to find the number of beautifully arranged permutations from among all permutations generated from a positive integer.

In this post I discuss, and present my solution to, Task 1: Beautiful Arrangement, and end a brief conclusion.

The Weekly Challenge 300 deadline is Sunday, December 23, 2024 at 23:59 (UK Time). To avoid bias, consider reading this post after competing.

2. Task 1: Beautiful Arrangement

You are given a positive integer, $int.

Write a script to return the number of beautiful arrangements that you can construct from $int.

A permutation of n integers, 1-indexed, is considered a beautiful arrangement if for every i (1 <= i <= n) either of the following is true:

  1. permutation[i] is divisible by i
  2. i is divisible by permutation[i]

The Weekly Challenge 300, Task 1: Beautiful Arrangement

Examples 1 and 2 present the expected outputs from given inputs.

Example 1

Input: $n = 2
Output: 2

For n = 2 and with i integers such that (1 <= i <= n) there are two permutations (1, 2) and (2, 1). Output: 2 because both meet the beautiful arrangement requirements.

The permutation (1, 2) is a beautiful arrangement because all of its elements match the first condition:

  • At i = 1, permutation[1] = 1 satisfies the first condition, since one is divisible by one.
  • At i = 2, permutation[2] = 2 satisfies the first conditions, since two is divisible by two.

The permutation(2, 1) is also a beautiful arrangement because all of its elements match either the first or second condition:

  • At i = 1, permutation[1] = 2 satisfies the first condition, since two is divisible by one.
  • At i = 2, permutation[2] = 1 satisfies the second condition, since two is divisible by one.

Example 2

Input: $n = 1
Output: 1

Example 3

Input: $n = 10
Output: 700

3. My solution to Task 1

from itertools import permutations

def generate_permutations(n)
    iterable = list(range(1, n + 1))
    return permutations(iterable)

def count_beautiful_arrangements(perms):
    num_beautiful_arr = 0
    for perm in perms:
        is_beautiful_arr = True
        for value_index, value in enumerate(perm):
            if value % (value_index + 1) == 0:
                continue
            elif (value_index + 1) % value == 0:
                continue
            else:
                is_beautiful_arr = False
                break
        if is_beautiful_arr == True:
            num_beautiful_arr += 1
    return num_beautiful_arr

My inelegant and unsophisticated solution utilizes two functions generate_permutations and count_beautiful_arrangements.

generate_permutations returns, for the parameter n, all permutations for the set where 1 <= i <= n.

  • iterable = list(range(1, n + 1)) generates a list of integers where 1 <= i <= n.
  • permutations(iterable), imported from the itertools module, generates all permutations of iterable.

count_beautiful_permutations returns, for the permutations iterable perms parameter, the total number of permutations in perms that match the beautiful arrangement conditions.

  • The outer loop for perm in... iterates through each permutation.
  • It starts with the assumption that perm is a beautiful arrangement (is_beautiful_arr = True).
    • The inner loop for value_index, value in... checks if each element of perm matches either condition 1 or condition 2.
      • If all elements match either condition, perm is counted as a beautiful arrangement.
      • Otherwise, if any element matches neither condition 1 nor condition 2, then is_beautiful_arr is set to False, the loop breaks early and perm is not counted as a beautiful arrangement.

4. Conclusion

In this post I discussed Task 1: Beautiful Arrangement and I presented my solution. My 'inelegant and unsophisticated' solution works, but it has considerable room for improvement.

Annotating Christmas Trees

Perl Advent Calendar 2024

Published by E. Choroba on Tuesday 17 December 2024 00:00

Lesser-known businesses

Everybody knows that the North Pole™ produces and delivers Christmas gifts, but it’s not the sole business they’re into. In fact, they’ve recently engaged in production of Christmas ornaments and Christmas cards, too.

As is common, starting a new business brings new problems. The elves needed a way to design decorated Christmas trees to evaluate their ornament proposals and their combinations. They started by planting small trees and decorating them by hand, but quickly found out this approach didn’t scale as more and more (and bigger and bigger) trees were needed.

At a C-level meeting, Santa listened to laments of the managing elf responsible for the ornaments and narrowed his eyes at another young elf at the other corner of the table.

“You had something for arranging trees, right?” asked Santa.

“Yes, but…” spluttered the elf.

“Let’s meet after lunch and see how we can share the knowledge,” commanded Santa.

There’s trees and there’s trees

In the afternoon (by the way, it was already dark, since it was the North Pole and summer was over) Santa met with the COO and CCO (where the second letter stands for Ornaments or Cards, respectively).The CBO (Chief Baubles Officer) was missing as his department was merged with the Ornaments in the last workforce shaping to trim the fat.

“Can you show us what your department uses to visualise trees?” asked Santa, turning to the CCO.

“Our developers found this open source tool called TrEd, which stands for ‘Tree Editor’,” replied the elf. “And they’re still discovering new features it has. You can do much more than view the trees: you can easily change their structure, add attributes to nodes and edges, add secondary relations that turn the trees into full graphs, and there are also tools for searching large treebanks.”

“I hate the jargon,” muttered Santa and turned to the COO, “but I guess you’re following.”

“Actually, not really,” replied the COO, “we need to arrange the ornaments, but we don’t want to change the structure of the trees. How is such a thing needed to produce a Christmas card, anyway?”

“We hear similar questions often,” said the CCO keeping a stiff upper lip. “At the beginning, we only produced English Christmas cards, so we didn’t need anything like that. But several years ago we started printing the cards in other languages, too, and we needed a way to translate all the greetings and wishes. We started with elvish translators, but we found ourselves in your boots, so to say: the approach didn’t scale.

“We needed an automated process. We reached for statistical machine translation, but for that, we needed large aligned corpora in both the source and target languages.”

“Corpora?” asked Santa raising an eyebrow.

“Large collections of texts. And we quickly found out aligning the individual words wasn’t enough, as the grammar in various languages can change the words in different roles. The sentence structure stays usually much more similar across languages than individual words and their order. That’s why we started annotating the trees.”

“Decorating,” said Santa and nodded to the COO hopefully.

“No, annotating,” explained the CCO. “I’m talking about trees in the graph-theory sense. We arrange the words in a sentence to a tree and annotate the relations between them with their syntactic roles: this word is a subject of this verb, that word is an adverbial of that word,” and he started to gesticulate wildly.

“Wait, wait,” the COO interrupted him, “can you show us what you’re talking about? I still have no idea.”

“Ho ho ho,” said Santa, “a picture is worth a thousand words!”

Diving deeper

The CCO opened his ChristmasPad and typed something into a terminal. “See? This is Ukrainian, by the way.”

“That’s impressive,” admitted Santa, “but I fear there’s some kind of confusion.”

“Let’s have a look at a simpler example in English,” replied the CCO and quickly typed on the keyboard. “The annotated sentence is Is that Microwave that you gave Dan really expensive?

“You can see the pronoun that references the word microwave, and the word microwave is an object of the verb give in a semantic sense which we can also capture.”

“No, no,” tried Santa to stop him, “linguistics is not our concern.”

“That”s great!” rejoiced the CCO. “I’ve always wondered whether TrEd can be used outside of linguistics. There already is one such use: The tree editor serves as a client to a search engine. You assemble a tree and the engine searches your tree data to find where the tree would fit. The trick is you can specify different relations than the ordinary parent–child one.”

“Ho ho ho,” nodded Santa, “Christmas is a family time!”.

“I mean this,” explained the CCO and again showed them his screen.

“Normally, the parent would be at the top, but here, we’re using the reversed relation, so the query will search for all nominal subjects whose parent is not a verb.”

“How can something that’s not a verb have a subject?” wondered Santa.

“Let me show you the English example with the microwave again. The Universal Dependencies style uses adjectives in copula constructions as parents of the subject and the auxiliary verb. The word expensive is not a verb, but the microwave is its nominal subject.”

“I fear this whole thing is of no use for us,” sighed the COO. “What programming language is the tool written in?”

“Perl,” replied the CCO. “It uses Tk::Canvas to edit the trees, which makes it rather easy to extend if you need more features.”

“At least something our team would understand. And the search engine is also written in Perl?” asked the COO again.

“There are in fact two implementations,” replied the CCO. “One uses SQL on Postgres to store and query the data, but it’s only suitable for data that don’t change, as updating the database is quite slow. The second implementation uses Perl and is great for querying frequently changing data. If the data are large, you need some kind of parallelism to compensate its less favourable speed, we run it over slurm. But you can also write your queries directly in Perl. This will show you exactly the same trees as the query I showed you before.” And he again used the terminal.

btred -N -T -e '
    FPosition()
        if $this->{deprel} eq "nsubj"
        && $this->parent->{upostag} ne "VERB"
    ' data/*.conllu | tred -l-

“Also, if you need to process the data without all the power TrEd offers, you can just use Treex::PML, the library that TrEd is based on. It implements the Prague Markup Language used as TrEd’s native data format. The previous five-liner turns almost into a screenful,” and he opened Elven Mate at Creating Scripts (EMaCS) and started to type, interrupted several times by squinting into the documentation.

#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };

my $ud_path;
BEGIN { $ud_path = $ENV{UD_DIR} }

use lib "$ud_path/libs";

use Treex::PML qw{ ImportBackends AddResourcePath };

my @backends = ImportBackends('UD');
AddResourcePath("$ud_path/resources");

my $schema = 'Treex::PML::Factory'->createPMLSchema({
    use_resources => 1,
    filename => "ud_schema.xml"});

for my $file (@ARGV) {
    my $doc = 'Treex::PML::Factory'->createDocumentFromFile(
        $file, {backends => \@backends});

    my $tree_no = 1;
    for my $tree ($doc->trees) {
        my $node_no = 1;
        for my $node ($tree->descendants) {
            say "$file##$tree_no.$node_no"
                if $node->{deprel} eq "nsubj"
                && $node->parent->{upostag} ne "VERB";
            ++$node_no;
        }
        ++$tree_no;
    }
}

No happy ending?

“It’s interesting, but I don’t see how our department could benefit from it,” shrugged the COO.

Santa seemed lost in thought. “Maybe your department can’t,” murmured he, “but we have many other departments that need solutions…”

He dismissed the meeting by pointing at the door and strode towards his office. Can you think of a way how you could benefit from the tool?

Day 17: New operations for Perl Data Language

PDL Advent calendar 2024

Published on Tuesday 17 December 2024 00:00

If you want to create new PDL operations, it's easy! You can make an ad-hoc one with Inline::Pdlpp, and expand it (or just start) by using pptemplate.

Continue reading...

Tags: inline-pdlpp pptemplate create operation

London Perl & Raku Workshop 2025 + 2024 Feedback

blogs.perl.org

Published by London Perl Workshop on Monday 16 December 2024 14:10

Do you want LPW to happen again in 2025? Then you need to make it happen. You need to start thinking about this now. After Lee's closing talk, which detailed how organisation of the 2024 workshop worked and effectively put out a call for organisers for the future, a small number of attendees hinted they would be able to help out in one way or another. For that we are grateful.

However there is no core organising team yet for 2025. Someone, ideally two or three people, need to step up and explicitly say "we are going to organise LPW 2025". If you need help around any of this then we (the 2024 organisers) can guide you. The TPRF have also said they would like to explore how to support LPW 2025 and welcome potential organisers to join the monthly community meeting to discuss this.

Failing that LPW will be going on an indefinite hiatus again.

Responding to the 2024 feedback

Roughly one fifth of the attendees completed the feedback form, I'm showing the results here and will respond to (paraphrased-to-reatain-anonymity) feedback below.

Screenshot 2024-11-25 at 19.19.01.png

Screenshot 2024-11-25 at 19.19.14.png

I think it's clear that a variety of subjects is beneficial, with Perl still having the core focus. I should also say that I hope it was relatively clear that if you didn't attend certain topics then you pick the "did not attend" option not the "not useful" option (you don't know if something is useful or not unless you attend it). I don't know if that was the case though and there was some gaming of the form, which was a bit... well, whatever.

Screenshot 2024-11-25 at 19.19.27.png

I think this is fair - as I explained in my talk, the venue is always a set of compromises and here I think we found the correct ones. Catering is a bonus, we could have spent more but decided not to. The size issue was probably the difference between the two rooms, which I cover below.

Screenshot 2024-11-25 at 19.20.00.png

I think it's clear here as well that most people are satisfied with the current setup. Maybe there's some demand or appetite to have a longer workshop (2 days) but not enough for demand to change this. Most comments about the above essentially confirmed what we suspected (or Lee asked/questioned in his talk).

Screenshot 2024-11-25 at 19.19.46.png

Well that's nice to know, thanks. And we also got positive feedback and thanks in the form as comments, so thanks for that as well. Below I'll respond to some suggestions, comments, and so on.

Acoustics in ballroom could be better / Some sound issues - yes, it was maybe down to the nature of the space.

The Library was too small for some talks. Mayby make it clear the size of the room will be selected based on signups so people pay more attention? / Second track was sometimes too full - When announcing the schedule I made it clear that attendees need to mark talks they plan to see in advance so we can choose the right rooms. In fact, it was the second sentence of the announcement. This was cross posted to the usual places. I did the same in another post a bit later. I don't know how I can make it clearer. This is always a problem at multi track events, I think we do OK. Roughly 50% of attendees marked their talks.

It was hard to find the venue, as it was tucked back and not obvious. - The workshop site had details of the venue, including a map. We had signs up on the venue doors. Maybe we could have had one outside, but I'm not convinced that's a viable option given the location. We will put a photo of the venue on the site next time.

Allow more "general open source" topics, and possibly including topics intended/useful for managers - We allow just about any talk on just about any subject, people need to submit them.

A Telegram or Whatsapp or whatsoever chat group for the attendees would have been nice. - Good idea.

Do not need to provide swag - Yes, but some people complain when they don't get a t-shirt. I don't want to do t-shirts anyway, but thought the scarves were a nice thing (and useful). Plus cheaper and easier. All other swag was provided by sponsors, which we allow them to do because it is an incentive for them to sponsor us.

Next time, maybe allow one or two "partner" level sponsors? - Getting companies to sponsor us is hard. Really really hard. I talked about this at the end. That said, this might work so we will look into it.

Probably also a Wiki [would be useful], though I'm not sure about the costs. - The workshop site (ACT) supports a wiki. We will add a link to it on future workshop sites and suggest attendees use it.

That's all for now. Thanks to this year's sponsors, without whom LPW would not have happened:

Perl 🐪 Weekly #699 - Happy birthday Perl

dev.to #perl

Published by Gabor Szabo on Monday 16 December 2024 06:35

Originally published at Perl Weekly 699

Hi!

I am not superstitious, but when a camel crosses my path ... I write about it in the Perl Weekly.

Similarly | On the other hand, I avoid celebrating birthdays of people ahead of time, but I think I can wish Perl a happy birthday already. It won't die on us in the next 2 days, will it?

The other day I was looking (again) for open source projects that are also deployed as a SaaS product (e.g MediaWiki is deployed as Wikipedia and is deployed as DEV.to. I found the awesome-selfhosted which is not the same, but might be used a good starting point. This brought me to the question, is there an awesome Perl list?

A quick search found me two: awesome-perl by hachioji.pm and awesome-perl by uhub.

Finally, the Advent calendars are still on. There are some truly awesome articles in all of them: The 2024 PDL Advent Calendar, the Perl Advent Calendar 2024, and the Raku Advent Calendar.

And one more thing, if you'd like to have your Perl event listed on our events page and listed at the bottom of the newsletter, send a Pull-Request to add it to the events.json file.

And a last thing. I started to have guests on the Code Maven live events. I'd be happy to have guests who would like to talk about some Perl-related subject. They don't have to be 'well reharsed talks', they can be just 'sit down and let me show you how to do X' things. Talk to me if you are interested.

Enjoy your week!

--
Your editor: Gabor Szabo.

Articles

Wide character (U+XXXX) in substitution (s///)

Oh the hated message...

Cosmoshop supports the German Perl/Raku-Workshop

Perl

This week in PSC (172) | 2024-12-12

The Weekly Challenge

The Weekly Challenge by Mohammad Sajid Anwar will help you step out of your comfort-zone. You can even win prize money of $50 by participating in the weekly challenge. We pick one champion at the end of the month from among all of the contributors during the month, thanks to the sponsor Lance Wicks.

The Weekly Challenge - 300

Welcome to a new week with a couple of fun tasks "Beautiful Arrangement" and "Nested Array". If you are new to the weekly challenge then why not join us and have fun every week. For more information, please read the FAQ.

RECAP - The Weekly Challenge - 299

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

Modularised approach to get the word search task done. You have to look carefully to get to the bottom. Keep it up great work.

Nothing But Words

Keeping it simple with multi layered for loops. Plenty of information presented too. Great work.

Search and Replace

Regex in action, brave heart. Loved it. Thanks for sharing knowledge with us every week.

Perl Weekly Challenge 299

PDL and matrix, what a deadly combination. Cool work to show the power of PDL. Well done.

Words, words and more words

One-liner from Peter? Yes, you heard me correctly. Don't forget to DIY. Brilliant work.

The Weekly Challenge #299

Not many tried Word Search this week and Robbie is not one of them. Please checkout his approach. Highly recommended.

Words, Words, What Are Words?

My favourite Postscript is now the choosen on this week for the blog post. Simply love it. Thanks for the contributions.

The one about words

For all Python lovers, you don't want to miss the regex solution in Python. There is always something new to learn, thanks for sharing the knowledge.

Weekly collections

NICEPERL's lists

Great CPAN modules released last week;
MetaCPAN weekly report;
StackOverflow Perl report.

Events

Toronto.pm December Social

December 19, 2024, In Person Event

GitLab pipelines and CI for Perl developers

January 20, 2025, Virtual event in Zoom

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

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

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

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

Advent Calendar - December 16, 2024

The Weekly Challenge

Published on Monday 16 December 2024 00:45

The gift is presented by Ryan Thompson. Today he is talking about his solution to The Weekly Challenge - 276. This is re-produced for Advent Calendar 2024 from the original post.

The Weekly Challenge - 300

The Weekly Challenge

Published on Monday 16 December 2024 00:44

Welcome to the Week #300 of The Weekly Challenge.

Advent Calendar - December 15, 2024

The Weekly Challenge

Published on Monday 16 December 2024 00:40

The gift is presented by Lance Wicks. Today he is talking about his solution to The Weekly Challenge - 221. This is re-produced for Advent Calendar 2024 from the original post.

Advent Calendar 2024

The Weekly Challenge

Published on Monday 16 December 2024 00:40

If you have any suggestions or ideas then please do share with us.

RECAP - The Weekly Challenge - 299

The Weekly Challenge

Published on Monday 16 December 2024 00:40

Thank you Team PWC for your continuous support and encouragement.

My Python Language Solution to Task 1 from The Weekly Challenge 299

dev.to #perl

Published by Robert McIntosh on Sunday 15 December 2024 20:25

1. Introduction

The Weekly Challenge, organized by Mohammad S. Anwar, is a friendly competition in which developers compete by solving a pair of tasks. It encourages participation from developers of all languages and levels through learning, sharing, and having fun.

Last week I competed in The Weekly Challenge 299 by solving Task 1: Replace Words. The task challenged developers to write a script that, when given an array and a sentence, replaced all words in the sentence that started with any of the words in the array.

In this post I present an overview of, and my solution to, Task 1: Replace Words from The Weekly Challenge 299 and finish with a brief conclusion.

2. Task 1: Replace Words

You are given an array of words and a sentence.

Write a script to replace all words in the given sentence that start with any of the words in the given array.

The Weekly Challenge 299, Task 1: Replace Words

Examples 1 - 3 illustrate the expected outputs from given inputs.

Example 1

Input: @words = ("cat", "bat", "rat")
       $sentence = "the cattle was rattle by the battery"
Output: "the cat was rat by the bat"

Output can be obtained by replacing any word in $sentence with $word from @words if it starts with $word, for example:

  • The word cattle starts with the word cat, so replacing cattle with cat transforms the sentence into the cat was rattle by the battery.
  • The word battery starts with the bat, so replacing battery with bat transforms the sentence into the cat was rattle by the bat.
  • The word rattle starts with the word rat, so replacing rattle with rat, transforms the sentence into the cat was rattle by the bat.

Example 2

Input: @words = ("a", "b", "c")
       $sentence = "aab aac and cac bab"
Output: "a a a c b"

Example 3

Input: @words = ("man", "bike")
       $sentence = "the manager was hit by a biker"
Output: "the man was hit by a bike"

3. My solution

def replace_word(sentence, this_word):
    return ' '.join([this_word if word.startswith(this_word) else word for word in sentence.split(' ')])

def replace_words(words, sentence):
    for word in words:
        sentence = replace_word(sentence,
                                word)
    return sentence

My solution uses two functions: replace_word and replace_words.

The replace_word function replaces any word in the string sentence that starts with this_word with this_word using built-in string methods split, startswith, and join and a list comprehension.

  • sentence.split(' ') splits sentence into a list of words using (' ') as a delimiter.
  • The list comprehension [this_word if word.startswith(this_word) else word for word in...] builds another list of words from the split sentence list, replacing a word with this_word when it startswith the this_word.
  • ' '.join(...) concatenates the second list into a string using (' ')
  • return returns the string

The replace_words function successively applies replace_word to sentence for each word in the array words. It then returns the transformed sentence.

4. Conclusion

In this post I presented an overview of, and my solution to, Task 1: Replace Words from The Weekly Challenge 299.

Since I used built-in methods like split, join, and startswith in my solution, it is straightforward, verbose, and maybe easy to understand. Such an approach may be helpful to you if you are new to Python, new to programming, or unfamiliar with regular expressions.

The one about words

dev.to #perl

Published by Simon Green on Sunday 15 December 2024 13:18

Weekly Challenge 299

Each week Mohammad S. Anwar sends out The Weekly Challenge, a chance for all of us to come up with solutions to two weekly tasks. My solutions are written in Python first, and then converted to Perl. It's a great way for us all to practice some coding.

Challenge, My solutions

Task 1: Replace Words

Task

You are given an array of words and a sentence.

Write a script to replace all words in the given sentence that start with any of the words in the given array.

My solution

For this task I use a regular expression to make the transformation. The complete code is

def replace_words(words: list[str], sentence: str) -> str:
    regexp = r"(?<![a-z])(" + "|".join(map(re.escape, words)) + r")([a-z]*(?:'[a-z]+)?)"
    return re.sub(regexp, r'\1', sentence)

The first bracket (?<![a-z]) is a negative look behind. This ensures that we only look at the first letters in each word. The next section (" + "|".join(map(re.escape, words)) + r") joins the words we want to replace with a | character, escaping any characters that have special meaning in a regular expression. The final part ([a-z]*(?:'[a-z]+)?) matches any remaining letters, optionally with an apostrophe ' character and some more letters. This ensures we match compound words like can't and would've.

For the input from the command line, I take the last value as the sentence and everything else as words.

Examples

$ ./ch-1.py cat bat rat "the cattle was rattle by the battery"
the cat was rat by the bat

$ ./ch-1.py a b c "aab aac and cac bab"
a a a c b

$ ./ch-1.py man bike "the manager was hit by a biker"
the man was hit by a bike

$ ./ch-1.py can "they can't swim"
they can swim

$ ./ch-1.py row "the quick brown fox"
the quick brown fox

Task 2: Word Search

Task

You are given a grid of characters and a string.

Write a script to determine whether the given string can be found in the given grid of characters. You may start anywhere and take any orthogonal path, but may not reuse a grid cell.

My solution

For this task, I start by checking all rows have the same number of columns. I then go through each cell. If the letter in that cell is the first letter of the word, I call the find_match function. If that returns true, this function will return true. If it doesn't, I continue to the next cell that contains the starting letter. If none exists, I return false.

def word_search(matrix: list[list[str]], word: str) -> bool:
    rows = len(matrix)
    cols = len(matrix[0])

    for row in range(rows):
        if len(matrix[row]) != cols:
            raise ValueError("Row %s has the wrong number of columns", row)

    for row in range(rows):
        for col in range(cols):
            if matrix[row][col] == word[0]:
                if find_match(matrix, word[1:], [[row, col]]):
                    return True

    return False

The find_match function is a recursive function. It takes three parameters

  1. The matrix
  2. The remain letters of the word (ones that haven't been matched)
  3. A list (arrayref in Perl) of [row,col] pairs of cells we have visited.

From the last position, we can move one of four directions (up, down, left or right). I check that moving this direction does not put us out of bounds or is a cell we've already used. If it isn't and the letter in this cell matches the letter we are looking for, I call the function again, taking the first letter off the word variable, and adding the new position. If I get to a point where there are no letters left, the word can be found and I return True.

def find_match(matrix, word, positions):
    if word == '':
        return True

    directions = [[-1, 0], [1, 0], [0, -1], [0, 1]]
    current_row = positions[-1][0]
    current_col = positions[-1][1]
    for direction in directions:
        next_row = current_row + direction[0]
        next_col = current_col + direction[1]
        if next_row < 0 or next_row >= len(matrix) or next_col < 0 or next_col >= len(matrix[0]):
            continue

        if [next_row, next_col] in positions:
            continue

        if matrix[next_row][next_col] == word[0]:
            if find_match(
                    matrix,
                    word[1:],
                    [*positions, [next_row, next_col]]
            ):
                return True

    return False

Examples

$ ./ch-2.py '[["A", "B", "D", "E"],["C", "B", "C", "A"],["B", "A", "A", "D"],["D", "B", "B", "C"]]' BDCA
True

$ ./ch-2.py '[["A", "A", "B", "B"],["C", "C", "B", "A"],["C", "A", "A", "A"],["B", "B", "B", "B"]]' ABAC
False

$ ./ch-2.py '[["B", "A", "B", "A"],["C", "C", "C", "C"],["A", "B", "A", "B"],["B", "B", "A", "A"]]' CCCAA
True

(dxxvi) 7 great CPAN modules released last week

Niceperl

Published by Unknown on Saturday 14 December 2024 22:10

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

  1. App::cpm - a fast CPAN module installer
    • Version: 0.997021 on 2024-12-11, with 73 votes
    • Previous CPAN version: 0.997020 was 17 days before
    • Author: SKAJI
  2. CPAN::Audit - Audit CPAN distributions for known vulnerabilities
    • Version: 20241208.001 on 2024-12-08, with 14 votes
    • Previous CPAN version: 20240910.001 was 2 months, 28 days before
    • Author: BDFOY
  3. Cpanel::JSON::XS - cPanel fork of JSON::XS, fast and correct serializing
    • Version: 4.39 on 2024-12-12, with 45 votes
    • Previous CPAN version: 4.38 was 6 months, 15 days before
    • Author: RURBAN
  4. Number::Phone - base class for Number::Phone::* modules
    • Version: 4.0005 on 2024-12-12, with 19 votes
    • Previous CPAN version: 4.0004 was 3 months, 2 days before
    • Author: DCANTRELL
  5. parent - Establish an ISA relationship with base classes at compile time
    • Version: 0.244 on 2024-12-13, with 25 votes
    • Previous CPAN version: 0.243 was 15 days before
    • Author: CORION
  6. PerlPowerTools - BSD utilities written in pure Perl
    • Version: 1.048 on 2024-12-09, with 40 votes
    • Previous CPAN version: 1.047 was 2 months, 9 days before
    • Author: BRIANDFOY
  7. XML::Twig - XML, The Perl Way
    • Version: 3.53 on 2024-12-13, with 62 votes
    • Previous CPAN version: 3.52 was 8 years, 20 days before
    • Author: MIROD

(dxcv) metacpan weekly report - Path::Tiny

Niceperl

Published by Unknown on Saturday 14 December 2024 22:07

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

Week's winner: Path::Tiny (+2)

Build date: 2024/12/14 21:06:47 GMT


Clicked for first time:


Increasing its reputation:

PEVANS Core Perl 5: Grant Report for November 2024

Perl Foundation News

Published by alh on Sunday 08 December 2024 13:54


Paul writes:

I had a suddenly much more productive month in November, as a lot of little logjams and other things in the way all got cleared.

Hours:

  • 4 = Optimise foreach on builtin::indexed
    • https://github.com/Perl/perl5/pull/22641
    • https://github.com/Perl/perl5/pull/22726
  • 8 = "faster signatures" experiment
    • https://github.com/leonerd/perl5/tree/faster-signatures
    • https://github.com/Perl/perl5/pull/22763
  • 3 = valid_identifier() function family
    • https://github.com/Perl/perl5/pull/22769
  • 1 = :writer attribute on fields
    • https://github.com/Perl/perl5/pull/22765
  • 7 = Implementing any() and all() (PPC0027)
    • https://github.com/Perl/perl5/pull/22773
  • 1 = Fix B::Deparse on method subs
    • https://github.com/Perl/perl5/pull/22790
  • 3 = Management of PPC documents
    • https://github.com/Perl/PPCs/blob/main/ppcs/ppc0029-attributes-v2.md
    • https://github.com/Perl/PPCs/blob/main/ppcs/ppc0030-undef-aware-equality.md
    • https://github.com/Perl/PPCs/blob/main/ppcs/ppc0031-metaoperator-flags.md
  • 2 = perl5-porters@ mailing list reading/replies
  • 2 = Github code reviews

Total: 31 hours

(dxxv) 3 great CPAN modules released last week

Niceperl

Published by Unknown on Saturday 07 December 2024 22:10

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

  1. Date::Manip - Date manipulation routines
    • Version: 6.96 on 2024-12-04, with 19 votes
    • Previous CPAN version: 6.95 was 9 months, 3 days before
    • Author: SBECK
  2. Mojolicious::Plugin::AssetPack - Compress and convert CSS, Less, Sass, JavaScript and CoffeeScript files
    • Version: 2.15 on 2024-12-06, with 50 votes
    • Previous CPAN version: 2.14 was 1 year, 10 months, 10 days before
    • Author: SRI
  3. SPVM - The SPVM Language
    • Version: 0.990032 on 2024-12-02, with 33 votes
    • Previous CPAN version: 0.990031 was 16 days before
    • Author: KIMOTO

(dxciv) metacpan weekly report - App::Changelog

Niceperl

Published by Unknown on Saturday 07 December 2024 22:07

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

Week's winner: App::Changelog (+2)

Build date: 2024/12/07 21:07:28 GMT


Clicked for first time:


Increasing its reputation:

How to Use Perl for Web Development with CGI

Perl on Medium

Published by Mayur Koshti on Tuesday 03 December 2024 20:48

Web Development with Easy Steps in Perl

Get ready for the 2025 Perl and Raku Conference!

perl.com

Published on Tuesday 03 December 2024 20:04

The Perl and Raku Conference 2025 is coming up June 27-29, 2025, and it’s set to be an exciting gathering for developers, enthusiasts, and community members alike. This annual event brings together some of the best minds in the world of Perl and Raku programming, and we can’t wait to see you there! For the first time ever, the conference will be presented in the Palmetto State, South Carolina! The technical and cultural hub of upstate South Carolina is the city of Greenville, home of the Lockheed-Martin F-16!

Whether you’re a seasoned Perl programmer or someone eager to learn more about Raku, the conference offers the perfect opportunity to share knowledge, network with like-minded individuals, and collaborate on innovative ideas. This year’s event promises to be an immersive experience full of workshops, discussions, and talks on the latest trends and developments in the Perl and Raku ecosystems.

This year’s conference format is a little different from past years, in a more-streamlined format. On Friday, June 27, we’ll have a day-long add-on class session, then the main conference on Saturday and Sunday, June 28 and 29. Lightning talks are scheduled both days, an we have an exciting keynote from a new voice to our community on Saturday morning: David Both, a writer, speaker, trainer, and long-time proponent of the Linux Philosophy.

Why You Should Attend

Attending the Perl and Raku Conference means you’ll have the chance to:

  • Learn from the Experts: Engage with community leaders, developers, and experts who have extensive experience with Perl and Raku. Discover new tools, techniques, and best practices that can help you in your own projects.
  • Connect with the Community: Build valuable relationships with other Perl and Raku enthusiasts from around the world. Share your experiences, collaborate, and even find potential collaborators for future projects.
  • Celebrate the Languages: Perl and Raku are both powerful, flexible, and continuously evolving programming languages. This conference provides the perfect setting to explore their unique features and the many ways they continue to shape the world of software development.

Call for Papers is Open: Share Your Knowledge!

The Call for Papers (CFP) for the Perl and Raku Conference 2025 is now open! This is your chance to contribute to the event by submitting your proposals for talks, tutorials, and workshops. Whether you’re an experienced developer with a deep dive into language features, or someone with a fascinating project that showcases the power of Perl and/or Raku, we want to hear from you!

Topics we’re looking for include, but are not limited to:

  • Advanced Perl and Raku techniques
  • Innovative uses of Perl and Raku in science or industry
  • Tools and libraries to enhance the Perl and Raku ecosystems
  • Tips and best practices for developing with Perl and Raku
  • Community contributions, stories, and case studies
  • The future of Perl and Raku

The Perl and Raku community thrives on collaboration and the sharing of knowledge. By submitting a proposal, you’ll not only have the chance to present your ideas to an engaged and passionate audience but also contribute to the growth of these incredible languages. Whether you’re a first-time speaker, or a seasoned pro, we encourage you to submit. Bring your passion and ideas to share with your colleagues! The submission deadline of January 15 is coming up quick, so start getting your ideas together, and submit your talk now. Accepted speakers will receive complimentary conference registration, as usual. With our streamlined, two-day format, there are fewer slots available, so talk acceptance will be more competitive than we’re used to.

We look forward to seeing you at the end of June in Greenville, SC! For more details, including special-price lodging at the conference hotel and submission guidelines, visit the official conference website.

List of new CPAN distributions – Nov 2024

Perlancar

Published by perlancar on Tuesday 03 December 2024 02:19

dist author abstract date
Acme-CPANModules-Soundex PERLANCAR List of modules that implement the soundex algorithm 2024-11-24T00:05:57
Acme-CaSe CONTRA The great new Acme::CaSe! 2024-11-19T08:13:26
Acme-Case CONTRA The great new Acme::Case! 2024-11-19T08:13:37
Akamai-PropertyFetcher SHINGO Akamaiプロパティã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ–ãƒãƒ¼ã‚¸ãƒ§ãƒ³æƒ…報をå–å¾—ã™ã‚‹ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ« 2024-11-04T08:09:49
Algorithm-Gutter JMATES cellular automata to simulate rain in a gutter 2024-11-25T15:59:02
Alien-DuckDB PERIGRIN Find or build DuckDB 2024-11-26T03:41:37
Alien-cargo PLICEASE Find or download the cargo command (build system and package manager for Rust) 2024-11-24T00:06:19
Alien-cargo-capi PLICEASE Find or build the cargo capi command 2024-11-24T23:56:49
Alien-cargo-clone PLICEASE Find or build the cargo clone command 2024-11-24T02:33:51
Alien-raylib5 PERIGRIN Alien distribution for raylib video game engine, version 5 and above 2024-11-23T06:04:11
Amazon-SQS-Client BIGFOOT Perl classes for interacting with Amazon SQS 2024-11-27T23:07:47
App-PasswordManager OLOOEEZ Simple password manager for adding, listing, editing, deleting, and copying passwords to the clipboard 2024-11-26T12:46:39
App-Stouch SAMYOUNG Simple template file creator 2024-11-22T02:59:41
App-TodoList OLOOEEZ Simple command-line to-do list manager written in Perl 2024-11-25T23:32:50
App-coldigits TULAMILI TSVファイルの各列が何桁のものが何件あったかを、行列状に示す。 2024-11-18T14:35:34
App-gapstat TULAMILI 改行区切りの数値列に、差分が1を超えるギャップ(間隙)がないかを、チェックする。 2024-11-20T15:35:38
App-grep-sounds-like PERLANCAR Print lines with words that sound like to the specified word 2024-11-20T05:47:15
Archive-Libarchive-Compress PLICEASE Recursively archive a directory (using libarchive) 2024-11-15T19:49:10
Business-CAMT MARKOV ISO20022 Cash Management (CAMT) messages 2024-11-25T08:57:16
CPANSA-DB BDFOY the CPAN Security Advisory data as a Perl data structure, mostly for CPAN::Audit 2024-11-17T20:32:36
Chart-ECharts GDT Apache ECharts wrapper for Perl 2024-11-21T22:24:32
CheerLights-API NOTHANS A Perl module for accessing the CheerLights API 2024-11-06T02:28:43
Comparer-file_num_links PERLANCAR Compare file's number of (hard) links 2024-11-24T00:06:08
Crypt-Bear LEONT BearSSL for Perl 2024-11-12T20:07:54
Data-Annotation POLETTIX [Put something meaningful here!] 2024-11-13T22:16:57
Data-FastPack-JPacker DRCLAW backend class for packing FastPack data files into web loadable JPack 2024-11-11T00:47:35
Data-FastPack DRCLAW FastPack Record format, parsing and serialising module 2024-11-08T04:39:52
Data-JPack DRCLAW Offline/Online Web application and data system 2024-11-08T04:40:03
Environment-Is PLICEASE Detect environments like Docker or WSL 2024-11-23T20:54:33
Eugener EUGENER A test package. DOnt install. 2024-11-26T14:55:51
Eugener-test EUGENER A test package. DOnt install. 2024-11-20T13:32:00
Eugener_test EUGENER A test package. DOnt install. 2024-11-20T13:34:56
Eugenertest EUGENER A test package. DOnt install. 2024-11-20T14:04:58
Future-IO-Impl-AnyEvent MATHIAS Future::IO implementation using AnyEvent 2024-11-27T21:09:50
Game-EnergyLoop JMATES a simple energy system 2024-11-05T19:13:51
Genealogy-FindaGrave NHORNE Find URLs on FindaGrave for a person 2024-11-11T13:01:21
Geo-Leaflet MRDVT Generates Leaflet web page 2024-11-09T02:48:31
Hash-Iter PERLANCAR Generate a coderef iterator for a hash 2024-11-04T08:09:16
HashDataBundle-Display-Resolution PERLANCAR HashData::* modules related to Display::Resolution 2024-11-10T00:05:43
Local-Acme CONTRA The great new Local::Acme! 2024-11-19T07:43:34
MFab-Plugins-Datadog DDROWN Mojolicious plugin for Datadog APM integration 2024-11-06T16:24:14
Mail-Colander POLETTIX Categorize and manage email messages 2024-11-28T06:49:09
Mail-Sieve POLETTIX Categorize and manage email messages 2024-11-16T10:11:54
Math-NumberBase-XS ZARABOZO Lighting fast number converter from one base to another base 2024-11-11T05:30:35
Math-Symbolic-Custom-Polynomial MJOHNSON Polynomial routines for Math::Symbolic 2024-11-27T17:41:18
Mojo-UserAgent-Role-TotalTimeout KARJALA Role for Mojo::UserAgent that enables setting total timeout including redirects 2024-11-06T09:41:19
Music-Dice GENE Define and roll musical dice 2024-11-30T22:57:09
PDL-Complex ETJ handle complex numbers (DEPRECATED – use native complex) 2024-11-26T02:13:32
PDL-Graphics-Limits ETJ derive limits for display purposes 2024-11-25T23:17:09
PDL-IO-Browser ETJ 2D data browser for PDL 2024-11-26T00:27:38
PDL-Perldl2 ETJ Simple shell (version 2) for PDL 2024-11-26T02:48:28
Perl-Version-Bumper BOOK Update use VERSION on any Perl code 2024-11-20T08:48:15
Pongo HAPPYBEAR A Perl MongoDB interface using XS and the MongoDB C driver. 2024-11-29T05:14:14
Random-Simple BAKERSCOT Simple, usable, real world random numbers 2024-11-08T23:59:53
RecentInfo-Manager CORION 2024-11-03T07:32:19
Result-Simple KFLY A dead simple perl-ish Result like F#, Rust, Go, etc. 2024-11-23T09:23:32
STIX GDT Structured Threat Information Expression (STIX) 2024-11-18T11:00:07
Standup-Diary SMONFF Manage a simple journal in Markdown files 2024-11-23T14:08:21
Str-Iter PERLANCAR Generate a coderef iterator to iterate a string one (or more) character(s) at a time 2024-11-17T00:06:14
Template-Plexsite DRCLAW Class for interlinked templating 2024-11-12T03:59:54
Test2-Tools-ComboObject PLICEASE Combine checks and diagnostics into a single test as an object 2024-11-22T07:22:27
UserAgent-Any MATHIAS Wrapper above any UserAgent library, supporting sync and async calls. 2024-11-15T21:01:30
UserAgent-Any-JSON MATHIAS Specialization of UserAgent::Any for JSON APIs. 2024-11-16T20:16:37
_Acme-Local CONTRA The great new _Acme::Local! 2024-11-19T07:35:37
eugener-test EUGENER A test package. DOnt install. 2024-11-20T12:58:19

Stats

Number of new CPAN distributions this period: 65

Number of authors releasing new CPAN distributions this period: 33

Authors by number of new CPAN distributions this period:

No Author Distributions
1 PERLANCAR 6
2 PLICEASE 6
3 EUGENER 5
4 ETJ 4
5 CONTRA 4
6 DRCLAW 4
7 POLETTIX 3
8 MATHIAS 3
9 OLOOEEZ 2
10 GDT 2
11 PERIGRIN 2
12 TULAMILI 2
13 JMATES 2
14 LEONT 1
15 ZARABOZO 1
16 NOTHANS 1
17 SMONFF 1
18 BOOK 1
19 BIGFOOT 1
20 KFLY 1
21 HAPPYBEAR 1
22 MRDVT 1
23 NHORNE 1
24 DDROWN 1
25 SHINGO 1
26 GENE 1
27 SAMYOUNG 1
28 BAKERSCOT 1
29 BDFOY 1
30 MARKOV 1
31 CORION 1
32 MJOHNSON 1
33 KARJALA 1

DuckDuckGo Donates $25,000 to The Perl and Raku Foundation

perl.com

Published on Tuesday 03 December 2024 00:05

DuckDuckGo Growth

Today, on “Giving Tuesday”, The Perl and Raku Foundation (TPRF) is extremely pleased to announce a donation of $25,000 from DuckDuckGo. Since 2011, DuckDuckGo has donated over 6 million dollars to organizations that align with their “vision of raising the standard of trust online”.

TPRF is dedicated to advancing the Perl and Raku programming languages through open-source development, community engagement, and outreach to ensure their ongoing growth, relevance, and accessibility. This support from DuckDuckGo will allow TPRF to continue to do things like fund core Perl development, fund grants for projects which are important to the community and otherwise to support the community where it can.

Every donation sends a message that this work matters. On the occasion of this gift, The Perl and Raku Foundation is deeply grateful to DuckDuckGo not only for its generosity but also for its confidence in TPRF’s mission.

To learn more about TPRF’s current activities and goals for the future, please see the TPRF 2024 prospectus

If your organization is interested in becoming a TPRF donor, please reach out to me. I’d be more than happy to set up a call so that we can discuss how a donor relationship with TPRF can benefit your organization.

What's new on CPAN - October 2024

perl.com

Published on Tuesday 03 December 2024 00:00

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

APIs & Apps

Config & Devops

Data

Development & Version Control

Hardware

Language & International

Science & Mathematics

  • Math::LiveStats (CDRAKE) makes mean, standard deviation, vwap, and p-values available for one or more window sizes in streaming data

Web

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

Part 1: Contiguous Array

You are given an array of binary numbers, @binary.

Write a script to return the maximum length of a contiguous subarray with an equal number of 0 and 1.

Let’s not concern ourselves with any particular efficiencies and just analyze all the subsets of the given numbers!

The main loop for iterating over all the contiguous sub-arrays.

loop over all sub-arrays 1 ⟩≡


do{
my $i = $_;
do{
my $j = $_;
if($i != $j && $i < $j){
my @s = @{$b}[$i .. $j];
my $zeroes = grep {$_ == 0} @s;
my $ones = grep {$_ == 1} @s;
$max_length = @s if $zeroes == $ones &&
@s > $max_length;
}
} for 0 .. @{$b} - 1;
} for 0 .. @{$b} - 1;

Fragment referenced in 2.

Uses: $b 2, $max_length 2.

We really just need one subroutine to co-ordinate the inputs and run the main loop that’s required.

main subroutine 2 ⟩≡


sub contiguous_array{
my $b = [@_];
my $max_length = 0;
loop over all sub-arrays 1
return $max_length;
}

Fragment referenced in 3.

Defines: $b 1, $max_length 1.

Putting it all together...

"ch-1.pl" 3


preamble 4
main subroutine 2
main 5

preamble 4 ⟩≡


use v5.40;

Fragment referenced in 3, 9.

The rest of the code just runs some simple tests.

main 5 ⟩≡


MAIN:{
say contiguous_array 1, 0;
say contiguous_array 0, 1, 0;
say contiguous_array 0, 0, 0, 0, 0;
say contiguous_array 0, 1, 0, 0, 1, 0;
}

Fragment referenced in 3.

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

Part 2: Semi-Ordered Permutation

You are given permutation of $n integers, @ints. Write a script to find the minimum number of swaps needed to make the @ints a semi-ordered permutation.

A permutation is called semi-ordered if the first number is 1 and the last number equals n. That means we need to count the number of swaps needed to move 1 to the beginning and $n to the end.

At first thought, I wonder if there’s a catch? Does the swapping end up moving 1 or $n further from its destination? That doesn’t seem to be the case even if they were adjacent to each other. That is because they are moving in opposite directions. 1 is always moving left and $n is always moving right. Although they may swap with each other it will always be of benefit to them both.

Let’s start with the code for swapping left and and right to move 1 and $n in their respective directions.

swap left 6 ⟩≡


($i->[$j - 1], $i->[$j]) = ($i->[$j], $i->[$j - 1]);
$j--;
$swaps++;

Fragment referenced in 8.

Uses: $i 8, $swaps 8.

swap right 7 ⟩≡


($i->[$n + 1], $i->[$n]) = ($i->[$n], $i->[$n + 1]);
$n++;
$swaps++;

Fragment referenced in 8.

Uses: $i 8, $swaps 8.

We’ll put everything together in a subroutine.

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


sub semi_ordered{
my $i = [@_];
my $swaps = 0;
my $j = -1;
my $n = @{$i};
do{
$j = $_ if $i->[$_] == 1;
$n = $_ if $i->[$_] == $n;
} for 0 .. @{$i} - 1;
{
if($j != 0){
swap left 6
}
if($n != @{$i} - 1){
swap right 7
}
redo unless $j == 0 && $n == @{$i} - 1;
}
return $swaps;
}

Fragment referenced in 9.

Defines: $i 6, 7, $swaps 6, 7.

The rest of the code drives some tests.

"ch-2.pl" 9


preamble 4
semi_ordered: co-ordinates all the swaps and checks 8
main 10

main 10 ⟩≡


MAIN:{
say semi_ordered 2, 1, 4, 3;
say semi_ordered 2, 4, 1, 3;
say semi_ordered 1, 3, 2, 4, 5;
}

Fragment referenced in 9.

Sample Run
$ perl perl/ch-2.pl 
2 
3 
0
    

References

The Weekly Challenge 297
Generated Code

Perl DBI et MariaDB MaxScale : Le Guide Complet

Perl on Medium

Published by Maud Dollie Perry on Sunday 01 December 2024 21:59

(dxxiv) 7 great CPAN modules released last week

Niceperl

Published by Unknown on Sunday 01 December 2024 16:06

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

  1. App::cpm - a fast CPAN module installer
    • Version: 0.997020 on 2024-11-24, with 73 votes
    • Previous CPAN version: 0.997019 was 8 days before
    • Author: SKAJI
  2. Dancer2 - Lightweight yet powerful web application framework
    • Version: 1.1.2 on 2024-11-25, with 137 votes
    • Previous CPAN version: 1.1.1 was 4 months, 7 days before
    • Author: CROMEDOME
  3. IO::Socket::IP - Family-neutral IP socket supporting both IPv4 and IPv6
    • Version: 0.43 on 2024-11-25, with 21 votes
    • Previous CPAN version: 0.42 was 1 year, 4 months before
    • Author: PEVANS
  4. MetaCPAN::Client - A comprehensive, DWIM-featured client to the MetaCPAN API
    • Version: 2.033000 on 2024-11-25, with 25 votes
    • Previous CPAN version: 2.032000 was 6 months, 10 days before
    • Author: MICKEY
  5. Object::Pad - a simple syntax for lexical field-based objects
    • Version: 0.816 on 2024-11-25, with 45 votes
    • Previous CPAN version: 0.815 was 12 days before
    • Author: PEVANS
  6. parent - Establish an ISA relationship with base classes at compile time
    • Version: 0.243 on 2024-11-28, with 25 votes
    • Previous CPAN version: 0.242 was 3 months, 15 days before
    • Author: CORION
  7. Parser::MGC - build simple recursive-descent parsers
    • Version: 0.23 on 2024-11-25, with 12 votes
    • Previous CPAN version: 0.22 was 1 month, 14 days before
    • Author: PEVANS

Building a Simple Web Scraper with Perl

Perl on Medium

Published by Mayur Koshti on Wednesday 27 November 2024 13:38

Build Powerful Scraper In Perl

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

Part 1: String Compression

You are given a string of alphabetic characters, $chars. Write a script to compress the string with run-length encoding.

A compressed unit can be either a single character or a count followed by a character.

BONUS: Write a decompression function.

After working so much with recursion for the previous challenge, TWC 295, this time around we’ll use a simple loop mechanism available in Perl: a redo block.

The main loop for iterating over the characters one by one.

loop over letters 1 ⟩≡


my $previous = q//;
{
my $c = shift @{$s};
$count++ if $c eq $previous;
if($c ne $previous){
concatenate partial encoding 2
$count = 1;
}
$previous = $c;
redo if 0 < @{$s};
}
concatenate partial encoding 2

Fragment referenced in 3.

Uses: $count 3, $s 3, 5.

concatenate partial encoding 2 ⟩≡


$encoding .= "$count$previous" if $count > 1;
$encoding .= $previous if $count == 1;

Fragment referenced in 1.

Uses: $count 3, $encoding 3.

Here’s a subroutine which co-ordinates encoding: splits the string, invokes the loop, and returns the compressed format.

string compression: co-ordinates encoding 3 ⟩≡


sub encoding{
my($s) = @_;
my $count = 0;
my $encoding = q//;
$s = [split //, $s];
loop over letters 1
return $encoding;
}

Fragment referenced in 6.

Defines: $count 1, 2, $encoding 2, $s 1, 4, 5.

The BONUS seems to be fairly doable. Given an encoded string we can expand it back to the original by a similar process as the encoding. In fact, let’s use the same sort of loop.

loop over encoded string 4 ⟩≡


my $previous = q//;
{
my $c = shift @{$s};
if($c =~ m/\d/){
my $d = $c;
$c = shift @{$s};
$decoded .= $c x $d;
}
else{
$decoded .= $c;
}
redo if 0 < @{$s};
}

Fragment referenced in 5.

Uses: $decoded 5, $s 3, 5.

As before we’ll define a subroutine which co-ordinates decoding.

decoding 5 ⟩≡


sub decoding{
my($s) = @_;
my $decoded = q//;
$s = [split //, $s];
loop over encoded string 4
return $decoded;
}

Fragment referenced in 6.

Defines: $decoded 4, $s 1, 3, 4.

Putting it all together...

"ch-1.pl" 6


preamble 7
string compression: co-ordinates encoding 3
decoding 5
main 8

preamble 7 ⟩≡


use v5.40;

Fragment referenced in 6, 12.

The rest of the code just runs some simple tests.

main 8 ⟩≡


MAIN:{
say encoding q/abbc/;
say encoding q/aaabccc/;
say encoding q/abcc/;

say q//;

say decoding encoding q/abbc/;
say decoding encoding q/aaabccc/;
say decoding encoding q/abcc/;
}

Fragment referenced in 6.

Sample Run
$ perl perl/ch-1.pl 
a2bc 
3ab3c 
ab2c 
 
abbc 
aaabccc 
abcc
    

Part 2: Matchstick Square

You are given an array of integers, @ints. Write a script to find if it is possible to make one square using the sticks as in the given array @ints where $ints[$i] is the length of ith stick.

First let’s notice that the lengths must all sum to a number evenly divisible by four, so that’ll be an initial filter on the list. If that first test passes we divide the sum by four (to get the side length) and determine if we can get four subsets which all sum to that side length.

test if evenly divisible by four 9 ⟩≡


my $length_sum = unpack(q/%32I*/, pack(q/I*/, @{$matchsticks}));
return false if 0 != $length_sum % 4;
my $side_length = $length_sum / 4;

Fragment referenced in 11.

Defines: $side_length 10.

Uses: $matchsticks 11.

If we have a sum of lengths evenly divisible by four we’ll then check if if we have four subsets which sum to the computed side length. To do this we’ll compute the powerset (all subsets) of the list and check the sums.

check subset sums 10 ⟩≡


my $counter = 0;
my $ps_iterator = powerset_lazy(@{$matchsticks});
while(my $set = $ps_iterator->()){
my $set_sum = unpack(q/%32I*/, pack(q/I*/, @{$set}));
$counter++ if $set_sum == $side_length;
return true if $counter == 4;
}
return false;

Fragment referenced in 11.

Uses: $matchsticks 11, $side_length 9.

is_square: co-ordinates all the checks 11 ⟩≡


sub is_square{
my $matchsticks = [@_];
test if evenly divisible by four 9
check subset sums 10
}

Fragment referenced in 12.

Defines: $matchsticks 9, 10.

The rest of the code drives some tests.

"ch-2.pl" 12


preamble 7
use boolean;
use List::PowerSet q/powerset_lazy/;
is_square: co-ordinates all the checks 11
main 13

main 13 ⟩≡


MAIN:{
say boolean is_square 1, 2, 2, 2, 1;
say boolean is_square 2, 2, 2, 4;
say boolean is_square 2, 2, 2, 2, 4;
say boolean is_square 3, 4, 1, 4, 3, 1;
}

Fragment referenced in 12.

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

References

The Weekly Challenge 295
Generated Code

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

Part 1: Word Break

You are given a string, $str, and list of words, @words.

Write a script to return true or false whether the given string can be segmented into a space separated sequence of one or more words from the given list.

This can be brute forced rather easily: just try every concatenated combination from the list and see if we get a match. It is not too much work to add a bit more efficiency though. Our approach will be:

  1. Put the list of words into a hash keyed by the first letter.
  2. Start with the first letter of the string, find a match in the hash.
  3. Remove the word from the string and move onto the next letter.
  4. Repeat until, if possible, all parts of the string are found in the list.

Since there may be many words which start with the same letter we will use a recursive implementation which will make sure to check each of them.

Here’s how we construct the hash of words keyed by their first letter. Nothing especially clever, just an ordinary loop over the words.

create hash 1 ⟩≡


my $h = {};
do{
my $c = substr $_, 0, 1;
push @{$h->{$c}}, $_;
} for @{$words};

Fragment referenced in 3.

Defines: $h 2, 3.

The biggest chunk of word is here in this subroutine, where we recursively explore all possibilities of matching words. If at any point we find all components of the string we return true. In cases where the string cannot be composed of words from the list then the recursion just simply ends and, by default, returns undef.

find breaks 2 ⟩≡


sub find_breaks{
my($s, $h) = @_;
return true if $s eq q//;
my $c = substr $s, 0, 1;
my $words = $h->{$c};
do{
$s = substr $s, length $_;
return find_breaks($s, $h);
} for @{$words};
}

Fragment referenced in 4.

Uses: $h 1.

Here’s a subroutine which co-ordinates everything: invokes the hash construction and recursion. The boolean function is used to make sure something nicely printable is returned.

word break: co-ordinates hash creation and the recursive search 3 ⟩≡


sub word_break{
my($s, $words) = @_;
create hash 1
return boolean(find_breaks $s, $h);
}

Fragment referenced in 4.

Uses: $h 1.

Putting it all together...

"ch-1.pl" 4


preamble 5
find breaks 2
word break: co-ordinates hash creation and the recursive search 3
main 6

preamble 5 ⟩≡


use v5.40;
use boolean;

Fragment referenced in 4, 9.

The rest of the code just runs some simple tests.

main 6 ⟩≡


MAIN:{
say word_break q/weeklychallenge/, [q/challenge/, q/weekly/];
say word_break q/perlrakuperl/, [q/raku/, q/perl/];
say word_break q/sonsanddaughters/,[q/sons/, q/sand/, q/daughters/];
}

Fragment referenced in 4.

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

Part 2: Jump Game

You are given an array of integers, @ints. Write a script to find the minimum number of jumps to reach the last element. $ints[$i] represents the maximum length of a forward jump from the index $i. In case last element is unreachable then return -1.

We always start at the array index 0. From there we can recursively explore the possible paths that may be taken. Keep in mind that at each step $i we can only move as many as $ints[$i] positions.

In many ways this is similar to the first part of this week’s challenge!

If at any point we detect we have reached list’s end then we save the number of moves made. At the end we sort the list of moves and return the smallest number of moves. If this list is empty then we return -1.

loop over our hand and remove 7 ⟩≡


sub jump{
my($l, $i, $counter, $moves) = @_;
my $m = $l->[$i];
if($i + $m >= @{$l} - 1){
push @{$moves}, $counter + 1;
}
else{
do{
jump($l, $i + $_, $counter + 1, $moves);
} for 1 .. $m;
}
}

Fragment referenced in 9.

Defines: $i Never used, $l Never used.

Uses: $moves 8.

jump game: co-ordinates the recursive search 8 ⟩≡


sub jump_game{
my $moves = [];
jump [@_], 0, 0, $moves;
return -1 if 0 == @{$moves};
return (sort {$a <=> $b} @{$moves})[0];
}

Fragment referenced in 9.

Defines: $moves 7.

The rest of the code drives some tests.

"ch-2.pl" 9


preamble 5
loop over our hand and remove 7
jump game: co-ordinates the recursive search 8
main 10

main 10 ⟩≡


MAIN:{
say jump_game 2, 3, 1, 1, 4;
say jump_game 2, 3, 0, 4;
say jump_game 2, 0, 0, 4;
}

Fragment referenced in 9.

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

References

The Weekly Challenge 295
Generated Code