Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

Meditations

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

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
$class = ref($class) if ref($class) Redux
3 direct replies — Read more / Contribute
by boftx
on Jul 04, 2014 at 00:51

    It has taken me a while to come around to the position that using code such as that in the title (or similar) is really cargo-cult programming. Given that seems to be the case, then I was somewhat dismayed to see that Moo automatically includes such when it generates a constructor.

    I initially got around this by using before new to detect the presence of a ref instead of a string and issuing an appropriate croak message. (tip of the hat to the folks on #moose for that!)

    However, several others on #moose, notably some of the authors of Moo, said that was not a wise practice, and indeed, I found that the code was position dependent in relation to where BUILDARGS is defined. Specifically, the code for before new must come after BUILDARGS is defined or else the return value from that gets blown away.

    After asking a couple of questions, and getting the expected response of "Well, write it yourself!" I decided to do just that. I have a working patch to Moo that disables the code in question, replacing it with an exception.

    My question at this point is this: Is the ability to force a constructor to be a "class only" method a viable feature to have in Moo (and be extension, Moose)?

    The solution I arrived at after reading the code for Moo and a few other MooX modules led me to use an option passed into Moo's import method. This was mainly due to the fact that other than a significant refactoring of Method::Generate::Constructor it does not seem feasible to alter the code being generated.

    While I am waiting for a review of my proposed patch, I'd like to hear the thoughts of my fellow monks if this is a desirable option to have.

    You must always remember that the primary goal is to drain the swamp even when you are hip-deep in alligators.
RFC: Converted Fiscal5253 from Classic OO Perl to Moo
1 direct reply — Read more / Contribute
by boftx
on Jul 02, 2014 at 22:53

    I have just finished converting DateTimeX::Fiscal::Fiscal5253 from classic OO Perl to Moo. I would greatly appreciate any comments that result from taking a look at the changes. The test suite required almost no changes (mainly tightening up) so I am fairly confident that I have it close to being correct.

    You can find the Moo branch here on GitHub: https://github.com/boftx/DateTimeX-Fiscal-Fiscal5253/tree/moo-delegation (The current release is in the master branch as one might suppose.)

    I would like to get some feedback before I release even as a devel version since I am fairly certain it will pass the CPAN testers without a problem as it is passing a make disttest on my platform.

    Update: Of special interest is that I had to place a modifier on "new" in order to force "new" to be a class-only method. That is, to ensure that one could not call it as $obj->new. This works as desired, but what is interesting is that the call to before new must come after the code for BUILDARGS or else the returned arg list from that gets blown up somehow before the object is instantiated.

    You must always remember that the primary goal is to drain the swamp even when you are hip-deep in alligators.
why Perl is good, it works
1 direct reply — Read more / Contribute
by zentara
on Jul 01, 2014 at 20:59
    Well, just to give a glimpse into what complexities we are
    being faced with, with ever increasingly complex and
    interdependent libraries, I would like to relate to
    you my day.

    So I'm going to try and make my own Gtk3 theme. A
    noble effort.

    So I here that every release breaks the internal
    css engine ( yes, CSS !!!) ... the bane of us all

    So in order to get a theme going I figured I would get
    the latest version of Gtk+ 3.13. Ok, after figuring out how
    to install it, I find the themes don't work as
    discussed in the forums, so I decide to backtrack
    to the latest stable version 3.12

    ... lo and behold, the themes worked as advertised

    ... So I get gtkparasite too, to really play with
    the settings

    Now, of course I wanted to share my new great theme
    with the world, so I fire up my trusty gftp, and
    for some reason involving the use of ftps, the
    program would hang at "receiving files".

    Now, where to find a ftps gui program that worked?
    I eventually settle on FileZilla as the only
    recommended GUI, but it came down as a binary
    Wx file

    I wanted source code, so I finally delve
    down 5 layers of menus and find the FileZilla
    source code

    I download it, try to build it and it fails with
    an error, needs WxWidgets

    no problemo, I get the latest version of Wxwidgets,
    and it installs fine

    I go back to FileZilla, try to compile, and it says
    "soory, you have version 3.0 of Wx, and we need version
    2.8.12"

    No problem, I get Wx-2.8.12 and try to compile:
    It fails with <gtk.h> cursor.h not found

    ...exasperated, I search for commandline solutions
    to do whole directory uploads via ftps

    Everyone recommends lftp, so I googled and followed
    everyones ftps lftp set commands, but nothing
    worked ... lftp's ftps would fail with unknown
    protocol
    everytime

    I finally deduced after a git download of lftp's
    git repository, and the required git clone of libtool,
    that my Perl script using Net::FTPSSL, was the only
    thing that worked

    What really tore at me, was when the libtool output
    lines were flashing by on the screen, they said
    Libtool: Doing nothing

    There must be an intelligence behind it all. :-)

    Perl just does it right, it's my only way to
    do ftps ... the C programs be damned. :-)

    My understanding now, is that my lsftp, which
    comes stock with my Slackware, was built for
    SSL, and not TLS encryption, and my ftp
    server uses auth TLS

    So I spent 5 hours, searching for a complicated
    software fixes, because sites are using TLS, and
    other software comes with OpenSSL only

    But Perl worked, I am proud to report. Out of all
    the mucked up software out there, only Perl
    would connect, and let me do what I need to do

    Finally, this whole diatribe just goes to show,
    the value of Tk. Simple to install, no collections
    of libs required, and the Tk::Zinc Canvas is the only
    decent, documented Perl GUI canvas available to
    Perl

    Working with software is the game, a maze to get
    thru, and a prize waits at the end

    I was looking for a Angry Bird's sized new app,
    how about a software maze ... you need to show
    intelligence and ingenuity to get to some prize
    at the center of the software maze

    Work thru the javascript, the css, the various
    maps that only can be seen with difficult to
    install software

    I give the idea free to the world, to stimulate
    hackers and students everywhere.

    I mean it's a great idea, but I don't want to do it. ;-)



    I'm not really a human, but I play one on earth.
    Old Perl Programmer Haiku ................... flash japh
Advice needed
5 direct replies — Read more / Contribute
by baxy77bax
on Jul 01, 2014 at 10:56
    Hi,

    As in every discussion there is always an out of framework post, not particularly related to other posts but a person asking needed to start somewhere so there you have it. This is that type of a post.

    So I finally decided it is time to move on. I am not young enough to change the job and start all over with my 90' programming skills (like someone nicely phrased it in response to one of my previous posts here) and not old enough or should I say not arrogant enough to steal someones else's position in the company I currently work at. So I decided to start my own business. Since I've been in system administration and search engines for a while now and know a thing or two about it I decided to frame my business idea around it. However for that I need a financial injection and/or an access to a machine (hopefully not too expensive) where I can set up my Internet business. Since this is not a typical internet sales framework I cannot just set up a web site and start selling. I need a full unix/linux environment with ca. 100GB of disc space 4-8 cores 4-8 GB of RAM and an Internet domain. Is there any service that you know that can rent something like that? Second I never programmed any money transfer app. And have no idea how to do it right now so is there any perl module that can be used to do something like that? Or how do people setup something like that so a client can safely make a money transfer. Essential I need some basic first hand advice on how to start an online business. How to register it even if I am looking at some donation based system like here at perlmonks. I have been googling a lot about the subject but there are bunch of advices like

    1. Have an Idea.
    2. Register a company
    3. Make a website
    4. Make a gazillion dollars

    Well maybe it is just me, but this is so vague that I cannot even begin to rationalize what the author meant or what was he/she thinking when writing something like that. So if there is anyone here that has some experience with it and willing to share I would gladly take some advice. (Positive or negative, both are welcomed)

    cheers,

    baxy

[RFC: Cool Uses for Perl] A weighted randomized word generator for conlangers
1 direct reply — Read more / Contribute
by flowdy
on Jun 20, 2014 at 18:32
    Hi,

    A decade or so ago, I was a conlanger. I liked to construct a language spoken by a virtual people I didn't however, in contrary to J.R.R. Tolkien, shape regarding their culture. Obviously I had a plenty of mind capacity for such things, and they called me quixotic. No more. Now I prefer programing and hobbies and a real life, too. I remember that the grammar part was in favour compared to developing a comprehensive lexicon so the language is talkable. Inflection and word order and features I liked in other languages however were far more interesting. The best part about it I found were its 35 cases, actually two case systems interacting like cogwheels.

    I just programmed a word generator as a kind of tribute to that young nerd's passion. It respects how words can be shaped in a language and how not. In English for instance there is no word like quirge, but it still seems more English than, er, dampfschiff which is by the way, believe it or not, actually a word in a spoken language. These unwritten principles are characteristic for every language. Despite of their being unwritten, you can approximate these principles by probabilistic shares and the rand() of perl.

    Even if you are not interested in conlanging, you might want to study this example how curried closures can lead to efficient code, i.e. code of which I am quite sure it's efficient, until someone will prove me wrong. For those who do not know yet: Closures are anonymous subroutines that cling, for their own life-time, to any used lexical variables which would have been garbage-collected otherwise on going out of their respective scopes. Higher Order is when you pass these subroutine references to other functions which call them back when appropriate. Learned that once from the High Order Perl book by Mark J. Dominus (available online but if you can effort it, consider buying it).

    Update: Corrected name of the Higher Order Perl author. Further confused Currying and Higher Order. Will have to re-read myself the very book I cited.

    -- flowdy

Perl Job Marketability Question - very important for me!
6 direct replies — Read more / Contribute
by o2bwise
on Jun 13, 2014 at 17:55

    Hi,

    I got laid off a couple of months ago and am in the midst of the whole job search process. With that in mind, one thing I am wanting to have a good idea of is my marketability.

    I have been programming in Perl for close to 15 years now, but I think my use of the language has been pretty limited in scope.

    Now, my last job included an application called CA eHealth. I did a ton of Perl programming involving this application. (In fact, I largely lost my job due to my employer’s decision to replace this application.)

    There is one particular kind of scripting that I just love, but I am frankly unsure if it is sufficiently marketable. What I love doing is having Perl read data from a number of sources (databases, flat files) and produce desired data. I just LOVE that kind of coding. I love the whole portion in between those two points. Data aggregation, coming up with one or more nested hash data structures, looping through the hashes and writing out data as needed. Sometimes needing to do math and/or stats as part of the data aggregation. Mining through lines of text and db queries, and so on.

    My question is, is just the above thing I love to do marketable? I honestly do not know, but I sure hope so.


    Tony

Bring back the smartmatch operator (but with sane semantics this time)!
6 direct replies — Read more / Contribute
by smls
on Jun 10, 2014 at 12:52

    No I'm not kidding, please hear me out... :)

    History of smartmatch in Perl

    Smartmatching was invented for Perl 6 where it turned out to be a very useful and well-loved1 feature, but the attempt to backport it to Perl 5.10 in 2009 did not turn out so great (and it was consequently deprecated again in Perl 5.18). Among the Perl 6 community the commonly accepted explanation for that is, from what I heard:

    • Perl lacks a strong & fine-grained type system (which in Perl 6, where it exists, adds much sanity to the concept of dynamic dispatch)
    • Perl lacks composable related features like Junctions (which allow the Perl 6 smartmatching rules to be simpler and less arbitrary than the rules that would be needed to facilitate the same set of use-cases in Perl)

    These limitations are hard to circumvent, but I don't think that means Perl should have no smartmatching at all, it just means it should have less ambitious / more focused smartmatching.

    I wasn't around at the time, but it looks to me as if the Perl 5.10+ smartmatching was designed with these goals:

    1. Support all use-cases that the Perl 6 smartmatch operator supports
    2. Use it as an opportunity to sneak in useful new comparison/searching operations into the core, without having to invent separate operator names for them, and without having to justify them individually

    ...and was thus doomed to failure.

    Some later proposals for re-designing the smartmatch operator (like this 2011 post by brian d foy) tend to avoid mistake no. 1, but still fall into the second trap.

    If there are comparison/searching operations that are deemed worthy of being added to Perl (say, "deep comparison" of two arrays, or checking whether an array contains a given scalar), then each of them should get its own operator. That's the normal Perl way: One operator per type of operation (that's why we have both == and eq for example).

    How smartmatch should be designed

    Smartmatching explicitly breaks with the conventional "one meaning per operator" rule by dynamically deciding what operation to perform based on its arguments. This means it should be carefully designed around use-cases where you actually need to dynamically decide what operation to perform. Operations that you would likely never want to mix-and-match, have no business being part of the smartmatch operator, even if they would be useful to have in core by themselves.

    So, what are those use-cases where you actually need dynamic smartmatching? I can think of two major ones:

    1. When you want to avoid writing out  ($_ <operator> ...)  in a given/when construct, for the purpose of brevity/elegance:

      use v6; given $username { when 'root' { dostuff } when /^guest\d*$/ { die "You're not allowed to do stuff." } when any(<http apache>) { authenticate :web; dostuff } default { authenticate :local; dostuff } }

      Of course it is only elegant when the meaning is self-evident without consulting a manual, so this use-case only makes sense for commonly used & unambiguous comparison operations.

    2. When you want your code to test things against a "filter/pattern/rule" that is passed in from the outside, and you don't want to restrict it to just one way of filtering (e.g. only by string comparison, or only by regex, or only by callback etc.)

      For example, consider the Perl 6 built-in function dir, which lists the contents of a directory in the filesystem. It takes an optional 'test' argument, against which it promises to smartmatch each filename and only return the matching ones. Since smartmatch is built into the language, Perl 6 programmers need no further documentation to understand that parameter; they know they can use anything that would be valid as the right-hand-side argument of ~~ as the test, for example:

      use v6; dir '/some/directory', test => /\.txt$/; # a regex dir '/some/directory', test => none('.', '..'); # a junction² dir '/some/directory', test => &validate_filename; # a coderef

      The result is a very flexible but still elegant and predictable API that is easy to imitate in your own functions/modules that want to allow their users to "match" or filter stuff: Just use smartmatch as your filter implementation!

    We can make new Perl 5 smartmatching rules useful for those use-cases, while still keeping them sane and predictable, by adhering to the these two principles:

    1. Decide what operation to perform, based on the type of the right-hand-side argument (and nothing else!)
      (Put another way, this means that  LHS ~~ RHS  can always be expressed in words as the question "Does LHS fit the constraint/template defined by RHS?")

    2. Blindly coerce the left-hand-side argument to the type that the chosen operation requires, just as normal Perl operators like eq also coerce their arguments.
      (So, for example, @foo ~~ /foo/ would be the same as @foo =~ /foo/, even though that may not be useful, rather than doing anything special just because it's an array!)

    Sensible smartmatch rules

    With that in mind, we can start to think about the kind of right-hand-side "things" that it should be possible to smartmatch against.

    The following are no-brainers imo:

    if RHS is an... (example) then  LHS ~~ RHS  should do...
    undefined scalar $x ~~ undef !defined(LHS)
    simple scalar $x ~~ 'foo' LHS eq RHS
    regex (literal or reference) $x ~~ /foo/ LHS =~ RHS
    code reference $x ~~ sub { ... } RHS->(LHS)
    an object that overloads ~~ $x ~~ $object call the overload method, with LHS as argument

    The 'simple scalar' case is not as elegant as one might wish it to be; Ideally it would be able to dynamically decide between string or numeric comparison like it does in Perl 6, but I don't think that is possible to do safely in Perl (its type system being what it is), so we need to take what we can get.

    The following two rules also tend to be pretty useful in Perl 6, and it might make sense to add them to our hypothetical new Perl smartmatch, but I'm unsure about them because range literals and typename barewords are not usually treated as first-class "things" in Perl, so it might feel strange:

    if RHS is a... (example) then  LHS ~~ RHS  should do...
    bareword $node ~~ XML::LibXML::Node ref(LHS) eq "RHS"
    range literal $age ~~ 0..17 interpret LHS as a number, and check if is within the range

    Lastly, the lack of junctions in Perl could be partially remedied by interpreting an array/list on the right-hand-side like an any() junction:

    if RHS is an... (example) then  LHS ~~ RHS  should do...
    array or list $switch ~~ qw(yes true on 1) (grep { LHS ~~ $_ } RHS) >= 1

    Of course, a better solution would be to add junctions to Perl together with re-adding smartmatch... :)
    (Perl6::Junctions already exists on CPAN, but it relies on at least one awful hack due to the fact that it is non-core).

    Anyway, the above rules would be more or less a subset of both Perl 6 smartmatching and the deprecated Perl 5.10+ smartmatching, but without the craziness of the latter.

    And that's it; All cases not handled by these rules should generate a runtime error.
    I don't think any other special cases need to be added - in particular, all the arbitrary behaviors that Perl 5.10+ smartmatching added for when one or both arguments were arrays/hashes, only served to confuse people and made the operator "not safe to use" in practice. Let's not repeat that mistake.

    PS: In case you want to get a "feel" for what this kind of smart-matching is like in practice, check out Toby Inkster's match::simple module which implements very similar rules to what is discussed here (but suffers from some unavoidable limitations due to the fact that it is not in core).

    ---

    1) Among the small but passionate fan base of Perl 6 :)
    2) This particular junction is in fact used as the default when the 'test' argument is omitted.
RFC - early draft of Menu::Simple
2 direct replies — Read more / Contribute
by RonW
on Jun 06, 2014 at 13:13

    A while back, to further simplify making menus for occasional Tk driven Perl tool, I started Menu::Simple as an alternative to the -menuitems option in Tk::Menu::Items. It has significantly helped others to add their own Tk GUIs to Perl tools. (None of us here do much GUI coding, so anything that makes it easier helps us.)

    Recently, while adding a Tk GUI to yet another tool I created using Perl, it occurred to me that Menu::Simple might be worth sharing.

    It still needs more documentation, but I do have a simple example that shows the basic usage. (It also needs some clean up. Over time, I have changed and enhanced it. Just haven't thought about sharing outside my team at work.)

    So, here is the module and usage example. (Warning: It currently uses the 'current_sub' feature, so at least Perl 5.16 is needed.)

    Update: Determined that Perl 5.16 is currently needed. Will try to make it work with earlier versions.

    Update 2: After clean-ups, of course, would this be worth submitting to CPAN? Maybe change the name to Tk::Menu::Simple?

    Update 3: Removed requirement for Perl 5.16, but not sure how old a Perl it will work with.

    Update 4: Added a draft of documentation. Also, changed name to Menu::Builder. (I am planning to contact the maintainer of the Tk namespace on CPAN about having this included as Tk::Menu::Builder.)

at continue, last
7 direct replies — Read more / Contribute
by djerius
on Jun 06, 2014 at 00:53
    Update The imprecise nature of the language in this post has muddied the waters. The point of the post was to enumerate some ways of ensuring a single path for cleanup from a conditional clause, not all of them practical. My thanks to the respondents who persevered in spite of the muddiness of the water.

    On to the original post...

    I need to ensure that a variable is decremented regardless of how an if clause is exited, which might be in the middle of the block. I can code it this way:

    if ( $condition1 ) {{ ... --$loop, last if $condition2; #bail! ... --$loop; }}
    The repeated decrements are not DRY. This one is better:
    if ( $condition1 ) { { ... last if $condition2; ... } --$loop; }
    Along the way I stumbled upon these monstrosities:
    for ( ; $condition1 ; $loop--, last ) { ... next if $condition2; ... }
    Even worse:
    while ( $condition1 ) { ... next if $condition2; ... } continue { --$loop; last; }
    A last in a continue? Who knew?
Tiny Perl puzzle
4 direct replies — Read more / Contribute
by Dominus
on Jun 05, 2014 at 17:16
    Without testing first, guess what this program will print:
    print (two + two == five ? "true" : "false")
    Then figure out why you were wrong. (Please mark spoilers accordingly.)
Perl::Minimal -- the good, bad, and the ugly...
7 direct replies — Read more / Contribute
by taint
on May 29, 2014 at 21:18
    Hello, Monks.

    I've seen quite a few questions in SOPW related to creating, or working with Perl installs of Reduced size. The thought occurred to me, that maybe there was some potential to something in the Minimal::Perl | Perl::Minimal namespace on the CPAN.

    But maybe not. I can see where there is great diversity needed to satisfy the needs of every-wants-a-smaller-version-of-perl project.

    Maybe so. But maybe there is some "common ground". Some RE of "features" that would only require some small subset of Modules to complete the scheme for any given project.
    In other words; some small subset of Modules only needed to be added to the Minimal-Perl.

    Anyway. I thought this topic had merit, and thought it'd be wonderful to get some feedback on the concept, from everyone.

    Thanks for taking the time.

    --Chris

    UPDATE: added some clarity.

    ¡λɐp ʇɑəɹ⅁ ɐ əʌɐɥ puɐ ʻꜱdləɥ ꜱᴉɥʇ ədoH

Thought(s) about SOP questions...
6 direct replies — Read more / Contribute
by wjw
on May 23, 2014 at 13:34

    SOP on PM: a basic template for successful questions


    Purpose:

    To provide a 'thought' template (or form/checklist) that `concisely' guides a SOPW participant through preparing to post a question on said SOPW.

    How do I post a question effectively? is one of the places to really dig in to writing a good post. This hopefully serves the purpose of getting you to think about all that good advice.


    What I am working on(brief overview)
    • Platform
    • OS
    • Integrating with...(excel, libreoffice...etc...)
    • Perl Version
    • Using (module::name::?) if appropriate
    • What I want for output
    • What I am using for input
    • Combine this with 'What the problem is' below and you will have a good start to answering How do I compose an effective node title?
    What the problem is
    • First, ensure this is not XY Problem
    • Post relevant code (use code tags, 'code' or 'code')
    • Keep to relevant portions.
    • Make sure it compiles (or would if complete, copy exactly what you have(not data though))
    What you have tried
    • If you provide some of the above, it will prove you did something and are not looking for free coding service.
    Errors you're are getting ... if you already tried the following: (helpfully suggested by LanX)
    • use warnings;
    • use strict;
    • use diagnostics;
    • Then:
    • Copy/paste the errors in code tags with the rest of your post.
    My input
    • Include __DATA__ block or at least a few lines of the input file(also in code tags, 'code' or 'c')
    • If it is a known format like JSON or TNNAME.ORA, mention that.
    • Clean it for security purposes, but don't screw it up! Original size, character counts etc... are important!
    What it is you don't understand about solving the problem
    • I don't know how to format...
    • I don't understand the data structure...
    • I don't understand this code at line...
    • ...

    Further excellent suggestions regarding the subject matter from other PM's:


    If you manage to get at least one clear, concise statement about what you are trying to solve from each those first three main categories, you are likely to get pretty good, pretty quick help. If you can't do that, go back and ask yourself those questions in the first three categories, get them clear in your head, then write them. The clarity of your question might lead you to your own answer, and if not, it will surely help those attempting to assist you...

    No one is going to beat you up for not knowing how to state every question above. Hell, my posts have sadly not even followed this format! They will from now on! But if you give it half a shot your results are going to be a lot more satisfying, and the questions you get about your question for clarification will help you better define your question, and therefore your solution. Really, this is all covered in [id://174051>, but here is some of it again...

    Hope that is helpful...


    A solution is simply a well stated problem...otherwise the problem is not a problem, it is a fact...

      Updates:(newest first)
    • Added a few select links
    • Clean up, re-order in more logical step by step sequence base on other successful SOP postings(based on my opinion
    • Added link to suggestion, Added 'Purpose Statement'
    • Clean up, clarify Title
    • Added reference to XY problem
    • Added this update list
    • Added suggestions from subsequent posters
      ToDo
    • Provide example of Excellent Question
    • Provide example of Marginal Question
    • Provide example of Poor Question

    ...the majority is always wrong, and always the last to know about it...

    Insanity: Doing the same thing over and over again and expecting different results...

RFC: config::simple vs config::ini
3 direct replies — Read more / Contribute
by thanos1983
on May 20, 2014 at 19:23

    Dear all,

    Recently I discovered, thanks to people of this forum the use of Benchmark. A great powerful tool comparing speeds, processes and times.

    Well since I love playing around with details I could not resist to make this make not useful test and compare the Config::IniFiles Vs Config::Simple.I decided to run an experiment and observe the output.

    Update:

    Thanks to Anonymous Monk and davido for their contributions and suggestions, I have modified my experiment and came up with new data.

    The experimental code:

    #!/usr/bin/perl use strict; use warnings; use List::Compare; use Config::Simple; use Config::IniFiles; use Fcntl qw(:flock); use Benchmark qw(:all) ; use Data::Dumper qw(Dumper); $|=1; #flush every time the program =flock sub LOCK_SH { 1 } ## shared lock sub LOCK_EX { 2 } ## exclusive lock sub LOCK_NB { 4 } ## non-blocking sub LOCK_UN { 8 } ## unlock =cut my %information; my $path = 'conf.ini'; my $count = -5 || die "Need a count!\n"; sub complex { open my $fh , '<' , "".$path."" or die "Could not open file: ".$path." - $!\n"; flock($fh, LOCK_SH) or die "Could not lock '".$fh."' - $!\n"; tie my %ini, 'Config::IniFiles', ( -file => "".$path."" ) or die "Error: IniFiles->new: @Config::IniFiles::errors"; close ($fh) or die "Could not close '".$path."' - $!\n"; print Dumper(\%ini); return %ini; } # end sub complex sub val { open my $fr , '<' , "".$path."" or die "Could not open file: ".$path." - $!\n"; flock($fr, LOCK_SH) or die "Could not lock '".$fr."' - $!\n"; my $cfg = Config::IniFiles->new( -file => "".$path."" ) or die "error: IniFiles->new: @Config::IniFiles::errors"; close ($fr) or die "Could not close '".$path."' - $!\n"; my $values = $cfg->val( 'Perl', 'test' ); my @array = split(',', $values); print Dumper(\@array); return @array; } # End of sub val sub simple { open my $fr , '<' , "".$path."" or die "Could not open file: ".$path." - $!\n"; flock($fr, LOCK_SH) or die "Could not lock '".$fr."' - $!\n"; Config::Simple->import_from( "".$path."", \%information) or die Config::Simple->error(); close ($fr) or die "Could not close '".$path."' - $!\n"; print Dumper(\%information); return %information; } # End of sub simple my $r = timethese ( $count , { 'complex' => '&complex', 'val' => '&val', 'simple' => '&simple' } ); cmpthese $r;

    I am using a common conf.ini folder that both scripts are reading from with flock process applied since I am planning to use in combination with other scripts.

    Sample of the conf.ini folder:

    [Perl] test= bar,baz,foo,quux

    The results after the test are the following:

    val: 6 wallclock secs ( 5.69 usr + 0.30 sys = 5.99 CPU) @ 989.98/s +(n=5930) Rate complex val simple complex 700/s -- -29% -46% val 990/s 41% -- -24% simple 1297/s 85% 31% --

    Well to be honest I was expecting the complex version of Config::IniFiles to be faster in comparison to Config::Simple due to simplicity of the code. But the results have proved my assumption wrong. Thanks to Anonymous Monk that he elaborate regarding the tie and OOP process I decided to add also the val process to make it more fair. Also davido point out that the unlock process is a trap and possibly the data can still remain within the process, so it is better to close the file in order to flush the output.

    Again thank you all for your contribution, to beginners like my self this is a big boost on the learning curve.

    Well I do not know if this comparison makes any sense to anyone. But since I am beginner and all of this stuff make a huge impression, I felt it would be nice to mention this. Just in case that someone needs to use one of these two solutions to get also an idea about speed.

For magnificent glory, a TT Replacement.
6 direct replies — Read more / Contribute
by EvanCarroll
on May 20, 2014 at 14:23
    TT is pretty old and dated, so I've endeavored to implement Jade in Perl. Jade is a modern markup that is quickly becoming somewhat of a standard for Node.js. Here is what Jade looks like, (and all of this currently works in my port).
    doctype html
    html(lang="en")
      head
        title= pageTitle
        script(type='text/javascript').
          if (foo) {
             bar(1 + 5)
          }
      body
        h1 Jade - node template engine
        #container.col
          if youAreUsingJade
            p You are amazing
          else
            p Get on it!
          p.
            Jade is a terse and simple
            templating language with a
            strong focus on performance
            and powerful features.
    
    You can read more about it on jade-lang.com/ There are a lot of key features to it. The big thing is, of course, not having to manage closing tags with whitespace sensitivity. This may be very un-Perlesque. But all good Perl users should join the rest of the rest of world in passionately hating sgml/xml. I've got very few tests on it currently, and most importantly it does not set out to recreate a DOM. It's a basic Jade recursive decent parser that supports interpolated (Blocks) and compiled (includes). The only things not yet implemented are in the POD. I plan on getting to them in the future.


    Evan Carroll
    The most respected person in the whole perl community.
    www.evancarroll.com
The 10**21 Problem (Part 4)
6 direct replies — Read more / Contribute
by eyepopslikeamosquito
on May 19, 2014 at 07:48

    In part three of this seemingly never-ending series on high performance computing we continued what may become the longest whittle in Perl Monks history by further reducing the running time of our magic formula search program, from 728 years down to just 286.

    The latest round of improvements were achieved not by a major breakthrough, rather by applying a succession of micro-optimizations. To achieve the required massive speed boost, it was becoming increasingly clear that we needed to find a new breakthrough idea.

    Constraint Satisfaction Problems

    Constraint satisfaction problems (CSPs) are mathematical problems defined as a set of objects whose state must satisfy a number of constraints or limitations. CSPs are the subject of intense research in both artificial intelligence and operations research, since the regularity in their formulation provides a common basis to analyze and solve problems of many unrelated families. CSPs often exhibit high complexity, requiring a combination of heuristics and combinatorial search methods to be solved in a reasonable time.

    -- Constraint satisfaction problem (wikipedia)

    So, while the talk of this being a “10**21 problem” is an interesting one, and the latest installment (#3) about whacking the TLB of the processor is even more so, it seems like an incredible amount of work to unleash on a problem that has a trivial algorithmic solution ... This is on the one hand very interesting and computer-sciency, as I have already said, but the choice of example-problem puzzles me.

    -- sundialsvc4

    Roman numerals were the challenge at hand. The method of the example is common to constraint searches beyond the example. Constraint searches exist in drug research and many other fields ... Pick any field which has a large search space for just the right combination of properties in an as yet undiscovered item. Write a program which tries and makes a preliminary fitness determination for each possibility. Have that program spit out a short list of candidates for further investment of testing and development ... In this specific case, the fitness is a maximum length, a handful of inputs, and a handful of outputs that map correctly to those inputs ... The point of an example is that it is a concrete thing that is completed and shown rather than an abstract idea.

    -- mr_mischief beautifully explains the point to sundialsvc4

    mr_mischief was right on the money, sundialsvc4 on the wrong track.

    This was indeed a classic constraint satisfaction problem ... which I felt woefully ill-equipped to solve. Lacking the mathematical ability of an ambrus, the only strategy I could think of was to desperately search for a hack, any hack, that would allow me to abandon a potential solution as early as possible, as soon I was certain it could not be successfully completed.

    In computer science and mathematical optimization, a metaheuristic is a higher-level procedure or heuristic designed to find, generate, or select a lower-level procedure or heuristic (partial search algorithm) that may provide a sufficiently good solution to an optimization problem, especially with incomplete or imperfect information or limited computation capacity.

    -- Metaheuristic (wikipedia)

    Ahem. Instead of "hack" above, please feel free to substitute "metaheuristic" -- a new word I learnt while researching this series.

    An "early abandonment hack", erm metaheuristic, would clearly be much faster than a brute force complete enumeration of all candidate solutions. How to find such a hack?

    Know Your Data

    To get a feel for what the data in the 4GB lookup tables actually looked like, I wrote some small Perl programs similar to the one below, which displays the data in 128-byte blocks:

    use strict; use warnings; use List::MoreUtils qw(natatime); # See [id://861938] sub chunk_array { my ( $n, @vals ) = @_; my $str; my $iter = natatime( $n, @vals ); while ( my @line = $iter->() ) { $str .= join( " ", @line ) . "\n"; } return $str; } sub dump_blocks { my $file = shift; # bytemap file to read my $nblock = shift; # number of blocks to dump local $/ = \128; # Make <> operator read 128 bytes open( my $fh, '<', $file ) or die "error: open '$file': $!"; binmode($fh); for my $n ( 1 .. $nblock ) { my $block = <$fh>; length($block) == 128 or die "oops"; print "block $n:\n"; print chunk_array( 16, map { sprintf "%3d", ord } split //, $b +lock ); } close($fh); } # A 4GB bytemap consists of four 1GB physical files (suffix: "-0" .. " +-3"). # (See [id://1086481] for a program that generates a bytemap). my $bytemap_root = "lookzpM.byte"; my $fname = $bytemap_root . "-0"; dump_blocks( $fname, 16 );
    which produced:
    block 1: 0 118 0 126 0 126 0 102 0 102 0 94 0 94 0 86 0 86 0 94 0 94 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 block 2: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 75 55 51 55 59 63 35 47 43 39 35 39 27 31 19 15 11 23 19 23 27 31 block 3: 0 111 0 103 0 103 0 127 0 79 0 119 0 119 0 127 0 111 0 103 0 103 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 block 4: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 114 0 122 0 114 0 106 0 98 0 90 0 66 0 74 0 82 0 90 0 82 44 42 40 34 36 58 56 2 12 0 8 50 52 58 56 50 44 42 40 34 36 block 5: 0 88 0 76 0 72 0 84 0 88 0 108 0 104 0 100 0 120 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 block 6: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 109 0 97 0 101 0 65 0 77 0 113 0 117 0 113 0 109 0 97 0 101 5 1 1 0 0 17 17 21 21 17 17 45 45 33 33 37 0 65 0 77 0 block 7: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 block 8: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 68 0 72 0 76 0 88 0 84 0 104 0 108 0 24 26 4 2 8 0 12 0 120 0 116 0 104 0 108 0 120 0 68 0 72 0 76 0 88 0 84 0 block 9: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 block 10: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 83 0 91 0 67 0 75 0 67 63 59 55 51 55 43 47 51 63 59 7 3 7 11 15 3 31 27 23 19 23 0 111 0 95 0 71 0 71 0 79 0 127 0 119 0 119 0 111 0 127 0 block 11: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 block 12: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 124 0 112 0 116 0 112 0 124 0 64 0 68 0 64 0 92 0 80 0 84 22 16 30 28 30 0 6 4 6 0 62 60 62 48 54 52 54 48 62 60 62 0 70 0 70 0 94 0 94 0 86 0 0 0 0 0 0 0 0 0 0 0 block 13: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 block 14: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 85 0 89 0 93 0 73 0 69 0 121 0 125 0 105 0 117 0 121 0 125 1 9 5 5 1 25 29 29 17 105 0 85 0 89 0 93 0 73 0 69 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 block 15: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 block 16: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 78 0 70 0 70 0 94 44 46 40 22 20 22 24 30 12 14 8 6 4 6 0 126 0 110 0 118 0 118 0 126 0 78 0 70 0 70 0 94 0 110 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    Hmmm, every one of these blocks looks like it is one of just three distinct types:
    • All zeros
    • All non-zero numbers even
    • All non-zero numbers odd
    Every one of those blocks is one of just three distinct types! Every one of those blocks is one of just three distinct types?!! Whoa. But does that hold true everywhere? To find out, I nervously ran a brute force search over all seven 4GB lookup tables and was elated to learn that this "theorem" does indeed hold true for every single block of every single lookup table!

    Only odd modulos (i.e. 1001, 1003, 1005, ...) can produce a valid solution

    -- ambrus' third theorem

    For modulo 1001, each and every 128-byte block in all seven 4GB lookup tables contains either all zeros, all non-zero numbers even, or all non-zero numbers odd

    -- ambrus' fourth theorem

    Once again I could not restrain myself from adding to our list of the theorems of ambrus. :-) I expect ambrus' third theorem is easy to prove, his fourth much harder.

    Curiously, out of all odd modulos in the range 1001..1221, the fourth theorem of ambrus applies to modulos 1001 and 1221 only. Why only those two? Who decides? Weird. Maybe ambrus can show mathematically why it must be so. I "proved" it only via brute force enumeration of hundreds of 4GB lookup tables.

    For modulo 1003..1219 you would need to find a different heuristic to trim the search space (if one exists). That is the main reason why I used modulo 1001 only.

    As you might have guessed, noticing this oddity in the lookup table data was a key breakthrough. Why?

    • All zero blocks can be skipped immediately. 125 searches eliminated.
    • To get a hit, all blocks must be even or all blocks must be odd (a value from an odd block can never match one from an even block).
    • We can encode each 128 byte block in just two bits: one to indicate zero or non-zero, the other to indicate odd or even. This reduces the lookup table size from 4GB down to just 8MB! This is crucial in reducing CPU cache misses.

    Wait, there's more. Each of MDCLXVI can produce a valid solution only if all their lookup table blocks are of the same (non-zero) type. Assuming an equal number of blocks of each type, that occurs with a probability of (2/3) (first block non-zero) times (1/3)**6 (next six blocks match first non-zero block). After a preliminary check of all seven bitmaps therefore, only one in 1093.5 candidate solutions needs further (more expensive) checking for an exact match -- via a 4GB table lookup plus calculation, as detailed in earlier episodes of this series.

    Bitmaps

    Here is the code (64-bit compile, 32-bit int, 64-bit size_t) to create a 8MB bitmap from a 4GB lookup table:

    #define LAST_CHUNK_IDX_4MB 33554431 #define LAST_CHUNK_IDX_8MB (33554432*2 - 1) #define BIT_MAP_SIZE_BYTES ((LAST_CHUNK_IDX_8MB+1) >> 3) typedef unsigned char bytev_t; void make_bitmapA( const char* bitfname, // in: bit map file name const bytev_t* bytevec, // in: byte vector unsigned char* bitvec // out: bitvec put here (assumed already z +eroed) ) { unsigned int uu; unsigned int uu2; unsigned int byte; unsigned int bit; const size_t* psz; const bytev_t* psy; int j; unsigned int neven; unsigned int nodd; unsigned int totzero = 0; unsigned int toteven = 0; unsigned int totodd = 0; for (uu = 0; uu <= LAST_CHUNK_IDX_4MB; ++uu) { psy = &bytevec[uu << 7]; psz = (size_t*)psy; // This is the zero case. if (psz[0] == 0 && psz[1] == 0 && psz[2] == 0 && psz[3] == 0 && psz[4] == 0 && psz[5] == 0 && psz[6] == 0 && psz[7] == 0 && psz[8] == 0 && psz[9] == 0 && psz[10] == 0 && psz[11] == 0 && psz[12] == 0 && psz[13] == 0 && psz[14] == 0 && psz[15] == 0) { // zero: both bits are zero, nothing to do ++totzero; continue; } // All non-zero elements in block will be all even or all odd! neven = 0; nodd = 0; for (j = 0; j < 128; ++j) { if (psy[j] != 0) { if (psy[j] % 2 == 0) { ++neven; } else { ++nodd; } } } if (neven > 0 && nodd > 0) { fprintf(stderr, "oops 1\n"); exit +(1); } if (neven == 0 && nodd == 0) { fprintf(stderr, "oops 2\n"); exit +(1); } uu2 = uu * 2; // nonzero: set first bit byte = uu2 >> 3; bit = uu2 & 7; bitvec[byte] |= (1 << (bit+1)); if (neven > 0) { // even: second bit is zero, nothing to do ++toteven; continue; } // odd: set second bit ++totodd; bitvec[byte] |= (1 << bit); } printf("zero=%u even=%u odd=%u from %u (%u)\n", totzero, toteven, t +otodd, LAST_CHUNK_IDX_4MB+1, uu); FILE* fh; printf("write %s\n", bitfname); fh = fopen(bitfname, "wb"); if (fh == NULL) { fprintf(stderr, "oops open '%s' failed: errno=%d\n", bitfname, e +rrno); exit(1); } if (fwrite(bitvec, BIT_MAP_SIZE_BYTES, 1, fh) != 1) { fprintf(stderr, "oops write '%s' failed: errno=%d\n", bitfname, +errno); exit(1); } fclose(fh); }


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!
  • 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
  • Outside of code tags, you may need to use entities for some characters:
            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?
    Username:
    Password:

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

    How do I use this? | Other CB clients
    Other Users?
    Others imbibing at the Monastery: (3)
    As of 2014-07-12 23:57 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?

      When choosing user names for websites, I prefer to use:








      Results (242 votes), past polls