Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery

Seekers of Perl Wisdom

( #479=superdoc: print w/replies, xml ) Need Help??

If you have a question on how to do something in Perl, or you need a Perl solution to an actual real-life problem, or you're unsure why something you've tried just isn't working... then this section is the place to ask.

However, you might consider asking in the chatterbox first (if you're a registered user). The response time tends to be quicker, and if it turns out that the problem/solutions are too much for the cb to handle, the kind monks will be sure to direct you here.

Post a new question!

User Questions
CPAN namespace hierarchy
2 direct replies — Read more / Contribute
by GrandFather
on Jan 24, 2021 at 16:29

    Is there a way to browse the CPAN namespace hierarchy? I'm trying to figure out the best place to fit a new module for parsing and dumping selected contents of ELF files. I've scanned through the PAUSE docs that looked most likely to lead the way, but didn't see anything.

    Hmm, while preparing this question I found which is at least part of the answer, but somewhat unwieldy. Maybe I'll just have to put a Tk wrapper around that data unless someone has a suitably lazier option for me?

    Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond
Critique requested for module code - QuickMemo+ reader
5 direct replies — Read more / Contribute
by Lotus1
on Jan 24, 2021 at 12:47

    While I'm still thinking over the excellent suggestions I received for the name for the module here is the code. Please help with suggestions or critiques.

    The module extracts the memo text from the lqm files that QuickMemo+ exports. The lqm file is actually a zip file that contains a JSON file that contains the memo text so it was an easy module to write. Each memo is in a separate archive so it is very tedious to extract each memo by hand.

    package Data::QuickMemoPlus::Reader; use 5.008001; use strict; use warnings; use JSON; use Archive::Zip qw( :ERROR_CODES :CONSTANTS ); our $VERSION = "0.01"; use Exporter qw(import); our @EXPORT_OK = qw( lqm_to_str ); our $suppress_header = 0; sub lqm_to_str { ## pass an lqm file exported from QuickMemo+ my ( $lqm_file ) = @_; if (not -f $lqm_file){ warn "$lqm_file is not a file"; return ''; } my $note_created_time = ""; if ( $lqm_file =~ /(QuickMemo\+_(\d{6}_\d{6})(\(\d+\))?)/i) { $note_created_time = $2; } my $ref_json_str = extract_json_from_lqm( $lqm_file ); return '' if not $ref_json_str; my ($extracted_text, $note_category) = extract_text_from_json($ref +_json_str); my $header = "Created date: $note_created_time\n"; $header .= "Category: $note_category\n"; $header .= "-"x79 . "\n"; $header = '' if $suppress_header; return $header . $extracted_text; } ##################################### # Unzip jlqm file and # return json file contents. # sub extract_json_from_lqm { # unzip # extract the memoinfo.jlqm file. my $lqm_file = shift; # Read a Zip file my $lqm_zip = Archive::Zip->new(); unless ( $lqm_zip->read( $lqm_file ) == AZ_OK ) { warn "Error reading $lqm_file"; ####### to do: add the zip error to the warning? return ""; } my $jlqm_filename = "memoinfo.jlqm"; my $member = $lqm_zip->memberNamed( $jlqm_filename ); ############### to do: add warning here if memoinfo.jlqm is missin +g. if( not $member ){ warn "File not found: $jlqm_filename in archive $lqm_file"; return ""; } my ( $string, $status ) = $member->contents(); if(not $status == AZ_OK){ warn "Error extracting $jlqm_filename from $lqm_file : Status += $status"; return ""; } return \$string; } ############################################### # Decode json file contents and # return the text in 'DescRaw' sub extract_text_from_json { my $ref_json_string = shift; ############# To do: eval this and trap errors. my $href_memo = decode_json $$ref_json_string; if (not $href_memo){ warn "Error decoding text"; return '',''; } my $text = ""; foreach( @{$href_memo->{MemoObjectList}} ) { $text .= $_->{DescRaw}; $text .= "\n"; } my $category = $href_memo->{Category}->{CategoryName}; $category //= ''; $category =~ s/[^\w-]/_/; return $text, $category; } 1; __END__

    Update: I neglected to add my tests as Discipulus wisely pointed out. Since I have prove -l working now with my tests I have been enjoying refactoring and letting the tests help me find the errors.


    use strict; use Test::More 0.98; use_ok $_ for qw( LG::QuickMemo_Plus::Extract::Memo ); done_testing;


    use strict; use Test::More tests => 5; use Test::Warn; use LG::QuickMemo_Plus::Extract::Memo qw( lqm_to_str ); my $lqm_file = 'not_a_file'; warning_is {lqm_to_str($lqm_file)} "$lqm_file is not a file", "warn +ing for missing file."; $lqm_file = 't/data/good_file.lqm'; warning_is {lqm_to_str($lqm_file)} [], "no warnings for good file." +; $lqm_file = 't/data/junk.lqm'; warnings_like {lqm_to_str($lqm_file)} [ {carped => qr/format error:/i}, qr/Error reading $lqm_file/, ], "warnings for non-zip, junk file."; $lqm_file = 't/data/missing_jlqm.lqm'; warnings_like {lqm_to_str($lqm_file)} [ qr/File not found: memoinfo.jlqm in archive $lqm_file/ +, ], "warnings for archive missing file - memoinfo.jlqm."; $lqm_file = 't/data/garbled.lqm'; warnings_like {lqm_to_str($lqm_file)} [ {carped => qr/error: inflate error data error/i}, qr/Error extracting memoinfo.jlqm from $lqm_file/, ], "warnings for garbled file - memoinfo.jlqm.";


    use warnings; use strict; use Test::More tests => 10; use LG::QuickMemo_Plus::Extract::Memo qw( lqm_to_str ); BEGIN { unshift @INC, 't/lib'; } use_ok 'ExampleMemo'; can_ok 'LG::QuickMemo_Plus::Extract::Memo', 'lqm_to_str'; can_ok 'ExampleMemo', 'memo_with_header'; can_ok 'ExampleMemo', 'memo_with_header_no_timestamp'; can_ok 'ExampleMemo', 'memo_no_header'; can_ok 'ExampleMemo', 'jlqm'; my $lqm_file = 't/data/QuickMemo+_191208_220400(5).lqm'; is ( lqm_to_str($lqm_file), ExampleMemo::memo_with_header(), 'memo wi +th full header' ); $lqm_file = 't/data/good_file.lqm'; is ( lqm_to_str($lqm_file), ExampleMemo::memo_with_header_no_timestam +p(), 'memo with header - missing timestamp' ); $LG::QuickMemo_Plus::Extract::Memo::suppress_header = 1; is ( lqm_to_str($lqm_file), ExampleMemo::memo_no_header(), 'memo with + no header' ); is ( ${LG::QuickMemo_Plus::Extract::Memo::extract_json_from_lqm($lqm_ +file)}, ExampleMemo::jlqm(), 'jlqm json contents' );
Executing program with arguments from cgi script
2 direct replies — Read more / Contribute
by natol44
on Jan 24, 2021 at 12:27

    I need to run ffmpeg from a CGI script, of course with arguments: Video to process, watermark to add, etc, and output file.

    I put all this in one variable:

    my $order = "$ffmpeg -i $video -i $watermark parameters etc $output";

    with $ffmpeg is the program's address, $video the video address etc.

    then I tried with

    system "$order";

    Nothing works.

    If I write the output content of $order in the SSH command line, it works.

    Where am I wrong? Thank you!
Ordering Template cards
3 direct replies — Read more / Contribute
by Bod
on Jan 24, 2021 at 11:03

    An internal system for business displays a series of 'cards' which show key data across various parts of the business all in one place. These are quite diverse and cover things like property occupancy levels, future pricing data and call centre call volume.

    Currently this is implemented with a bespoke kind of template. There is an HTML file with placeholders for all the data items and a Perl script which gathers all the data from various systems across the business, reads the file, substitutes that data into the placeholders before displaying the output. It can be viewed at any time as a webpage but also runs twice per week from CRON and sends an email to key people. The script knows the difference by checking if $ENV{'GATEWAY_INTERFACE'} is defined.

    This system already has 106 placeholders and needs extra information adding to it and I've decided to take the opportunity to refactor it to use Template thanks to the good influence of the Monastery! As part of the refactoring I want to add the facility for different users to be able to view the system with the cards in an order to suit them. Perhaps even to be able to hide the ones that do not interest them. We operate an open information policy so everyone in the business is permitted to see everything so there are no permission issues but not everything is actually useful to everyone so it would be good if they could put the cards they use most at the top and ones they seldom use further down.

    In trying to work out how to implement this I have come up with a solution but it seems there must be a more elegant solution.

    I've considered having a database table consisting of 4 fields:

     - User_idUser      - Foriegn Key to primary of User table
     - Card_idCard      - Foreign Key to primary of Card table
     - metric           - order to display cards for user
     - visible          - boolean - show card to user?
    with User_idUser and Card_idCard being the composite primary key.

    Then have a Perl script (of course!) that reads the cards from the database in the order given by metric. For each card it calls a subroutine that assembles the appropriate data for that card and uses Template to display the template file for that card. There will need to be 12 template files plus one for header and footers. Something like this (untested):

    my $cards = $dbh->prepare("SELECT Card_idCard FROM CardList WHERE User +_idUser = $user_number AND visible = 1 ORDER BY metric"); $cards->execute(); while (my $card = $cards->fetchrow_array) { card_call_center() if $card == 1; card_price_data() if $card == 2; card_occupancy() if $card == 3; # etc etc } # ... sub card_call_center { # Collect data # from systems my $vars = { 'foo' => bar, 'some' => data, }; $template->process('', $vars); }
    But I especially do not like the conditional subroutine calls with magic numbers in the statement modifiers.

    Is there a more elegant solution?
    Should I be calling multiple template files from the script or should that processing be done within Template?

CGI package recommendation
5 direct replies — Read more / Contribute
by BernieC
on Jan 24, 2021 at 08:00
    I last did a CGIed website something like 25 years ago -- AJAX was _just_ becoming popular! At the time I just used I now would like to do another -- it is for a simple but CGIed site.. I don't need AJAX or a DB interface or the like. Is there a better/more modern package for that kind of thing than just {NB: I remember almost nothing about using -- it's been a long time :) so I'd have to start by studying the POD docs anyway, so if there's something newer/easier/better I'd be happy to try it.}
guidance on naming my first module for CPAN
6 direct replies — Read more / Contribute
by Lotus1
on Jan 23, 2021 at 17:05

    I'm looking for guidance on naming my first module for CPAN. So far I've been calling it


    The purpose of the module is to help me extract the large number of memos I have written on my LG smartphone in QuickMemo+. The module extracts the memo text from the lqm files that QuickMemo+ exports. I couldn't find any software that could open those files other than 7zip. The lqm file is actually a zip file that contains a JSON file that contains the memo text so it was an easy module to write. Each memo is in a separate archive so it is very tedious to extract each memo by hand.

    My questions are:

    • Is this name acceptable for CPAN? Some other options I considered are:
      • LG::QuickMemo_Plus::Memo::Extract
      • LG::QuickMemo+::Memo::Extract
      • QuickMemo_Plus::Memo::Extract
      • QuickMemo_Plus::Extract::Memo
      • QuickMemo_Plus::Extract
    • Is a module like this needed on CPAN?
      • I'm thinking it might be better to just make a small GUI and release the binary on Github. My plan is to do both. But I wonder how many Perl programmers would be interested in this module.
Papal infallibility
5 direct replies — Read more / Contribute
by Anonymous Monk
on Jan 23, 2021 at 00:51

    Larry Wall says "We will encourage you to develop the three great virtues of a programmer: laziness, impatience, and hubris."

    However the perlmonks listing of users by rank at Saints in our Book says "there are a lot of things monks are supposed to be, but lazy is not one of them!"

    Is this a test? Can I get some guidance on how I should act?
I am confused by a "Learning Perl" sample showing "unshift"
6 direct replies — Read more / Contribute
by KenAndrews
on Jan 22, 2021 at 15:41

    I am starting to learn Perl by reading "Learning Perl" and testing on a Centos box.

    I typed in a piece of code from the book and it did exactly what the book said it should do... But I don't know why!

    This is the code I typed in (modded to my coding requirements):

    use strict; use warnings; my @lArray; my @lNums = 1..3; unshift @lArray, 5; print "Array: @lArray\n"; unshift @lArray, 4; print "Array: @lArray\n"; unshift @lArray, @lNums; print "Array: @lArray\n";

    The output of the third print is "Array: 1 2 3 4 5", exactly as the book showed. My question is why is it that way? After thinking about it my expectation was that it would be "Array: 3 2 1 4 5".

    I expected "unshift @lArray, @lNums" to expand to "unshift @lArray, 1 2 3" and then be processed as though:

    unshift @lArray, 1 unshift @lArray, 2 unshift @lArray, 3

    However, it doesn't. It looks like the unshift operation is processing the values given in reverse order (3 2 1). Is this true? If not, how is it putting them in in the given order rather than reversed?

    Anyway, that's my problem; totally confused by Chapter 3.

.dancer -- what's it for
2 direct replies — Read more / Contribute
by kcott
on Jan 22, 2021 at 11:28

    G'day All,

    I keep seeing the file '.dancer' when working with Dancer2. It's in every tutorial but never explained. I've no idea what this file is for.

    Any ideas?

    — Ken

Internal SSL error after Ubuntu update
4 direct replies — Read more / Contribute
by afoken
on Jan 22, 2021 at 08:04

    It's Friday, I've switched from developer to admin, as usual, and decided to upgrade some of our machines.

    There's a script to set permissions on a Linux machine based on what can be found in an LDAP server of the Samba NT4 domain controller. Not pretty, but it is working.

    After updating to Ubuntu 20.04.1 LTS, LDAP access does not work any more:

    SSL connect attempt failed error:14161044:SSL routines:state_machine:i +nternal error at myscript line 23

    Line 23 is:

    my $ldap=Company::LDAP->new();

    Company::LDAP inherits from Net::LDAP and reads all required options for Net::LDAP->new() from a global configuration file:

    my $conffile='/etc/ldap.conf'; sub my_conf { state %conf; my $key=shift; unless ($conf{'.read'}++) { open my $f,'<',$conffile or die "Can't open $conffile +for reading: $!"; while (<$f>) { next if /^\#/; next if /^\s+$/; s/^\s+//; s/\s+$//; my ($k,$v)=split /\s+/,$_,2; warn "Duplicate key $k in $conffile line $.\n" + if exists $conf{$k}; $conf{$k}=$v; } close $f; my $fn=$conffile; $fn=~s/\.conf$/.secret/; open my $f2,'<',$fn or die "Can't open $fn for reading +: $!"; $conf{'.secret'}=<$f2>; chomp $conf{'.secret'}; close $f2; } return $conf{$key}; } sub new { my $proto=shift; my $uri=URI->new(my_conf('uri') // die "Missing uri in $conffi +le\n"); my $host=$uri->host(); my $scheme=$uri->scheme(); my $path=$uri->path(); my $port=$uri->port(); my %opts=( onerror => 'die', host => $host, scheme => $scheme, port => $port, timeout => my_conf('timelimit')//120, version => my_conf('ldap_version')//3, inet4 => 1, inet6 => 0, ); my $ldap=$proto->SUPER::new($host,%opts) or die "Can't connect + to $host: $@"; if ((my_conf('ssl')//'') eq 'start_tls') { %opts=(); $opts{'verify'}='none'; $opts{'cafile'}=my_conf('tls_cacertfile') // die "Miss +ing tls_cacertfile in $conffile\n"; # $opts{'capath'}=$opts{'cafile'}=~s|/[^/]+$|/|; $opts{'sslversion'}='tlsv1_1'; $ldap->start_tls(%opts); } return $ldap; }

    /etc/ldap.conf is

    base dc=company,dc=de uri ldap:// ldap_version 3 rootbinddn cn=ldapadmin,dc=company,dc=de timelimit 5 bind_timelimit 3 pam_password crypt ssl start_tls tls_cacertfile /etc/ssl/certs/company-cacert.pem

    (plus a lot of comments)

    The problematic machine is actually a copy of another machine, still running the older Ubuntu 18.04.5 LTS. That one runs exactly the same code without problems.

    Google gave me tons of results, but with an SNR close to zero. I've no clue what is wrong here.


    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

Add your question
Your question:
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, 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, 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.
  • Log In?

    What's my password?
    Create A New User
    and the web crawler heard nothing...

    How do I use this? | Other CB clients
    Other Users?
    Others contemplating the Monastery: (8)
    As of 2021-01-24 22:19 GMT
    Find Nodes?
      Voting Booth?