If you've discovered something amazing about Perl that you just need to share with everyone, this is the right place.

This section is also used for non-question discussions about Perl, and for any discussions that are not specifically programming related. For example, if you want to share or discuss opinions on hacker culture, the job market, or Perl 6 development, this is the place. (Note, however, that discussions about the PerlMonks web site belong in PerlMonks Discussion.)

Meditations is sometimes used as a sounding-board — a place to post initial drafts of perl tutorials, code modules, book reviews, articles, quizzes, etc. — so that the author can benefit from the collective insight of the monks before publishing the finished item to its proper place (be it Tutorials, Cool Uses for Perl, Reviews, or whatever). If you do this, it is generally considered appropriate to prefix your node title with "RFC:" (for "request for comments").

User Meditations
TPF PERL Swag
1 direct reply — Read more / Contribute
by Anonymous Monk
on Jan 09, 2023 at 02:42
    I want some swag from The Perl Foundation but the graphics...

    1. They spelled it: PERL
    2. Raptors are extinct.
    3. Raw onions? C'mon!

    I want cool cryptic, like Perl itself:

    $Perl->{5.36}

    Front Back
    #!/usr/bin/perl exit;
    BEGIN{} END{}
    <DATA> __DATA__
    use Perl; $?
    $@% ...
    $_ @_

    Obviously: camel code

Probabilities of drawing certain cards
3 direct replies — Read more / Contribute
by jdporter
on Jan 06, 2023 at 12:33

    This shows the probabilities of drawing two specific cards (labeled A and B) in a hand of five cards, from decks of various sizes.

    All numbers are percentages.

    When the deck contains no 'draw' cards:

    Deck sizeA & BA & !BA ^ BA | B
    666.716.733.3100.0
    747.623.847.695.2
    835.726.853.689.3
    927.827.855.683.3
    1022.227.855.677.8
    1118.227.354.572.7
    1215.226.553.068.2
    1312.825.651.364.1

    When the 'A' card causes Draw 1:

    Deck sizeA & BA & !BA ^ BA | B
    650.00.050.0100.0
    741.78.350.091.7
    835.714.350.085.7
    931.218.850.081.2
    1027.822.250.077.8
    1125.025.050.075.0
    1222.727.350.072.7

    The probabilities of other combinations can be derived from those given in this table:

    • A | !B (A or not B - possibly both conditions) is the inverse of A & !B.
    • A ^ !B (A or not B but NOT both conditions) is the inverse of A ^ B.
    • !A & !B (neither A nor B) is the inverse of A | B
    • !A | !B (not A, or not B - possibly both conditions) is the inverse of A & B.
    • !A ^ !B (not A, or not B, but NOT both conditions) is logically the same as A ^ B.
My Fondest Farewell to the Monastery
2 direct replies — Read more / Contribute
by perldigious
on Jan 02, 2023 at 01:21

    Hello my fellow Monks.

    I've been absent the last few months. I have, unfortunately, been forced to submit to the snake cult.

    I resisted. I resisted for as long as I could. I even thought I might get away with continuing to use Perl until my "retirement" from corporate life that is hopefully less than a half decade away. But alas, the pervasiveness of Python, and it's success in becoming the first language of choice for so many engineering schools for the last several years has backed me in to a corner, and the zealots have come for me demanding I convert or be burned at the stake for heresy. I am in effect being told I can no longer write scripts in Perl and must adopt Python so that others can read and modify my code. :-(

    Our young engineers use Python. Our technicians use Python. All our automated tests and data analytics are now written in Python. I had such hope when I joined my current company. They even had an old learning course on video originally taught in person by someone who is now one of our VPs called "Test Automation with Perl Scripting"... but it's almost two decades old now.

    Sadly, I simply don't have the capacity at this point to maintain any sort of proficiency in two scripting languages. Frankly, I barely have enough for one. So I am now forced to type their indoctrination mantras in the devil's own parseltoungue. Pity me, for your brother monk has truly fallen from grace.

    I may leave the monastery now, some seven years after I joined your order, but I have decided to leave it as I have lived in it. With a bit of my own awkward brand of humor via one final Perl Poetry entry from the Monk who fancies himself a drunken poet.

    To those of you who have helped me over the years, or made me laugh, or raised my spirits, I sincerely thank you. Be well, live long, and prosper. :-)

    - perldigious

    Just another Perl hooker - My clients appreciate that I keep my code clean but my comments dirty.
Happy Holidays!
4 direct replies — Read more / Contribute
by stevieb
on Dec 23, 2022 at 20:51

    Happy Holidays, fellow Monks!

    Over the last decade, with lots of help, I've been able to bring forth some interesting things for Perl, and I'm now in the beginning stage of another one.

    I put forth an API to command and control Raspberry Pi devices and dozens of Integrated Circuits and sensors related to it. I then reverse engineered Tesla's API and wrapped it with Perl.

    I'm a strong privacy advocate. For years, I distrusted all vendors of all kind. However, through one of my jobs, I was forced to better familiarize myself with Apple. Despite issues and setbacks, they are, IMHO, very reasonable with privacy. Even their legalese is human readable for the most part. In fact, not only am I typing this on a Macbook, I have an iPhone, Apple Watch and several devices that allow me to control my home automation. Yep, I am even friends with Siri.

    With that said, I want to embark on another very, very ambitious project... figure out how I can write a Perl API to deal with Apple devices, particularly HomeKit stuff.

    To keep this SoPW, does anyone have experience writing Perl software or wrappers against anything Apple? I'm wiggling my way into a position of a starting point.

    Happy Holidays all, and thanks for being supportive of both Perl, and myself over the years. You're all the reason I've become the developer I have.

    Cheers,

    -stevieb

21! Another fun year passes
3 direct replies — Read more / Contribute
by talexb
on Dec 12, 2022 at 11:38

    The website didn't tell me anything exciting on my arrival today, but I know it's my Monk Day because it's also my older step-son's birthday. :) Matt's now 35 (yikes).

    My Dad, who was 90, died this Fall. He was a retired actuary, and loved Maths. His father was a higher-up at one of the insurance companies in London, so Dad kind of fell into that field, although I think his first love was trains and civil engineering. When I started to show an aptitude for math, he would gladly give me a problem (like calculating ten factorial) to go to sleep with. He worked on his insurance company's computer system, an IBM 360 package called A Life Insurance System (ALIS, an IBM product, obviously), written in COBOL. He also did some work in APL (another brilliantly name IBM package that stands for A Programming Language).

    So, by the time my high school got time-sharing access to the school board's mainframe so we could learn BASIC, he was all keen to jump in and try it out (Fall of '73), by writing a program that calculated the probabilities of the various blood types in a population. I became one of the nerds who would hang out in the computer room, trying out code and watching fellow nerds do cool stuff on the teletype. Sometimes, we'd download our programs to yellow paper tape.

    University work terms led to me learning assembler, and then C. Full time work led to Pascal, then awk and Perl. SQL crept in pretty soon after that. Once outside the safe walls of university, I had to figure out my own continuing education, which is where the Perl community came in. I started with the local Perlmongers, and continued with this community. It's a cool place to ask questions, read other folks' answers, and maybe provide some answers of your own.

    My education continues to this day. And I thank you all. :)

    Alex / talexb / Toronto

    Thanks PJ. We owe you so much. Groklaw -- RIP -- 2003 to 2013.

Double the speed of Imager->setpixel
4 direct replies — Read more / Contribute
by Anonymous Monk
on Dec 11, 2022 at 16:49
    My app was taking 5 seconds to generate an image involving about a million calls to Imager->setpixel and this felt way too slow. NYTProf revealed the cause to be expensive sanity checking in Imager.pm at lines 3456 and 3465. Commenting those lines gets me down to 3 seconds and this now feels much less slow:
    sub setpixel { my ($self, %opts) = @_; # $self->_valid_image("setpixel") or return; my $color = $opts{color}; unless (defined $color) { $color = $self->{fg}; defined $color or $color = NC(255, 255, 255); } # unless (ref $color && UNIVERSAL::isa($color, "Imager::Color")) { # unless ($color = _color($color, 'setpixel')) { # $self->_set_error("setpixel: " . Imager->errstr); # return; # } # } unless (exists $opts{'x'} && exists $opts{'y'}) { $self->_set_error('setpixel: missing x or y parameter'); return; } ... } sub _valid_image { my ($self, $method) = @_; ref $self or return Imager->_set_error("$method needs an image object"); $self->{IMG} && Scalar::Util::blessed($self->{IMG}) and return 1; my $msg = $self->{IMG} ? "images do not cross threads" : "empty inpu +t image"; $msg = "$method: $msg" if $method; $self->_set_error($msg); return; }
    Should the next version of Imager have an option to disable global sanity so it can operate almost twice the usual speed?
Schizophrenic var
1 direct reply — Read more / Contribute
by bliako
on Dec 05, 2022 at 16:59

    I admit that dualvar was a term I never felt looking up until it came up recently here at the Monastery at Re^2: Rosetta Code: Long List is Long -- dualvar by marioroy. And I had a look at it. I found that Scalar::Util's dualvar can indeed create such a variable but I did not find any way of driving an existing variable into schizophrenic behaviour.

    And so here is a gutty way to alter the string and/or numeric part of an existing scalar. Mind you I did a brief search on whether there was already some existing package doing that but did not find any.

    This can find applications in some cases of the Schwartzian transform where the "decorations" and "undecorations" can apply on existing data rather than creating new (re: decorate/undecorate, Schwartzian_transform). The concept is not new (e.g. see comments under https://www.endpointdev.com/blog/2009/08/perls-scalarutildualvar/), but I did not find anything without creating new (dual)var but altering existing var. So here it is in a single-file SCSE form (XS can be found in ./_Inline/build dir):

    ## by: bliako ## on: 2022-12-05 ## EDIT: kudos to https://metacpan.org/release/PEVANS/Scalar-List-Util +s-1.63/source/ListUtil.xs (line 1674, dualvar) use strict; use warnings; use Devel::Peek; use Inline Config => clean_after_build => 0; use Inline C => <<'EOC'; // alter the 'numeric' slot of existing var 'asv' with that of + 'theiv' void setIV(SV *asv, SV *theiv){ (void)SvUPGRADE(asv, SVt_PVNV); SvIV_set(asv, SvIV(theiv)); SvIOK_on(asv); } // alter the 'string' slot of existing var 'asv' with that of +'thesv' void setSV(SV *asv, SV *thesv){ sv_setsv(asv, thesv); } EOC my $num = 42; my $x = "My name is Ace!"; Dump($x); setIV($x, $num); Dump($x); setSV($x, "Hello Ozy!"); Dump($x); # and here is a one-legged Schwartzian transform # to sort strings on their lengths using above XS: my @unsorted = ("Just", "another", "Perl\x{7}\x{7}\x{7}", "hacker\x{7} +"); my @sorted = sort { $a <=> $b } map { setIV($_, length($_)); $_ } @unsorted; print "Sorted: @sorted\n"; ;

    Hacking away with Perl into the new year ... (actually I think I am in 2048 already, riding on Perl)

    bw, bliako

Rosetta Code: Long List is Long
12 direct replies — Read more / Contribute
by eyepopslikeamosquito
on Nov 30, 2022 at 17:27

    I've long found it fun to implement the same algorithm in different languages, especially Perl and C++ ... and then sit back and reflect on the lessons learned ... so when Long list is long appeared recently, I felt it was short and interesting enough to make an excellent Rosetta code node.

    Solutions to this problem must read a number of input LLiL-format files (given as command line arguments) and write a single merged LLiL-format file to stdout. The LLiL-format is described in the comments at the top of llil.pl below.

    In the interests of keeping the code as short and fast as possible, you may assume the input LLiL files are well-formed. For example, you don't need to check for and remove leading and trailing whitespace on each line. The sample solutions given below in Perl and C++ should clarify program requirements.

    Please feel free to respond away with solutions to this problem in your favourite programming language and to offer suggested improvements to my sample Perl and C++ solutions below.

    Perl Solution

    Here's my Perl solution, heavily influenced by responses to Long list is long, especially kcott's concise and clear solution:

    # llil.pl # Example run: perl llil.pl tt1.txt tt2.txt >oo1.tmp use strict; use warnings; # -------------------------------------------------------------------- +-- # LLiL specification # ------------------ # A LLiL-format file is a text file. # Each line consists of a lowercase name a TAB character and a non-neg +ative integer count. # That is, each line must match : ^[a-z]+\t\d+$ # For example, reading the LLiL-format files, tt1.txt containing: # camel\t42 # pearl\t94 # dromedary\t69 # and tt2.txt containing: # camel\t8 # hello\t12345 # dromedary\t1 # returns this hashref: # $hash_ret{"camel"} = 50 # $hash_ret{"dromedary"} = 70 # $hash_ret{"hello"} = 12345 # $hash_ret{"pearl"} = 94 # That is, values are added for items with the same key. # # To get the required LLiL text, you must sort the returned hashref # descending by value and insert a TAB separator: # hello\t12345 # pearl\t94 # dromedary\t70 # camel\t50 # To make testing via diff easier, we further sort ascending by name # for lines with the same value. # -------------------------------------------------------------------- +-- # Function get_properties # Read a list of LLiL-format files # Return a reference to a hash of properties sub get_properties { my $files = shift; # in: reference to a list of LLiL-format fil +es my %hash_ret; # out: reference to a hash of properties for my $fname ( @{$files} ) { open( my $fh, '<', $fname ) or die "error: open '$fname': $!"; while (<$fh>) { chomp; my ($word, $count) = split /\t/; $hash_ret{$word} += $count; } close($fh) or die "error: close '$fname': $!"; } return \%hash_ret; } # ----------------- mainline ----------------------------------------- +-- @ARGV or die "usage: $0 file...\n"; my @llil_files = @ARGV; warn "llil start\n"; my $tstart1 = time; my $href = get_properties( \@llil_files ); my $tend1 = time; my $taken1 = $tend1 - $tstart1; warn "get_properties : $taken1 secs\n"; my $tstart2 = time; for my $key ( sort { $href->{$b} <=> $href->{$a} || $a cmp $b } keys % +{$href} ) { print "$key\t$href->{$key}\n"; } my $tend2 = time; my $taken2 = $tend2 - $tstart2; my $taken = $tend2 - $tstart1; warn "sort + output : $taken2 secs\n"; warn "total : $taken secs\n";

    What makes this problem interesting to me is the requirement to sort the hash in descending order by value:

    sort { $href->{$b} <=> $href->{$a} || $a cmp $b } keys %{$href}
    because the performance of such a sort may suffer when dealing with huge files (after all, performance was the reason for the OP's question in the first place).

    I'm hoping solving this problem in multiple languages will be fun and instructive -- and perhaps give us insight into how performance changes as the number of items increases.

Code brewing for the upcoming MCE 10 year anniversary
4 direct replies — Read more / Contribute
by marioroy
on Oct 23, 2022 at 09:12

    Greetings, all

    The following is a glimpse of what's coming for MCE. There are two new modules; MCE::Semaphore and MCE::Simple. I completed the code tonight. Now, I need to finish the docs and more testing before releasing on Meta::CPAN.

    MCE Simple

    use MCE::Simple -strict, max_workers => 4; MCE::Simple->init( # mce options user_begin => sub { MCE->say("hello from ", MCE->wid); }, # spawn options on_finish => sub { my ( $pid, $exit, $ident, $signal, $error, @ret ) = @_; say "@_"; }, ); mce_foreach my $i ( 1..10 ) { MCE->say(MCE->wid, ": $i * 2 = ", $i * 2); } spawn "Hello", sub { "one" }; spawn "There", sub { "two" }; foreach my $ident (qw/foo baz/) { spawn $ident, sub { my $text = "something from $$"; }; } sync; # clear or set options MCE::Simple->init(); sub fib { my $n = shift; return $n if $n < 2; spawn my $x = fib($n - 1); spawn my $y = fib($n - 2); sync $x; sync $y; return $x + $y; } say "fib(20) = ", fib(20);

    Output

    $ perl demo.pl hello from 1 hello from 2 hello from 3 hello from 4 3: 2 * 2 = 4 4: 1 * 2 = 2 2: 3 * 2 = 6 3: 5 * 2 = 10 4: 6 * 2 = 12 1: 4 * 2 = 8 4: 7 * 2 = 14 3: 8 * 2 = 16 2: 9 * 2 = 18 1: 10 * 2 = 20 10792 0 Hello 0 one 10793 0 There 0 two 10794 0 foo 0 something from 10794 10795 0 baz 0 something from 10795 fib(20) = 6765

    MCE Semaphore

    A fast pure-Perl implementation. Testing involves big number. Notice the mce_foreach_s keyword, for processing a sequence of numbers.

    use MCE::Simple -strict, max_workers => 16; use MCE::Semaphore; use Time::HiRes 'time'; my $start = time; my $sem = MCE::Semaphore->new(8); mce_foreach_s ( 1 .. 1_000_000 ) { $sem->down; $sem->up; } printf "%0.3f seconds\n", time - $start;

    Input file

    mce_foreach_f ("/path/to/file") { MCE->print($_); } # what about file handles? no problem... open my $fh, "<", "/tmp/infile.txt" or die "open error: $!"; mce_foreach_f my $line ( $fh ) { MCE->print($line); } close $fh;
How not to implement updaters
2 direct replies — Read more / Contribute
by afoken
on Sep 30, 2022 at 17:25

    Every two weeks, I switch from embedded developer to network and server administrator to keep our network and servers at work up and running. Today, updating our issue/requirement/test tracking software was on the plan. We have four virtual machines, each running one instance of the software. I won't state its name, and I will neither confirm nor deny any guess. But let's say the manufacturer has recently demonstrated in that their idea of forcing their clients to use the cloud variant of their software instead of local servers might not be the best idea. Users don't like having years of work deleted from the cloud servers, without a way to undo that quickly and completely.

    Experience from previous updates has taught me to make a full backup of the entire VM before updating. So the day started with shutting down all four VMs and creating copies of their harddisk image files. Just to be sure. The VMs are relatively small, just a bare-bones installation of Debian plus a database plus the bugtracker software, so that four extra copies of the HDD images don't matter much.

    I planned the entire day for the update, expecting some trouble with the first VM to learn about the new issues during the update, and then be able to update the three other VMs much faster, knowing what issues to expect. So I was absolutely not surprised that the first update went bonkers.

    Act One

    The update installer did created some zip files of the existing installation (don't hope to be able to recover from a broken update using those zip files), then removed the entire old version of the bugtracker software and unpacked the new version. "Do you want me to overwrite some.freaking.dll in the program directory?" Sure, why not? If the installer wants to overwrite what was unpacked seconds ago, let it do so. I have a good HDD image. A few moments later, it started the web server and pointed me to http://localhost:someport/. No, that web interface does not work in lynx or links, we are running a server, not a point-and-shoot adventure game. But the web server is really listening on all interfaces, so I can connect using Firefox on my PC. After several minutes of the old "don't blink, you might miss the progress bar moving another pixel" game, the browser shows the well-known "oops, something went wrong" page.

    "We can't talk to the database." Well, the old version could. The old version had a database config file stating that we use a really exotic database. You probably never heard of it. It is called MySQL. Right out of the Debian package (so it is actually MariaDB). After some clicking on the eror page, you end at a wiki page of the manufacturer, which tells you to download a MySQL driver from a third party page. Yes, I really know that issue, and I should have thought about it, because it happened with every single update so far. It must be incredible hard to parse the database config file from the updater and instruct the admin right from the updater to download and install that driver BEFORE playing the waiting game. And it must be absolutely impossible just to bundle the driver like the tons of other crap that come with the software.

    So, copy the driver file (it really is just a single file!) to /opt/crap/crap/crap/lib/, restart the server, play the waiting game again. "Oops, something went wrong." Yes, sure. "We can't detect the database version." I could not care less. "We just discarded your old startup configuration, here is a link to our wiki how to fix that." Oh well, it's just fine-tuning of how much memory the bugtracker wastes. Defaults are fine for now. "There is an expired license installed, you are only allowed to update to versions that were released before that license expired." What? "Click here to buy a new license, click here to enter the new license code." There is no way to bypass that.

    I share the administration of the bugtracker with a coworker. She does the high-level stuff (workflow, addons and so on), I care about OS, database, network, backup, and basic installation. She told me that we don't actually use that license. The license is not for the bugtracker itself, it is for a component that wasn't even installed in the old version. The expired license is just garbage data, we don't use that component, we don't need that component. It once was installed, but nobody bothered to delete the license code.

    To make matters worse, there is no way to delete the expired license, or just tell the installer that we are willing not to be able to use the unlicensed component. At this point, you can either pay a lot of money to renew a license for a component that you don't want and don't need, just to get past that error screen, or shut down the VM and copy the backup copy of the HDD image over the actal HDD image. I did the latter.

    Act Two

    Restart the VM, remove that left-over license code, redo the update installation, this time copying the database driver before starting the webserver. "You were updated". No, the updater managed to do its job of updating the bugtracker. "Oh, and by the way, we are just rebuilding our search index. Because, you know, we can't search in the database." Actually, the last sentence was not displayed. But you have to wait for the index rebuild job has finished before you can continue.

    Well, the updater did not manage to do its job. "There are this 20+ apps that won't work for whatever reason." Good, let's see if the bugtracker does work at all. The personalized overview page displays fine, but where is the navigation bar? It's gone. You can't log out. You can't gain admin privileges. You can't navigate anywhere. Let's open an existing issue. "500 Internal Server Error - click here to see a long, useless stack trace and a random number that will identify this problem". Some other attempts of navigating elsewhere also ended in that 500 page. Well, that did not go well.

    Half a day has passed, and we just managed to kill the first bugtracker VM twice. Or, to be precise, watch it commit suicide. Guess what? Shutdown, copy the backup once more over the actual HDD image, and retry a third time.

    Act Three

    My coworker thought that one of that many add-ons that she installed might be responsible for the trouble. (I don't know why we need 20+ addons, we use the core functions, plus an add-on for requirements, plus one add-on for tests, plus one add-on for making the search function work properly.) So she decided to clean up the mess, uninstall everything not needed, including that expired license.

    It turns out that not everything uninstalled cleanly. "Something went wrong that you don't need to know. But if you really want to know, here is a link to an assistent that will tell you that we wrote some stack traces to one of the many log files." A 16 MByte log file. 390 kByte of which were created during the hour or so she tried to get rid of some garbage.

    Well, shut down the VM, make a second copy of the HDD image just to have a slightly cleaner state to work from. Redo the update, again copying the database driver. After the waiting game, I'm greeted by the same "You were updated" screen, and only three add-ons are inoperable now. A few clicks later, I once again get the overview page. Almost any click gets me either to a much uglier 500 page than before, or to the pretty 500 page. "Click here to download an archive with all relevant data you can mail to our support." Click - "500 Internal Server Error". Yes, you can't even download the crash report archive.

    VM suicide number three. After a short discussion, we decided to roll back to the very first backup I created in the morning. Copy the backup once again over the actual HDD image, start the VM again. Nearly eight hours have passed. We did not even try to update the three other VMs, we just started them in their old state.

    Epilog

    We wasted an entire day trying to update the software. It should be so simple. Run the update installer, add the database driver that the manufacturer does not bundle, watch the system update itself, run the new version. Or, if something is critical and might cause touble, get a good error message from the update installer BEFORE f-ing up the entire system.

    It is possible. I know it, because my main job is software development. It takes testing, and during testing and development, you (as the developer) expect things to go horrible wrong. That's why VMs are so great. One click and you are back to a known state that you can fail to update again, and again, and again, until the updater just works or stops before damaging the system. With embedded systems, reverting to a known state is not always that easy, but even there, it is possible to make updates just work or abort before things go wrong.

    I don't really want to know why the updater managed to kill our system three times, I just want it to do its job. Luckily, I'm on vacation now, and my coworker will contact the manufacturer of this crappy software. After my vacation, we will see how far she got.

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
CSS mods for the new metacpan layout
1 direct reply — Read more / Contribute
by hippo
on Sep 30, 2022 at 11:14

    You've probably seen the new styling of MetaCPAN by now. One anonymous monk is less than enthralled. It's not all bad, IMHO and will hopefully improve over time. Meanwhile here is the little snippet of userContent.css which I've put together today to restore a little sanity.

    Update 6th Oct 2022 with a fix for the search results and similar one-pane pages:

    @-moz-document url-prefix(https://metacpan.org/) { div.page-content { grid-template-columns: 200px calc(100vw - 200px +) !important; } .no-sidebar div.page-content { grid-template-columns: 1fr !importa +nt; } ul.nav-list { padding: 10px !important; width: 200px !important } ul.nav-list>li a, ul.dependencies>li>a { color: #337ab7 !important + } div.content { padding: 20px !important } #index-container { margin-left: 20px !important } }

    Original attempt was:

    @-moz-document url-prefix(https://metacpan.org/) { div.page-content { grid-template-columns: 200px calc(100vw - 200px +) !important; } ul.nav-list { padding: 10px !important; width: 200px !important } ul.nav-list>li a, ul.dependencies>li>a { color: #337ab7 !important + } div.content { padding: 20px !important } #index-container { margin-left: 20px !important } }

    This will:

    • Reduce the left nav from 300 to 200 pixels in width and reduce the padding on the main content so there is not so much wasted space (Don't ask me why they've gone with a fixed pixel width here to begin with)
    • Re-enable the different styling (colour) of links in the nav so you can tell what is a link and what is just info once again

    We'll see how much this needs tweaking over the next little while but at least if you are interested in this it saves us all reverse-engineering it independently.

    The new layout proposal and discussion is in the issues here.


    🦛

The new black metacpan (meta::cpan throws away brand)
1 direct reply — Read more / Contribute
by Anonymous Monk
on Sep 30, 2022 at 06:15
LWP::UserAgent Client-Warning 500 against HTTP standards?
4 direct replies — Read more / Contribute
by Discipulus
on Sep 30, 2022 at 03:35
    Hello community,

    being our halls so quite in these days I'm lazily inviting you to meditate about LWP::UserAgent behaviour returning 500 when LWP can't connect to some URL or when other failures in protocol handlers occur.

    Is this breaking HTTP specification? If ever glanced current rfc or not you should know that all 5** status code are server side.

    The LWP doumentation is very clear on this:

    > There will still be a response object returned when LWP can't connect to the server specified in the URL or when other failures in protocol handlers occur. These internal responses use the standard HTTP status codes, so the responses can't be differentiated by testing the response status code alone. Error responses that LWP generates internally will have the "Client-Warning" header set to the value "Internal response". If you need to differentiate these internal responses from responses that a remote server actually generates, you need to test this header value.

    Infact..

    use strict; use warnings; use LWP::UserAgent; my $ua = LWP::UserAgent->new(); for my $url ( qw( https://perlmonks.org https://perlmonks.roma.it) ){ print "\nGET $url\n"; my $res = $ua->get( $url ); # ..yes you can $res->status_line to have both combined print "code :\t", $res->code, "\n"; print "message :\t", $res->message, "\n"; print "Client-Warning header:\t", $res->header( "Client-Warning" ) +, "\n"; } __END__ GET https://perlmonks.org code : 200 message : OK Client-Warning header: GET https://perlmonks.roma.it code : 500 message : Can't connect to perlmonks.roma.it:443 Client-Warning header: Internal response

    The message returned is already very clear Can't connect.. is oblviously client side: so why the choose of an error of the 5** class?

    In the chat LanX suggested 418 I'm a teapot and is fun and new to me, but not usable: teapots are reserved to IANA :)

    In the 4** class are defined status codes 401-418 plus 421 422 426 so there is room to have something like: 419 - Can't connect

    See also other status numbers used to craft a HTTP::Response

    So (and I dont want to blame LWP authors) why they choosed to return 500 setting an header internally to disambiguate it?

    What other frameworks do? Quickly trying Mojo::UserAgent I see it uses it's own Mojo::Message::Response and does not return any status code for unexisting urls:

    use strict; use warnings; use Mojo::UserAgent; my $ua = Mojo::UserAgent->new; for my $url ( qw( https://perlmonks.org https://perlmonks.roma.it) ){ print "\nGET $url\n"; my $res = $ua->get( $url )->result; print "code :\t", $res->code, "\n"; print "message :\t", $res->message, "\n"; #print "Client-Warning header:\t", $res->header( "Client-Warning" +), "\n"; } __END__ GET https://perlmonks.org code : 200 message : OK GET https://perlmonks.roma.it Can't connect: Host unknown. at testLWP500.pl line 10.

    ..and this error is defined in Mojo::IOLoop::Client it seems to me a better design, but... wait this is a die behaviour! if you switch URLs in the above code you never reach the second GET.

    By other hand curl tell us it is unable to resolve the URL:

    curl -I https://perlmonks.roma.it curl: (6) Could not resolve host: perlmonks.roma.it

    ..and it is right.

    What do you think about? What other frameworks I missed do?

    Is 200 if you post 203 but no 204 will be accepted! :)

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Types, objects, and systems, oh my!
No replies — Read more | Post response
by awncorp
on Sep 19, 2022 at 17:01
What if Perl had an OO standard library?
8 direct replies — Read more / Contribute
by awncorp
on Aug 23, 2022 at 07:39

    Programming in Perl is choices all the way down. An OO standard library would make it a lot easier to write Perl in a way that avoids having to come up with similar or the same solutions to common computing tasks, but, ... sustained object-orientation in Perl is difficult because the concept and mechanisms were bolted onto the language as an afterthought, and because it's optional, so one has to oscillate between this paradigm and others, i.e. some things are objects, most things are not, so when using Perl you have to constantly reaffirm your object-orientation. What do you think?

    http://blogs.perl.org/users/al_newkirk/2022/08/introducing-venus-a-new-world-for-perl-5.html

    "I am inevitable." - Thanos

Add your Meditation
Title:
Meditation:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":


  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.