Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic


( #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
SSH to Java based SSH server
No replies — Read more | Post response
by Beatnik
on Sep 16, 2015 at 16:22
    First post in over 10 years. Ugh!
    Recently, I had to work with a Java based SSH server (based on SSHTools, sometimes forked as J2SSH). I tried different options (ignoring the fact that some SSH modules are an absolute pain to install). There were different reasons why one or the other solution didn't work. Public key authentication was not support (don't ask), Expect was at the top of my list either. In the end, I made it work with Net::OpenSSH and the pty mapping to Net::Telnet. From POD:
    my ($pty, $pid) = $ssh->open2pty({stderr_to_stdout => 1}) or die "unable to start remote shell: " . $ssh->error; my $telnet = Net::Telnet->new(-fhopen => $pty, -prompt => '/.*\$ $/', -telnetmode => 0, -cmd_remove_mode => 1, -output_record_separator => "\r"); $telnet->waitfor(-match => $telnet->prompt, -errmode => "return") or die "login failed: " . $telnet->lastline; my @lines = $telnet->cmd("who"); ... $telnet->close; waitpid($pid, 0);
    The Prompt needed to be adjusted as the COTS had its own customized prompt.
    ... I'm belgian but I don't play one on TV.
Should I come back to Perl?
7 direct replies — Read more / Contribute
by jekyll
on Sep 11, 2015 at 07:16


    maybe this is not a good forum to ask this, but on reddit they were rather quiet ... :-)

    I exclusively used Perl 5 and a bit of JavaScript and PHP for my first job, then I somehow focused on PHP completely and started to make money with it. Writing scripts in other languages was never a job choice for me, I just like to learn new things. (Although I guess that knowing more languages will highly increase my job chances anyway.) The occasional Perl here and there (a fun IRC bot in my spare time, a text parser for some of my colleagues at work) was never gone but I didn't invest much time into it.

    Some day I needed a website parser for the PHP tool I had been hired to develop. As I had read about Python's urllib just a short time before, I decided to implement that script in Python, not being aware of the actual difference between Python 2 and Python 3. Another hobby, I thought. When the script was nearly complete, I learned that Python 2 is about to be phased out slooooowly and Python 3 lacks a comparable community yet. I assume Python 4 will cause even more trouble, and it's not really worth all that.

    I have a couple of other projects in my "To do when there's some more spare time left" list, including a rework of the particular Python script and some web development things. I guess some will be in Common Lisp (learning languages by implementing things in them has always worked out for me), but I also will revive my Perl knowledge. I just don't want to switch to Perl just to see it suffering from the same problem too, Perl 5 being slowly phased out and Perl 6 being not widely accepted. If Perl 5 won't have the same "future" as Python 2, I'm happy to join the old Perl club again; otherwise, I (again) don't really know what to do.

    I don't want to rewrite my code every few years just because someone decides that the language I wrote it in is deprecated for no good reason now. Does anyone of you have a deeper, reasonable clue about what will happen with Perl 5 when Perl 6 has gained enough attraction?

    Regards and all that, jkl
RFC: Emulating the monastery voting system
2 direct replies — Read more / Contribute
by biohisham
on Sep 10, 2015 at 08:27

    Out of admiration for the PM voting and ranking system described in votes; I am inspired to suggest an implementation along its lines on a website being developed with a team of my friends. So as a proof of concept I wrote this interactive code that accepts: a member's reputation, (u)pvotes & (d)ownvotes, average likes per week as well as age of the node; then decides whether the number of u's or d's would result in reputation gain or loss relative to the current reputation.

    As it is the code tests fine but I feel it could still use comments and anecdotal wisdom from the monks here, hence I posted it in Meditations.

    use strict; use warnings; use Readonly; use Getopt::Long; use Scalar::Util::Numeric qw(isint); #age and avg_xp are calculated at the start of everyday. #The avg_xp=sum(XP)/#nodes in the past 7 days. #The program takes these two values in addition to #likes and #unlikes + to dynamically compute reputation gains and losses. #Input for current reputation is prompted when it is time to update th +e reputation. my ($age, $avg_xp,$gained_rep, $lost_rep); my ($upvotes, $downvotes, $total_rep); my $current_rep; #variable to hold the current user reputation from th +e user page. my $vote; #a listener:either (u)pvote or (d)ownvote. Readonly::Scalar my $args =>4; #program accepts two args & two vals if(@ARGV != $args){die "syntax error: perl --age n -- +avg_xp n\n";} GetOptions( "age=i"=>\$age, "avg_xp=i"=>\$avg_xp, )or die "syntax error: perl --age n --avg_xp n\n" +; print "enter u for upvote or d for downvote\n"; while($vote=<>){ chomp $vote; if($vote =~/^u$/i){ $upvotes++; analyze_upvotes($age, $upvotes); }elsif($vote=~/^d$/i){ $downvotes++; analyze_downvotes($age,$downvotes); }else{ print "ERROR: enter u for upvote or d for downvote\n"; } } sub analyze_upvotes{ my $node_age=shift; my $like_counter=shift; printf "you have %d likes\n",$like_counter; if($like_counter==1){#reward the first upvote $gained_rep=1; rep_update($gained_rep,"gain", $like_counter); $gained_rep=0; } if($age>2 && $like_counter>1){ #nodes older than two weeks get 1/5 + rep increase $gained_rep+=1/5; if(isint $gained_rep){ #reputation is reported when gained +reputation sums to a whole number rep_update($gained_rep,"gain", $like_counter); $gained_rep=0; } }elsif($age<=2 && $like_counter>1){ #rep for nodes < 2 weeks o +ld is calculated with avg_xp perspective if($like_counter<=$avg_xp){ $gained_rep+=1/3; } elsif($like_counter>$avg_xp && $like_counter<=2*$avg_x +p){ $gained_rep+=1/2; } elsif($like_counter>2*$avg_xp && $like_counter<=3*$avg +_xp){ $gained_rep+=2/3; } elsif($like_counter>3*$avg_xp && $like_counter<=4*$avg +_xp){ $gained_rep+=3/4; } elsif($like_counter>4*$avg_xp){$gained_rep+=1; $gained +_rep=int $gained_rep; } if(isint $gained_rep){ if($current_rep-$gained_rep==0){ #for when cur_rep +=1 and gained_rep=1; rep_update(1,"gain", $like_counter); }else{ rep_update($gained_rep, "gain", $like_coun +ter); } $gained_rep=0; } } } sub analyze_downvotes{ my $node_age=shift; my $unlike_counter=shift; printf "you have %d unlikes\n", $unlike_counter; if($age<=2){ if($unlike_counter<= 3*$avg_xp){ $lost_rep+=1/3; } elsif($unlike_counter > 3*$avg_xp && $unlike_counter <= 4* +$avg_xp){ $lost_rep+=1/4; } elsif($unlike_counter > 4*$avg_xp){ $lost_rep+=0; } if(isint $lost_rep){ rep_update($lost_rep, "loss", $unlike_counter); $lost_rep=0; } }elsif($age>2){ $lost_rep+=0;} } sub rep_update{ my $rep_gain_loss=shift; my $status=shift; my $like_unlike_counter=shift; print "what is the current user reputation?\n"; $current_rep=<>; chomp $current_rep; if($status eq "gain"){ my $total_gain=$current_rep + $rep_gain_loss; printf "you gained %d points\nyour reputation is %d\n", $rep_g +ain_loss, $total_gain; }elsif($status eq "loss"){ my $total_loss=$current_rep-$rep_gain_loss; printf "you lost %d reputation points\nyour reputation is +%d\n", $rep_gain_loss,$total_loss; } }

    I am also thinking about changing the way loss of reputation is done by basing it on a variable (say avg_unlike_xp) similar to the avg_xp that I currently use for calculating gain/loss or reputation. If I did this I won't be that benevolent of a dictator any more though as I could risk over-penalizing members.

    Something or the other, a monk since 2009
Mojolicious and MongoDB
1 direct reply — Read more / Contribute
by rahuldhodapkar
on Sep 09, 2015 at 19:54
    Hey Monks!

    I haven't been around the perl community for a while, but have had a lot of fun getting familiar with the language again. Perl was my first language, but it seems to me that a lot of new programmers choose other languages like Python or Javascript to get themselves started.

    I set out to make a simple, but robust starter framework using Mojolicious and MongoDB so that new programmers (especially those at hackathons) would be able to use Perl for fun and diverse projects.

    I wanted to put the current project out there, and would appreciate help (or even pull requests maybe ^_^) and feedback. Hope everyone is doing well

Dup: Perl 5 Optimizing Compiler, Part 14: RPerl v1.1 Release, Codename Jupiter, Now Supporting N-Body Benchmark
1 direct reply — Read more / Contribute
by Will_the_Chill
on Sep 05, 2015 at 19:37
    Howdy Monks,

    RPerl v1.1, codename 'Jupiter', has been released to CPAN!

    Jupiter supports fully-automated compiling of the long-awaited N-body application software, which is a solar system simulator used by the Alioth Benchmark Game to rank programming languages by speed.

    RPerl and the new PhysicsPerl software suite enable the N-body app to run at the speed of C++, dropping from over 19 minutes runtime to barely 13 seconds!

    For now, see the INSTALL notes file for instructions on running N-body using RPerl & PhysicsPerl.

    Also, take a look at the pre-release user documentation, Learning RPerl!

    Please visit us on IRC for real-time tech support:

    ~ Will the Chill, &
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 aka Landing Page. 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".
    • Create a Video. As, for example, DropBox did.
    • One Night Stand (aka Concierge service aka Wizard of Oz). A fairly complete service experience is provided, minus the expensive underlying infrastructure required by a permanent solution.
    • Partnership. Instead of building expensive underlying infrastructure, partner with others who have it. Webvan, for example, might have avoided building expensive infrastructure by partnering with existing grocery stores (or by using Concierge).
    • Impersonator. A new wrapper is put on an existing product in order to impersonate a new one.
    • Piecemeal Solution. Similar to Impersonator, the product is presented by combining existing technologies, using minimal code/scripting to glue components together.
    • Walking Skeleton by Alistair Cockburn. Similar to Piecemeal Solution.
    • Audience Building. Get an audience before you build your product. For example, blog first.
    • Crowdfunding. Get the money first, before you actually build your product.
    • Single Feature. Instead of building the whole product, build just a single feature that can be used to test assumptions.
    • 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

    Extra References Added Later

    Updated Sep/Oct 2015: Added "Create a Video", "Partnership", "Audience Building", "Crowdfunding", "Single Feature", "Piecemeal Solution", and "Walking Skeleton" to "Some Pretotyping Techniques" section. Added Extra References section.

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 }

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

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

    How do I use this? | Other CB clients
    Other Users?
    Others drinking their drinks and smoking their pipes about the Monastery: (6)
    As of 2015-12-01 09:26 GMT
    Find Nodes?
      Voting Booth?

      What would be the most significant thing to happen if a rope (or wire) tied the Earth and the Moon together?

      Results (797 votes), past polls