Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer


( #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
Notepad++ Perl Function List with "Classes"
No replies — Read more | Post response
by VinsWorldcom
on Aug 24, 2015 at 12:50

    Windows Monks,

    As follow-on to my previous meditation regarding Notepad++ Integrated Perl Debugging, I've been doing other things with Notepad++ to make it more friendly when I write Perl (of which I've been doing more than usual lately).

    One thing I did was to get Python debugging working the same way as with Perl. In case you're interested, see here:

    This got me thinking as I looked in the "Function List" window at Python code: +[Class]h_main __init__ +[Class]h_base toXML convert main

    Why does the "Function List" window show Python classes, but not Perl by default? Of course by Perl class, I mean 'package <name>'. All I would see was a list of subs. Take the following example program:

    #!perl use strict; use warnings; package MyPkg; sub one { 1; } sub two { 1; } 1; package main; my $p = pre(); print $p . MyPkg->one; sub pre { return "ONE = "; }

    The Notepad++ Function List is: one two pre

    But there are clearly "classes" (read: packages) under which I'd like my subs grouped. Thankfully, Notepad++ allows customization of a file in the Notepad++ top level directory called 'functionList.xml' (documentation: A quick web search turned up a partial solution and with some more tweaking I finally got it to display: +[Class]MyPkg one two +[Class]main pre

    If there are no "packages", then the original display of just filename with the subs is what is displayed. I even tweaked it a bit to ignore stuff after __END__, so any "sub name" that appears in POD won't be mistakenly added to the Function List. I've tested it by viewing a few of my scripts, some modules and a few "custom" codes to demonstrate different use cases. So far, so good.

    The solution; save a copy of your existing 'functionList.xml' to something like 'functionList.xml.ORIG' (just in case you want to revert back), open the existing 'functionList.xml' file, find the Perl parser lines:

    <parser id="perl_function" displayName="Perl" ... ... </parser>

    and replace the whole lot with:

    <parser id="perl_function" displayName="Perl" commentExpr="(#.*?$|(__E +ND__.*\Z))"> <classRange mainExpr="(?&lt;=^package).*?(?=\npackage|\Z)"> <className> <nameExpr expr="\s\K[^;]+"/> </className> <function mainExpr="^[\s]*(?&lt;!#)[\s]*sub[\s]+[\w]+[\s]*\(?[^\)\ +(]*?\)?[\n\s]*\{"> <functionName> <funcNameExpr expr="(sub[\s]+)?\K[\w]+"/> </functionName> </function> </classRange> <function mainExpr="^[\s]*(?&lt;!#)[\s]*sub[\s]+[\w]+[\s]*\(?[^\)\(] +*?\)?[\n\s]*\{"> <functionName> <nameExpr expr="(?:sub[\s]+)?\K[\w]+"/> </functionName> </function> </parser>
MCE::OrdHash naming Push and Unshift methods supporting merging and reordering
1 direct reply — Read more / Contribute
by marioroy
on Aug 18, 2015 at 12:49

    Greetings all,

    I have been working on MCE::OrdHash, a sharable ordered hash module for use with MCE::Shared. These things will be included with MCE 1.7 when released. MCE::OrdHash is 100% compatible with Tie::IxHash. It overlays a modified tombstone deletion seen in Hash::Ordered. It supports both OO and Tie. The OO interface is faster, but provides auto-tie on-demand when hash-like dereferencing is requested. This is done via an autoload directive.

    The Push and Unshift methods in MCE::OrdHash merges for existing keys to remain compatible with Tie::IxHash. It adds two methods when reorder is desired. The method names are PushRo and UnshiftRo. Reorder means having to delete an existing key prior to inserting.

    I seek for the opinion of other monks on the naming of PushRo and UnshiftRo. Should I name these something else?

    Thank you, Mario

    If interested, I benchmarked against Hash::Ordered and Tie::IxHash. I have dropped MCE::Hash::Indexed (OI) and keeping MCE::Hash::Ordered (OT) which is now MCE::OrdHash.

OT: Sigh ... Windows 10
9 direct replies — Read more / Contribute
by roboticus
on Aug 14, 2015 at 19:27

    Annoying OT rant. You'll probably want to skip reading this altogether.

    I built myself a rather nice Gaming system a while back, and for the most part, I'm pretty happy with it. The big pain in the ass, though, was that I installed Windows 8.1 on it, rather than finding a copy of Windows 7. I've used Windows 7 for a couple years at work, and am pretty happy with it.

    However, Windows 8.1 was a nasty kick in the teeth. I'm still fighting with it, and hating it. So when the new and improved Windows 10 was announced, I thought I'd go and install it.

    Though, this time, I thought I'd learn a little about it first, so as not to install something even worse than Windows 8.1 (which sucks horribly, by the way). (Note: It's pretty much just the UI part that seems to suck. Performance is good. It's just that the UI went to hell for no good reason. When you mention it on a mailing list, you get the old "Oh, you old farts are afraid of change". Bullhocky! I'm not a *bit* afraid of change. I just hate things that suck!)

    Anyway, reading the reviews, it seems that Windows 10 might be a significant improvement over Windows 8.1. Not that I'll be finding out, though. Luckily, before I allowed my box to upgrade to Windows 10, I stumbled across something: Apparently Windows 10 is going to *force* autoupdates--no compromises.

    Sorry, Microsoft, but you've lost *far* too much trust for me to allow you to decide when to upgrade my operating system. So I'll be sticking with Windows 8.1 until someone either gives me a (legal) copy of Windows 7 (I'm not interested in pirating it, *nor* am I planning on giving Microsoft another dime to fix their mistake.)

    Sorry for the off-topic rant, but I'm in a ranting mood.

    (For those advising that I should use Linux, I'll let you know that I have more Linux boxes (5) at home than Windows boxes (2). I put this box together for gaming, but I run it most of the time because it has the good monitors on it, the big honkin' CPU and the excessive RAM. The instant that game stops being fun, this box'll be getting upgraded to Debian, and there'll only be my son's Windows box left in the place.)


    When your only tool is a hammer, all problems look like your thumb.

RFC: Improving the quality of your module
1 direct reply — Read more / Contribute
on Aug 14, 2015 at 15:24

    I have been looking for a list of tools that I can use to improve the quality of my modules, and I haven't been able to find one elsewhere, so I posted a question to Seekers and summarized the tools below. I propose adding the following to be added to the tutorials list (under Modules: How to Create, Install, and Use -> Creating and Distributing Modules).

    Improving the quality of a perl module

    There are a large number of tools available which can be used to improve the quality of a perl module. This might mean decreasing the number of bugs in it, improving it's performance, improving it's ability to interact with various other perl tools, or making it more usable to others.

    Below is a list of tools that are available which may help improve various aspects of your module. Not all will be useful in all situations, but it should still be a useful starting point.

    Change Kwalitee
    Every module should come with a description of the changes made at each version. There is a standard format that can be used. This site can be used to determine if your changes file meets the standard.
    CPAN Testers
    Once a module is released to CPAN, it is automatically tested by a set of volunteer testers on various platforms with different versions of perl. This site lists the platforms used to test the module as well as which ones succeed and which fail.
    CPANTS Kwalitee
    There are a number of best practices when creating a module. This site lists many of the most common ones and reports on which ones a module passes and which ones it fails.
    These can be used to make sure that every line in your module is covered by at least one test in the test suite.
    This is THE tool for profiling a module to see where the time is being spent in order to speed things up.
    This can be used to check perl code to see whether it uses the best practices described in Damian Conway's Perl Best Practices book.
    This can be used to fix indentation and enforce a few other coding style practices.
    A spell checker for Pod files.
    A check list of things to look at when releasing a new module.
    A list of recommended perl modules. Especially useful are Task::Kensho::ModuleDev and Task::Kensho::Testing which contain modules recommended for development and testing.
    Test::Pod, Test::Pod::Coverage
    These are used to make sure that no pod files are missing and that they cover all of the functions in a module.
    Travis CI
    This tool can be used for modules stored on GitHUB. Every time a set of changes is checked in, the module will be automatically tested using a number of different perl versions to make sure that all tests pass.
Ternary vs. Sort vs. Max
8 direct replies — Read more / Contribute
by QM
on Aug 10, 2015 at 05:23
    A line in BrowserUK's post reminded me of one of my cobwebs that I'm always chasing, namely, whether the Conditional Operator, ?:, is preferable over sort. In the end I should import a max function when possible, but I don't always do so.

    Conditional operator:

    my $n = $x > $y ? $x : $y;

    I find this awkward to read, and it also duplicates the variable names.


    my $n = (sort {$a <=> $b} $x, $y)[-1];

    But because sort needs a numeric sort function, that's a bit long winded.

    And the max function:

    use List::Util qw(max); my $n = max($x, $y);

    Which seems to be the laziest and preferred way.

    Quantum Mechanics: The dreams stuff is made of

RFC: (DRAFT Tutorial) A Gentle Introduction to Perl 6
5 direct replies — Read more / Contribute
by u65
on Aug 05, 2015 at 20:56

    I have posted a draft tutorial in my scratchpad here below (per Arunbear's suggestion) and am looking for constructive criticism. Thanks.

    UPDATE 1: Added three subheadings including an informal list of Perl 6's desirable features.

    UPDATE 2: Added link to rosettacode in the "Some Longer Comments" section below.

    UPDATE 3: After some rework (perltidy, perlcritic) in the Perl 5 code, modified the Perl 6 code accordingly, then made additional improvements to the Perl 6 code to be more Perl6ish.

    === BEGIN TUTORIAL ===


    Perl 6 is almost upon us, and it promises to cure many of the shortcomings of Perl 5. For all the official information, check out its web site at <>. I use the instructions here <> for a Linux source installation with the rakudobrew script.

    I asked for users opinions of Perl 6's "killer" features on the Perl 6 users list and following are some of the responses:

    • variables must be declared
    • strong typing available
    • built-in command line processing
    • built-in multiple dispatch
    • the where clause
    • built-in sets and bags
    • built-in pick and roll
    • built-in better arithmetic (Rat number type)
    • improved regex
    • no parens required for if statements
    • built-in facilities for the language to parse, transform and extend itself (std grammar, macros)
    • awesome error messages
    • hyphens allowed in names
    • grammars
    • easy interface with C
    • named subroutine arguments
    • better classes and namespaces
    • built-in object methods
    • see rosettacode for good examples

    Some longer comments:

    • Just make them look at Perl6 source code, e.g., on rosettacode. Someone who doesn't see how wonderful Perl6 is, is a lost soul anyway.
    • Less cumbersome to write and easier to read.
    • Grammars: Perl 6 is most attractive to me as a framework development tool. It lets you be really creative in how you let users describe their problem to your framework, whether that be webserver, parser, etc.
    • One thing that was not mentioned already is using Rat instead of standard floating point number. It prevents many silly mistakes, especially when counting money.


    This tutorial aims to show how my typical modest Perl 5 scripts translate into Perl 6. As the current Perl 6 documentation is not yet complete, my beginning Perl 6 efforts have resulted in putting together a simple model for a typical task for me. It was completed somewhat by trial and error along with much help from the Perl 6 mailing list.

    The Code

    A typical script of mine does something like the following:

    • Provides a simple usage statement when executed without any arguments.
    • Provides detailed help when the '--help' or '-h' or '?' options are provided.
    • Opens and parses some kind of data file (often in a special key-value format).
    • Takes some kind of action with the input data.
    • Writes data to STDOUT or a specific file.
    • Provides a friendly results message upon successful completion.

    The following table is a side-by-side comparison of the two example programs (both of which work for me; please report any errors you may find). There are some comments to indicate differences in Perl 5 versus Perl 6, but many are not documented explicitly. In many cases of my Perl 6 usage, as in Perl 5, TIMTOWTDI, so I'm sure both programs can be improved.

    Below the programs is the input data file used by each program. Run each program like this to compare results (assuming you have done chmod +x filename for each file):

    $ ./ -g -d >& p5.txt $ ./ -g -d .& p6.txt
    Perl 5Perl 6
    #!/usr/bin/env perl # file: # PRELIMS ======================== use v5.10; # features 'say' and 'state' use strict; use warnings; use File::Basename; # p6: no such module yet use Data::Dumper; my $default_infile = 'tutorial-data.txt'; my $prog = basename $0; my $debug = 0; my $infile = 0; my $usage = "$prog: --go | --infile=<data file name>"; $usage .= ' | --help | ? [--debug[=N]]'; # ARG/OPTION HANDLING ======================== if (!@ARGV) { say $usage . "\n"; exit; } foreach my $arg (@ARGV) { my $oarg = $arg; # save original for error handling my $val = undef; my $idx = index $arg, q{=}; if ($idx >= 0) { $val = substr $arg, $idx+1; $arg = substr $arg, 0, $idx; } if ($arg eq '-g' || $arg eq '--go') { $infile = $default_infile; } elsif ($arg eq '-i' || $arg eq '--infile') { $infile = $val; } elsif ($arg eq '-d' || $arg eq '--debug') { $debug = defined $val ? $val : 1; } elsif ($arg eq '-h' || $arg eq '--help' || $arg eq q{?}) { long_help(); } else { die "FATAL: Unknown argument '$oarg'.\n"; } } # MAIN PROGRAM ======================== die "FATAL: No such file '$infile'.\n" if (! -e $infile); my %user; my @keywords = qw(last first job); my %keywords; @keywords{@keywords} = (); parse_data_file($infile, \%user, $debug); if ($debug) { say 'DEBUG: Dumping user hash after loading:'; print Dumper(\%user); } else { say 'Normal end.'; } #### SUBROUTINES ======================== sub parse_data_file { my $fname = shift @_; my $href = shift @_; my $debug = shift @_ || 0; say "Parsing input file '$fname'..."; open my $fp, '<', $fname or die "$fname: $!"; my $uid = undef; my $linenum = 0; while (defined(my $line = <$fp>)) { ++$linenum; my $err = 0; # remove comments my $idx = index $line, q{#}; if ($idx >= 0) { $line = substr $line, 0, $idx; } # skip blank lines next if $line !~ /\S/xms; # every valid line must have a colon (':') # following a key word $idx = index $line, q{:}; if ($idx >= 0) { # ensure the key is lower case my $k = lc substr $line, 0, $idx; # trim ws on both ends $k =~ s{\A \s* | \s* \z}{}gxms; my $val = substr $line, $idx+1; # also needs trimming $val =~ s{\A \s* | \s* \z}{}gxms; # User attributes if ($k eq 'user') { $uid = $val; die 'FATAL: $uid not defined.' if !defined $uid; if ($uid =~ /\D/xms) { say 'ERROR: User ID not an integer.'; ++$err; } elsif ($uid <= 0) { say 'ERROR: User ID not an integer > 0.'; ++$err; } elsif (exists $href->{$uid}) { say 'ERROR: User ID is not unique.'; ++$err; } next; } # for the following keys, an exception will be # thrown if $uid is not defined if (!defined $uid) { say 'ERROR: User ID is not defined for this user.'; ++$err; } elsif ($k eq 'hobbies') { $href->{$uid}{hobbies} = []; my @h = split q{,}, $val; foreach my $h (@h) { # trim ws on both ends $h =~ s{\A \s* | \s* \z}{}gxms; push @{$href->{$uid}{hobbies}}, $h; } } elsif (exists $keywords{$k}) { $href->{$uid}{$k} = $val; } else { chomp $line; say 'ERROR: Unknown line format:'; say " '$line'"; ++$err; } } else { say 'ERROR: Unknown line format.'; ++$err; } if ($debug) { chomp $line; say STDERR "DEBUG: line = '$line'"; } if ($err) { chomp $line; say "FATAL error in file '$fname' at line $linenum:"; say " '$line'"; exit; } } } # parse_data_file sub long_help { say <<"HERE"; Usage (one of the following three): $prog --go (or '-g') $prog --infile=<data file name> (or '-i=') $prog --help (or '-h' or '?') The '--go' option uses the default input file: $default_infile Any of the first two options can use the '-d' (or '--debug') flag for debugging. A debug number may be provided with '-d=N' (or '--debug=N'). HERE exit; } # long_help # EOF ========================
    #!/usr/bin/env perl6 # file: # PRELIMS ======================== use v6.0; # not required, but good practice for # maintenance # 'strict' and 'warnings' are the default # Note: Using perl6 -v => # '2015.07.1-66-g0dcbba7 built on MoarVM version 2015.07-8-gb8fdeae' use Data::Dump; my $default_infile = 'tutorial-data.txt'; my $prog = basename($*PROGRAM); my $debug = 0; my $infile = 0; my $usage = "$prog: --go | --infile=<data file name>"; $usage ~= ' | --help | ? [--debug[=N]]'; # '~=' instead of '.=' # ARG/OPTION HANDLING ======================== # See [] # for built-in methods similar to Getopts::Long if !@*ARGS.elems { say $usage ~ "\n"; # '~' instead of '.' exit; } for @*ARGS -> $arg is copy { # 'is copy' allows modifying locally my $oarg = $arg; # save original for error handling my $val = Any; # 'Any' instead of 'undef' my $idx = index $arg, '='; if $idx.defined { # index is defined if an index is found $val = substr $arg, $idx+1; # use substr function $arg = substr $arg, 0, $idx; } if ($arg eq '-g' || $arg eq '--go') { $infile = $default_infile; } elsif ($arg eq '-i' || $arg eq '--infile') { $infile = $val; } elsif ($arg eq '-d' || $arg eq '--debug') { $debug = defined $val ? $val : 1; } elsif ($arg eq '-h' || $arg eq '--help' || $arg eq q{?}) { long_help(); } else { die "FATAL: Unknown argument '$oarg'.\n"; } } # MAIN PROGRAM ======================== die "FATAL: No such file '$infile'.\n" if $infile.IO !~~ :f; my %user; my @keywords = <last first job>; my %keywords; %keywords{@keywords} = (); parse_data_file($infile, %user, $debug); if $debug { say "DEBUG: Dumping user hash after loading:"; say Dump(%user); } else { say 'Normal end.'; } #### SUBROUTINES ======================== sub parse_data_file(Str $fname, # declare args #Any $href, %href, Int $debug = 0) { say "Parsing input file '$fname'..."; my $uid = Any; # p6 doesn't use 'undef' my $linenum = 0; for $fname.IO.lines -> $line is copy { ++$linenum; my $err = 0; # remove comments my $idx = index $line, '#', 0; if defined $idx { $line = $line.substr(0, $idx); } # skip blank lines next if $line !~~ /\S/; # '~~' and '!~~' for matching # every valid line must have a colon (':') # following a key word $idx = $line.index(':'); if $idx.defined { # ensure the key is lower case my $k = $line.substr(0, $idx).lc; # trim ws on both ends $k = $k.trim; # string object method my $val = $line.substr($idx+1); # use object method # also needs trimming $val = $val.trim; # User attributes if $k eq 'user' { $uid = $val; die "FATAL: \$uid not defined." if !$uid.defined; if $uid ~~ /\D/ { say "ERROR: User ID not an integer."; ++$err; } elsif $uid <= 0 { say "ERROR: User ID not an integer > 0."; ++$err; } elsif %href{$uid}:exists { # 'exists' adverb say "ERROR: User ID is not unique."; ++$err; } next; } # for the following keys, an exception will be # thrown if $uid is not defined if !$uid.defined { say "ERROR: User ID is not defined for this user."; ++$err; } elsif $k eq 'hobbies' { # literal string keys must be quoted %href{$uid}<<hobbies>> = []; my @h = split ',', $val; for @h -> $h is rw { # trim ws on both ends $h .= trim; # literal string keys must be quoted # use '@()' instead of '@{} push @(%href{$uid}<hobbies>), $h; } } elsif %keywords{$k}:exists { %href{$uid}{$k} = $val; } else { $line .= chomp; say "ERROR: Unknown line format, \$k = '$k'."; say " '$line'"; ++$err; } } else { say 'ERROR: Unknown line format (no key).'; ++$err; } if $debug { $line .= chomp; say "DEBUG: line = '$line'"; } if $err { $line .= chomp; say "FATAL error in file '$fname' at line $linenum:"; say " '$line'"; exit; } } } # parse_data_file sub long_help { # note indent is taken from position of ending token say qq:to/HERE/; Usage (one of the following three): $prog --go (or '-g') $prog --infile=<data file name> (or '-i=') $prog --help (or '-h' or '?') The '--go' option uses the default input file: $default_infile Any of the first two options can use the '-d' (or '--debug') flag for debugging. A debug number may be provided with '-d=N' (or '--debug=N'). HERE exit; } # long_help sub basename(IO::Path $fname) { # no File::Basename module in p6 yet my $idx = rindex $fname, '/'; if $idx { return $fname.substr($idx+1); # use substr method } return $fname; } # basename # EOF ========================

    Following is the input data file used in the programs above:

    # file: tutorial-data.txt # a data file of users and their attributes # note all valid lines are in format "key: value..." user: 1234 # unique ID (an integer > zero) last: Brown first: Sam job: gunsmith # hobbies may be a comma-separated list hobbies: hunting, Perl Monging user: 2316 last: Doe first: Jane job: financial analyst hobbies: Python open source, bowling
Notepad++ Integrated Perl Debugging
2 direct replies — Read more / Contribute
by VinsWorldcom
on Aug 05, 2015 at 06:28

    Windows Monks,

    Do you use Notepad++ as your preferred editor? Have you done some things with NppExec to move towards an IDE? Do you want integrated debugger support?

    I was out of luck on the last one and a myriad of Google-ing didn't help. There was a debugger plugin for Notepad++ (DBGp - but it was for PHP debugging with XDebug ... originally. I set out to get Perl working with it and lo and behold - I did it!

    UPDATE: I'm on Windows 7 x64 and using Strawberry Perl 5.18.1 MSWin32-x64-multi-thread.

    The gory details can be found here:

    Essentially, you need:

    DBGp plugin

    Get it from the SourceForge page at Get the latest (0.13 beta as of this writing) and you'll only need the DLL. Current file name is: Unzip the DLL to your Notepad++\plugins directory.

    Perl Debugger for Komodo IDE

    We only need this since there isn't a "Perl Debugger for Notepad++ IDE". It essentially supplies the interface via "" and subdirectory "DB" of various supporting modules. You get it here: and you'll want the file. NOTE: I tried newer releases, but found other issues cropped up in addition to the ones I show you how to fix below, so use this version, or the rest of this won't make much sense.

    I created a directory in my Notepad++\plugins directory called "PerlDebug"; so, ...Notepad++\plugins\PerlDebug. I unzipped only the "" file and the entire "DB" directory and its sub directories into that PerlDebug directory.

    Getting it to Work

    You need to make some edits to the Perl Debugger scripts from the Komodo IDE as well as set some environment variables. First, the edits.

    Edit DB\

    Open the Notepad++\plugins\PerlDebug\DB\ file. Line 657-659 is something like:

    $res .= sprintf(qq(<value%s><![CDATA[%s]]></value>\n), $encoding ? qq( encoding="$encoding") : "", $encVal);

    Change that to:

    $res .= sprintf(qq(<![CDATA[%s]]>\n), $encVal);

    Also, further up on line 131, you'll see:


    Change that to:


    Open the Notepad++\plugins\PerlDebug\ file. On line 1525:

    $res .= sprintf(' line="%s"',

    change to:

    $res .= sprintf(' lineno="%s"',

    And, after line 2898, which should read:

    my $bpInfo = getBreakpointInfoString($bkptID, function => $bFuncti +on);

    add the following three lines:

    if ($bpInfo) { $res .= $bpInfo; }
    Environment Variables

    You'll need some environment variables to get this to work. I wanted them to be volatile so as not to upset normal operations. This where I used NppExec. I'll assume you have it installed as it's an awesome plugin that you should have installed. If not, get if from the Plugin Manager.

    The only essential environment variables to set are:

    set PERL5LIB=C:\path\to\Notepad++\plugins\PerlDebug set PERLDB_OPTS=RemotePort=

    where "\path\to\Notepad++" is your directory path to Notepad++. I have mine at "C:\usr\bin\npp\plugins\PerlDebug". Yours may be "C:\Program Files\Notepad++\plugins\PerlDebug". Note if your path has a space (like between "Program" and "Files" in the example, you'll probably need to double-quote the entire path assigned to PERL5LIB like: set PERL5LIB="C:\Program Files\Notepad++\plugins\PerlDebug".

    I set my variables with an NppExec script:

    NPP_SAVE cd "$(CURRENT_DIRECTORY)" NPP_MENUCOMMAND Plugins\DBGp\Debugger ENV_SET PERLDB_OPTS=RemotePort= ENV_SET PERL5LIB=$(SYS.PERL5LIB);$(NPP_DIRECTORY)\plugins\PerlDebug INPUTBOX "Command Line Arguments: " cmd /c start "Perl Debug" cmd /c perl.exe -d "$(FILE_NAME)" $(INPUT)

    I saved it as "Perl - Debug" and used NppExec to add it to my "Macro" menu in Notepad++. It saves the current file, changes to the working directory, enables the DBGp plugin, sets the environment variables (only temporarily within the Notepad++ context, and careful not to step on a current value that may be in PERL5LIB), prompts for any command-line input to pass to your script to get it to run and finally starts the Perl debugging session - integrated in Notepad++!

    Some options I used to tune the DBGp plugin; from the Notepad++ "Plugins" menu, select "DBGp" and then "Config...".

    • Ensure the top checkbox "Bypass all mapping (local windows setup) is checked
    • No configuration in the "Remote Server IP", "IDE KEY" ... window
    • Under the "Misc" section, check:
      • "Break at first line when debugging starts"
      • "Refresh local context on every step"
      • "Refresh global context on every step"

    Hope it works for you - happy debugging!

Building the Right Thing (Part I): Pretotyping
8 direct replies — Read more / Contribute
by eyepopslikeamosquito
on Aug 04, 2015 at 07:56

    The biggest waste in software development seems to be building the wrong product, or the wrong features

    -- from How to build the right thing by Henrik Kniberg

    There is nothing so useless as doing efficiently that which should not be done at all

    -- Peter Drucker

    I'd originally planned yet another installment of the long-running Agile Imposition series, reporting on Lean startup and related ideas. As I began my research however, I soon realized this is a vast, complicated and perplexing topic; a topic so important it can make or break your business.

    So, to do it justice, I've decided instead to start a new series of articles on building the right thing.

    Innovators Trump Ideas

    Most new ideas fail, even if they are very well executed.

    -- from The Pretotyping Manifesto by Alberto Savoia

    At work we have a place where googlers submit their ideas; there are over 10,000 ideas. I call it the place where ideas go to die.

    -- from The Pretotyping Manifesto by Alberto Savoia

    If you have any doubt about the business value of ideas, try going to any venture capitalist and telling them: "I have a great idea that could be turned into a multi-billion $ business. I am not going to implement it, but if you give me a mere $10,000 I'll give you my idea and it's yours to do whatever you want with it." Just for fun, I created an ad peddling my services as an Ideator and posted it on Craigslist: "Ideator for hire. $10 per idea." I am still waiting for a serious reply.

    -- from Innovators beat Ideas by Alberto Savoia

    Leonard approaches them with an idea for a smartphone app that helps users solve Differential Equations and announces that nobody else is currently making an app like theirs. Because of Penny's presence, Sheldon is afraid Penny will steal Leonard's idea. He points out an "Unlikely, but very plausible scenario" that Penny befriends the gang to steal a marketable idea from them. Penny points out that she hangs out with them partly because she receives free food.

    -- from The Bus Pants Utilization Big Bang Theory, Season 4, Episode 12

    Sheldon's reaction notwithstanding, ideas themselves are of little value.

    Though innovators trump ideas, backing an innovator -- even one with a successful track record -- is hardly a safe bet. Innovation is hard. Startups are risky. Indeed, the prime motivation of both Alberto Savoia (father of pretotyping) and Eric Ries (father of Lean startup) is that they both experienced both phenomenal success and catastrophic failure in different Startups -- and so became determined to figure out why.

    Some Famous Product Failures

    Many businesses disappear because the founder-entrepreneur insists that he or she knows better than the market

    -- Peter Drucker

    The Innovator's nightmare is spending years and millions to build and perfect a product or service that people don't need or want

    -- from The Pretotyping Manifesto by Alberto Savoia

    The throwaway merchants at Bic thought; I know we've been very successfully making disposable pens, lighters and razors, why not make disposable underwear for women?

    -- from Biggest and Worst Product Failures

    Some examples of spectacular failures caused by building the wrong "it":

    Many other examples could be given.

    What is especially tragic is when huge investments are made up front, then -- when the product idea is clearly failing -- instead of calling it quits, still more cash is pumped in. Until bankruptcy ensues. How to avoid this sort of tragedy?


    IBM 30 years ago did something very clever. They thought that speech to text would be the next big thing because managers could not type. Their market research told them that if they built a speech to text translator, people would buy it. As a small experiment they got people who said "we will pay $10,000 if you build it" and brought them to IBM. They put them in a room with a microphone and a screen, so they thought they had a speech to text translator when in fact they had a super typist in a hidden room! It sounded like a good idea. However, after using it, at the end of the day my throat is sore; and I cannot dictate confidential memos in an open office. After the test, folks said "I'm sorry, I hope you didn't build too many of them, because we don't want them".

    The person who built the Palm Pilot, Jeff Hawkins, had an innovator's nightmare, lost millions. This time, instead of whipping my investors into a frenzy, this time let's test the idea with a little wood block and a tooth pick, and he went around for two weeks pretending he had built this Palm Pilot. After two weeks of this pretending, he said "You know, if this wasn't just a piece of wood I would actually use it". It had much less functionality than the Newton, yet was much more successful.

    -- from The Pretotyping Manifesto by Alberto Savoia

    Pretotyping: Validating the market appeal and actual usage of a potential new product by simulating its core experience with the smallest possible investment of time and money.

    -- from The Pretotyping Manifesto by Alberto Savoia

    The Pretotyping Manifesto:

    • innovators beat ideas
    • pretotypes beat productypes
    • data beats opinions
    • doing beats talking
    • simple beats complex
    • now beats later
    • commitment beats committees

    False Positives and False Negatives

    Remember Webvan, the originators of the idea of groceries ordered online, then delivered to your door? Conceived during the first internet boom of the late 1990's, the idea behind Webvan was an instant success in Thoughtland. Everyone gave it a thumbs-up, and why not? It sounded simple, convenient, it had that why-didn’t-I-think-of-that, forehead-smacking ring of genius.

    Who can ignore Twitter? But when you first heard of the service, what was your reaction? Some may have thought it an intriguing experiment in real-time micro-broadcasting (though what evidence there was that this was a gap for people is unclear to me). But surely few intuited that it would ultimately power the democratic revolutions of the Arab Spring. The elevator pitch for Twitter has that terrier-twisting-its-head-to-comprehend, temple-scratching ring of insanity.

    -- from Pretotyping@Work Invent Like a Startup, Invest Like a Grownup by Jeremy Clark

    With Webvan, people who had been asked a hypothetical "would you use it?" question turned out to be far less enthusiastic when faced with a concrete "will you use it?" question.

    By the way, seeking to learn from failure, Amazon has recently hired several of the original Webvan developers to launch a new Amazon Fresh grocery business.

    It seems that False Positives are usually based on the opinions of acknowledged (and over-confident) experts. We pretotype because data beats opinions.

    False Negatives, such as Twitter, are much rarer. Which leads us to Clark's second law of failure: too few crazy-sounding ideas get tried.

    To avoid both False Positive and False Negative outcomes, revealed-preference market testing of reasonable proxies for the final product have to be achievable at much lower investments of time and money.

    -- from Pretotyping@Work Invent Like a Startup, Invest Like a Grownup by Jeremy Clark

    Some Pretotyping Techniques

    • Fake Door. Advertise a new product or feature then track the response rate to see who would be interested.
    • Pinocchio. As used by Jeff Hawkins with his wooden model of the Palm Pilot.
    • Mechanical Turk. As used above by IBM to test customer reaction to speech-to-text translation "software".
    • One Night Stand. A fairly complete service experience is provided, minus the expensive underlying infrastructure required by a permanent solution.
    • Impersonator. A new wrapper is put on an existing product in order to impersonate a new one.
    • MVP. A Minimum Viable Product (MVP), a core part of Lean startup, is a working prototype put in the customer's hands. It is stripped down to the bare minimum required to perform a fair test.

    A complementary approach to pretotyping that has made a big splash recently is Lean startup, the subject of the next installment in this series.

    Perl Monks References

    External References

Time for an application portfolio
9 direct replies — Read more / Contribute
by talexb
on Jul 27, 2015 at 12:04

    I have been tinkering with a few tools lately, and now want to put up a portfolio of some web applications that I am working on. I have an account on pair Networks (they also host this site), so I set up local::lib and went ahead and tried to install Mojolicious::Lite, since that's the platform I'm working on these days.

    No dice -- Mojo::Lite requires 5.10, and pair only has 5.8.9. I checked with the other provider I use, and they have 5.8.8.

    So the two options I can see are a) install an up-to-date Perl on one of those accounts, or b) have these web applications run on my home machine (perhaps using to provide consistent name resolution -- not sure is this is still available).

    I could go find another web provider, but that's additional expense, and not really my best option right now. Feedback welcome!

    Alex / talexb / Toronto

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

RFC: , my very first script!
6 direct replies — Read more / Contribute
by Darfoune
on Jul 24, 2015 at 15:40

    Hello monks,

    This is my very first post on this site! I wrote my first program, , a few times ago, in order to save some repetitive typing and I really want your opinions, critics, suggestions etc..

    It's job is very simple, create an empty script. At first written in bash, with only bash as supported language, now written in Perl it includes Perl, Bash and I started slowly working to include C as well. It's not very portable and surely not very efficient, but I'm using it everyday, when reading thru intermediate Perl, advanced Bash scripting and learning C the hard way.

    The script first ask user for the name of the new script, then it asks for the language you're going to use. It will then print the shebang line as well as wanted modules (if you asked for a Perl script) and save it to a file withyourname.test. It then fires up emacs -nw with your newscript so you are ready to input code right away.

    #!/usr/bin/perl use strict; use warnings; use File::Basename; ############################ # # Name : newscript # Usage: Makes ready to use script templates for # Bash and Perl only at the moment. It includes # the shebang line for both. Perl templates # includes some useful pragmas and the option to # include the required modules on the command line. # ############################ # declare some required vars my ($name, $language); my @modules = (); my $fullname = $0; my $progname = basename($fullname); ## main program: print "Name of the new script : "; chomp ($name = <STDIN>); print "Language of $name script: "; chomp ($language = <STDIN>); # If laguage is Bash, make a Bash script if ($language =~ /bash/i) { $name = "$name.test"; print "\nMaking a Bash script: $name\n"; _makebash(); # If language is Perl, make a Perl script } elsif ($language =~ /perl/i) { $name = "$"; print "\nMaking a Perl script: $name\n"; print "\nAdd modules? ex: File::Basename;\n(use strict and use war +ning are turned on by default).\n"; print "[yes/no]: "; # check if user wants modules chomp (my $addmodule = <STDIN>); if ($addmodule =~ /yes/i) { print "\nThis script does NOT add a ';' for you!\nSay 'done' w +hen you done..\nModules: "; while (<STDIN>) { last if ($_ =~ /done(;)?/i); push @modules, $_; } _makeperl(); } elsif ($addmodule =~ /no/i) { _makeperl();} else { print "I assume no.\n"; _makeperl(); } # If language is C, make a C program } elsif ($language =~ /c/i) { $name = "$name.test.c"; print "\nMaking a C program: $name\n"; print "\nThis is the first version with C included, no more option +s yet.\n"; print "Only '#include <stdio.h>' added at this time.\n\n"; _makec(); } else { print "This might help you:\n"; _usage(); } # Make a bash script sub _makebash { if ($language eq 'bash') { open (NEWSCRIPT, '>', $name); print NEWSCRIPT "#!/bin/bash\n\n"; close NEWSCRIPT; chmod 0700, "$name"; exec (`emacs -nw +3 $name`); } } # Make a perl script sub _makeperl { open (NEWSCRIPT, '>', $name); print NEWSCRIPT "#!/usr/bin/perl\n\nuse warnings;\nuse strict;\n"; if (defined($modules[0])){ # if module is defined +, include them to the template for my $mods (@modules) { print NEWSCRIPT "use $mods"; } } print NEWSCRIPT "\n"; close NEWSCRIPT; print "\n"; chmod 0700, "$name"; exec (`emacs -nw +50 $name`); } # Make a C program sub _makec { open (NEWPROG, '>', $name); print NEWPROG "#include <stdio.h>\n\n"; close NEWPROG; print "\n"; chmod 0700, "$name"; exec (`emacs -nw +10 $name`); } # Sets the usage message. sub _usage { print<<EOF; Usage: $progname [no options yet] Creates ready to use script templates. The script will first ask you for the name of your program, then the language in which you want it written. If your chosen language is supported, it will make an empty script, with your name and 'test' appended to it. The script then makes an exec call to emacs -nw with your new file. (not very portable yet ..) note: If your chosen language is Perl, The script will ask you if you wish to import more modules. If you do want more input them then followed by a ';' and input 'done' when finish. bash: #/bin/bash perl: #/usr/bin/perl use warnings; use strict; use [yourmods]; C: #include <stdio.h> EOF }
IBM Cloud Challenge.
4 direct replies — Read more / Contribute
by BrowserUk
on Jul 21, 2015 at 18:07

    I just read about an IBM programming challenge to try and entice developers to IBMs Bluemix Cloud development environment.

    (Don't bother if you're outside the UK; or if you want to use Perl (it ain't supported :(); or if stupid sign-up processes that don't work annoy you; or ... )

    What struck me was that the three programming tasks are, at least notionally, so trivial. It took me less than 5 minutes to write (working, but probably not best) solutions to all three.

    (Whether they would pass their test criteria I guess we'll probably never know)

    I was also struck by this part of the description:

    that you can put together a programme that can run within a time limit or on limited resources rather than just lashing together a hideous brute-force monstrosity. And that you can actually read the questions properly in the first place (a useful start, but one that's often forgotten).

    I think it would be interesting to see how the best Perlish solutions we can come up with compare with those other languages that get entered to the competition; when and if they are actually made public.

    So have at them. (Don't forget to add <spoiler></spoiler> tags around your attempts.)

    I'd post the questions here but I'm not sure it wouldn't be a problem copyright wise?

    I'll post my solutions here in a few days.

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
    I'm with torvalds on this Agile (and TDD) debunked I told'em LLVM was the way to go. But did they listen!
Beyond Agile: Subsidiarity as a Team and Software Design Principle
3 direct replies — Read more / Contribute
by einhverfr
on Jul 20, 2015 at 21:24

    This is a collection of thoughts I have been slowly putting together based on experience, watching the development (and often bad implementation of) agile coding practices. I am sure it will be a little controversial in the sense that some people may not see agile as something to move beyond and some may see my proposals as being agile.

    What's wrong with the Waterfall?

    I think any discussion of agile programming methodologies has to start with an understanding of what problems agile was intended to solve and this has to start with the waterfall model of development, where software has a slow, deliberate life cycle, where all design decisions are supposed to be nailed down before the code is started. Basically the waterfall approach is intended to apply civil engineering practices to software and while it can work with very experienced teams in some limited areas it runs into a few specific problems.

    The first is that while civil engineering projects tend to have well understood and articulated technical requirements, software projects often don't. And while cost of failure in dollars and lives for a civil engineering disaster can be high, with software it is usually only money (this does however imply that for some things, a waterfall approach is the correct one, a principle I have rarely seen argued against by experienced agile developers).

    The second is that business software requirements often shift over time in ways that bridges, skyscrapers, etc don't. You can't start building a 30 floor skyscraper and then have the requirements change so that it must be at least 100 floors high. Yet we routinely see this sort of thing done in the software world.

    Agile programming methodologies arose to address these problems. They are bounded concerns, not applicable to many kinds of software (for example software regulating dosage of radiotherapy would be more like a civil engineering project than like a business process tool), but the concerns do apply to a large portion of the software industry.

    How Agile is Misapplied

    Many times when companies try to implement agile programming, they run into a specific set of problems. These include unstructured code and unstructured teams. This is because too many people see agile methodologies as devaluing design and responsibility. Tests are expected to be documentation, documentation is often devalued or unmaintained, and so forth.

    Many experienced agile developers I have met in fact suggest that design is king, that it needs to be done right, in place, and so forth, but agile methodologies can be taken by management as devaluing documentation in favor of tests, and devaluing design in favor of functionality.

    There are many areas of any piece of software where stability is good, where pace of development should be slow, and where requirements are well understood and really shouldn't be subject to change. These areas cut against the traditional agile concerns and I think require a way of thinking about the problems from outside either the waterfall or agile methodologies.

    Subsidiarity as a Team Design Principle

    Subsidiarity is a political principle articulated a bit over a hundred years in a Papal encyclical. The idea is fairly well steeped in history and well applicable beyond the confines of Catholicism. The basic idea is that people have a right to accomplish things and that for a larger group to do what a smaller group can therefore constitutes a sort of moral theft. Micromanagement is therefore evil if subsidiarity is good but also it means that teams should be as small as possible, but no smaller.

    In terms of team design, small teams are preferable to big teams and the key question is what a given small team can reasonably accomplish. Larger groupings of small teams can then coordinate on interfaces, etc, and sound, stable technological design can come out of this interoperation. The small team is otherwise tasked with doing everything -- design, testing, documentation. Design and testing are as integrated with software development as they are in agile, but as important as they are in the waterfall approach.

    This sort of organization is as far from the old waterfall as agile is but it shares a number of characteristics with both. Design is emphasized, as is documentation (because documentation is what coordinates the teams). Stability in areas that need it is valued, but in other areas it is not. Stable contracts develop where these are important and both together and individually, accomplishments are attained.

    Subsidiarity as a Technical Design Principle

    Subsidiarity in team design has to follow what folks can accomplish but this also is going to mean that these follow technological lines as well. Team responsibility has to be well aligned with technological responsibility. I.e. a team is responsible for components and components are responsible for functionality.

    The teams can be thought of as providing distinct pieces of software for internal clients, taking on responsibility to do it right, and to provide something maintainable down the road. Once a piece of software is good and stable, they can continue to maintain it while moving on to another piece.

    Teams that manage well defined technical and stable components can then largely end up maintaining a much larger number of such components than teams which manage pieces that must evolve with the business. Those latter teams can move faster because they have stability in important areas of their prerequisites.

    But the goal is largely autonomous small teams with encapsulated responsibilities, producing software that follows that process.

Advanced techniques with regex quantifiers
5 direct replies — Read more / Contribute
by smls
on Jul 19, 2015 at 05:29
RFC: Net::SNTP::Server v1
2 direct replies — Read more / Contribute
by thanos1983
on Jul 17, 2015 at 10:45

    Dear Monks,

    Once again I need your expertise opinion as I am about to upload my second module related with Net::SNTP::Client.

    The module serves purpose of a simple SNTP server able to reply back to client requests based RFC4330 message format.

    In order to test the code I will provide both the client and server scripts so you can easily test and observe bugs or possible improvements based on your experience.

    Update: changing value(s) from "0" to "1" -RFC4330 => "1" and -clearScreen => "1" on the client code.

    Update 2: Modifying POD based on new findings, also the function $verify_port and last adding a new error message/restriction in checking $moduleInput{-port}.

    Update 3: Modifying server module based on comments from Monk::Thomas.

    Update 4: Modifying server module based on comments from Anonymous Monk.

    Client script:

    Server script:

    Server module:

    Thank you all in advance for your time and effort reviewing my work.

    Seeking for Perl wisdom...on the process of learning...not there...yet!
Recamán's sequence and memory usage
3 direct replies — Read more / Contribute
by Athanasius
on Jul 13, 2015 at 04:41

    Esteemed Monks,

    I was looking at The On-Line Encyclopedia of Integer Sequences (OEIS) (you know, as one does), and on the Welcome page I found a list of Some Famous Sequences, of which the first is Recamán’s sequence, defined as follows:

    R(0) = 0; for n > 0, R(n) = R(n-1) - n if positive and not already in the sequence, oth +erwise R(n) = R(n-1) + n.

    What makes this sequence interesting is N. J. A. Sloane’s conjecture that every number eventually appears.

    Coding the sequence is simplicity itself; the challenge is to test Sloane’s conjecture by keeping track of the numbers that have not yet appeared in the series. My initial, naïve approach was to use a sieve, à la Eratosthenes:

    But this turned out to be far too memory-hungry: for values of MAX of the order of twenty million, RAM usage on my 3GB system approaches 100%, thrashing sets in, and the script (along with the rest of Windows) grinds to a shuddering halt.

    Surely, I thought, there must be a memory-efficient way to represent a sieve? And of course there is, and of course it was already implemented on CPAN. A little searching led to the Set::IntSpan module which stores runs of consecutive integers as spans, allowing large (even infinite) collections of integers to be represented very economically.

    Calculation of successive terms in the Recamán sequence is noticeably slower using Set::IntSpan for lookup than it is using a hash. But, as the adage says, it’s better to be late than be dead on time. (This was the slogan of an Australian safe driving ad campaign some years ago.) For the record: I also looked at Set::IntSpan::Fast and Set::IntSpan::Fast::XS. The latter failed to install on my system, and the former actually ran slower than Set::IntSpan for this use-case.

    Turns out that Set::IntSpan not only solves the memory problem, it also makes it possible to dispense with an upper bound for the sieve. How, then, to display progressive results? Well, the OEIS has a couple of additional series related to Recamán’s:

    • A064228: values of R(n) that take a record number of steps to appear: 1, 2, 4, 19, ...
    • A064227: the values of n corresponding to the values in A064228: 1, 4, 131, 99734, ...

    So I recast the script to output successive values of these two series:

    14:20 >perl 1 <-- 1 2 <-- 4 4 <-- 131 19 <-- 99734 ...

    Here is the new script:

    use strict; use warnings; use sigtrap handler => \&int_handler, 'INT', handler => \&break_handler, 'BREAK'; use Set::IntSpan; use Time::HiRes qw(gettimeofday tv_interval); $| = 1; my $t0 = [gettimeofday]; my $min0 = 1; my $n = 0; my $r0 = 0; my $missing = Set::IntSpan->new( '1-)' ); print "$min0 <-- "; while (++$n) { my $r = $r0 - $n; $r = $r0 + $n if $r < 0 || !$missing->member($r); $missing->remove($r); if ((my $min1 = $missing->min) > $min0) { print "$n\n$min1 <-- "; $min0 = $min1; } $r0 = $r; } sub int_handler { printf "\nn = %d, elapsed time: %.1fs\n", $n, tv_interval($t0); } sub break_handler { int_handler(); exit 0; }

    This script was developed under Windows 8.1, 64-bit, using Strawberry Perl:

    14:20 >perl -v This is perl 5, version 22, subversion 0 (v5.22.0) built for MSWin32-x +64-multi-thread

    The two signal handlers allow the script to be interrupted as follows:

    • Control-C causes the script to display the current value of $n and the total running time of the script so far.
    • Control-Break causes the script to display the same information and then exit.

    My takeaways from this meditation?

    First, we all know that micro-optimisation is pointless until you have first selected the best algorithm(s). But optimising an algorithm may actually consist in optimising its underlying data structures. Obvious? Yes, but still worth a reminder now and then.

    Second, CPAN is awesome! But you knew that already. :-)


    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Add your 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
  • 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 rifling through the Monastery: (6)
    As of 2015-09-04 04:30 GMT
    Find Nodes?
      Voting Booth?

      My preferred temperature scale is:

      Results (130 votes), past polls