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

Cool Uses for Perl

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

This section is the place to post your general code offerings -- everything from one-liners to full-blown frameworks and apps.

Moon phase on historical events
1 direct reply — Read more / Contribute
by bliako
on Oct 07, 2021 at 07:55

    While I was watching the moon at a place away from civilisation I wondered what phase was the moon on certain historical events. I am not into astrology. I was curious to see how military planners make use of the moon and its effect on illumination and the tides. Invasions primarily...

    Thankfully Perl and the wonderful playground of CPAN provide all the tools one needs for an application which calculates the moon phase given date and, optionally, time and timezone or location. Thank you Astro::MoonPhase and DateTime and Geo::Location::TimeZone. All is needed is the date. Time defaults to the beginning of the day (00:00:01) and the timezone defaults to UTC. If the event's time is critical then supply it along with a timezone to make the conversion to unix-epoch-seconds (assumes UTC) accurate. In starting this I was not aware that Moon phase for a specific time is more-or-less the same for anywhere on the surface of our planet, irrespective of standpoint. With the caveat that our antipodean fellows will see it, well ... , antipodeanly.

    It looks that some military invasions took advantage of the full moon (invasion of Libya/2011, invasion of Iraq/2003 which, btw, both happened on the same day 8 years apart) while others planned for a "dark" moon (Invasion of Bay of Pigs, Cuba/1961). Normandy Landing/1944 (D-Day) planners chose a full moon (in the output: illuminated fraction: 99.4 % of full disc and also Moon age: 14.0637595011504 days which is just about half the moon cycle, i.e. full-moon) because the way it affected the tide, although the illumination would have been unwanted.

    The basic module used is Astro::MoonPhase and seems to work fine as I confirmed its output with an online calculator. Although its input is unix-epoch-seconds, it seems to handle well cases older than 1970, with a negative epoch.

    A moon phase calculator has also been posted here some time in 2007, phoon - show the phase of the moon by jima, based on previous program by Jef Poskanzer.

    Some results:

    Normandy Landing on 1944-06-06T05:00:00 (-806965200 seconds unix-epoch +) timezone: Europe/Paris (lat: 49.18, lon: -0.37) Moon age: 14.0637595011504 days Moon phase: 47.6 % of cycle (birth-to-death) Moon's illuminated fraction: 99.4 % of full disc important moon phases around the event: New Moon = Mon May 22 08:14:24 1944 First quarter = Tue May 30 02:06:14 1944 Full moon = Tue Jun 6 20:59:37 1944 Last quarter = Tue Jun 13 17:57:49 1944 New Moon = Tue Jun 20 19:01:26 1944 end event. US Invasion of Cuba, Bay of Pigs on 1961-04-15T05:00:00 (-274975200 se +conds unix-epoch) timezone: America/Havana Moon age: 0.207041969010797 days Moon phase: 0.7 % of cycle (birth-to-death) Moon's illuminated fraction: 0.0 % of full disc end event. Invasion of Libya on 2011-03-19T05:00:00 (1300503600 seconds unix-epoc +h) timezone: Africa/Tripoli Moon age: 14.0213525003449 days Moon phase: 47.5 % of cycle (birth-to-death) Moon's illuminated fraction: 99.4 % of full disc end event. Invasion of Iraq on 2003-03-19T05:00:00 (1048039200 seconds unix-epoch +) timezone: Asia/Baghdad Moon age: 15.4878029842796 days Moon phase: 52.4 % of cycle (birth-to-death) Moon's illuminated fraction: 99.4 % of full disc end event.

    Edit: caveat: the most reliable way to get the timezone right is to set it manually using a string that DateTime::TimeZone understands. Getting timezone from coordinates via Geo::Location::TimeZone is less reliable (case in point is Cuba's Bay of Pigs which gets the timezone of Pacific/Norfolk, I have edited the results to correct this.). Another edit: made example output terse and added readmore tags around the code. And added some more thanks to the existing modules my lame app relies on because they deserve it.

    The driver script follows. The input is provided in-script by an event hash which specifies a name and date, optional are time, timezone, location coordinates. Enjoy:

    bw, bliako

KenKen puzzle helper
No replies — Read more | Post response
by toolic
on Sep 16, 2021 at 17:51
    The most common mistake I make when solving KenKen puzzles is that I fail to enumerate all the correct combinations that could fill a cage. It can be tedious (and hence error-prone) to think up all the combinations for larger addition and multiplication cages.

    This is not intended to be part of a complete puzzle solver. I just want to use it to "check my math" after I realize I made a mistake while working on a puzzle.

    Since I don't have tests for the code, there could be bugs. One limitation is that it does not account for the shape of a cage. Depending on the shape, some cages forbid the same number appearing more than once, while others allow one or more numbers to appear multiple times. There is an option to control the number of duplicates to some degree.

    Here is an example output for a 9x9 grid with a cage size of 5, and the numbers adding up to 29:

    kenken -c 5 -n 29 -r 2 Grid size: 9 Cage size: 5 Operator : a Number : 29 Reject : 2 29+ = 1 + 4 + 7 + 8 + 9 29+ = 1 + 5 + 6 + 8 + 9 29+ = 2 + 3 + 7 + 8 + 9 29+ = 2 + 4 + 6 + 8 + 9 29+ = 2 + 5 + 6 + 7 + 9 29+ = 3 + 4 + 5 + 8 + 9 29+ = 3 + 4 + 6 + 7 + 9 29+ = 3 + 5 + 6 + 7 + 8 Combinations = 8

    For this run, I rejected all duplicates. If I rerun allowing numbers to appear twice, the number of combinations jumps up to 48.

    I was surprised at how little of my own code I had to write because it leverages so heavily on CPAN and Core modules.

Generate graphviz visualisation of interrelationships between variables using Graph and GraphViz2
No replies — Read more | Post response
by etj
on Aug 28, 2021 at 22:27
    This also currently lives on GitHub at It helps me see at a glance what PP parameters get data from each other, but the principle should be widely applicable:
    use strict; use warnings; use PDL::PP; use Graph; use GraphViz2; my $g = Graph->new; # should really be hypergraph but GraphViz2 not do + yet for my $r (@{$PDL::PP::deftbl}) { for my $t (@{$r->{targets}}) { $g->add_edge($t, $_) for map s/_//gr, @{$r->{conditions}||[]}; } } my ($fmt) = $ARGV[0] =~ /\.([^.]+)$/; $g->set_graph_attribute(graphviz=>{graph=>{rankdir=>'LR'}}); GraphViz2->from_graph($g)->run(format=>$fmt,output_file=>$ARGV[0]); =head1 NAME doc-pp - Generate graph of pp_def key dependencies with graphviz =head1 SYNOPSIS doc-pp deps.svg =head1 DESCRIPTION Uses L<Graph> and L<GraphViz2> to visualise the dependencies between keys in L<PDL::PP/pp_def>.
One-liner to show C struct sizes using Inline
No replies — Read more | Post response
by etj
on Aug 28, 2021 at 22:15
    This uses the superb Inline, and specifically the use Inline with =>... feature, to show the size of C data structures. The sample shown is from PDL.

    perl -Mblib -MInline=with,PDL -MInline=C,'size_t f() { return sizeof(struct pdl); }' -E 'say f()'

A BASIC interpreter to run StarTrek
5 direct replies — Read more / Contribute
by GrandFather
on Aug 11, 2021 at 08:03

    Many years ago I spent a chunk of time playing StarTrek written in BASIC on a PDP11. I stumbled on BASIC source for the game recently and thought it might be cool to write a BASIC interpreter in Perl to run it. This is the result (click the Readmore to see the code).

    There are bound to be bugs in the code still, but I've spent a little time playing the game and it seems to substantially work (i.e. I haven't seen any breakage).

    The BASIC script for the StarTrek program is given in a reply to this node.

    Update: Changed chomp to s/\r?\n// per roboticus's suggestion. Thank's too to cavac for also picking up on the issue.
    Commented out srand 1 used to get a consistent game world for debugging.
    Update to make parser case agnostic for key words and identifiers.
    Fix parameter parsing bug,

    Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond
Inline::CUDA : looking for feedback
2 direct replies — Read more / Contribute
by bliako
on Jul 28, 2021 at 05:52

    Hi all,

    I have placed a preliminary version of Inline::CUDA at, it has only been installed on my machine (Linux, GeForce 650). I would be grateful for comments from anybody who would try to install it in their machines: OSX, Windows, other Linux versions with different NVIDIA GPU versions.

    It's a lot of work to download the huge NVIDIA CUDA SDK and it is very likely that you will also need to install a specific compiler version (additional to your system compiler). So, be prepared to spend a few hours on it! I apologise!

    Hopefully, with your insight and feedback I will be able to create a better installation workflow. I have Alien::Build in mind.

    Comments and feedback on the actual code and style are very welcome as well.

    Many Thanks

    bw, bliako

    Edit: I have got a bit more into git and I think I have managed to master a git-commit-push workflow. I hope from now on it will not copy all files back to the repository but only those with changes.

Linux/Perl Cabrillo to ADIF Conversion Script
1 direct reply — Read more / Contribute
by jmlynesjr
on Jul 21, 2021 at 16:15

    Script to convert an Amateur Radio Cabrillo format log file into to an ADIF(Amateur Data Interchange Format) logfile.

    A Cabrillo file has space delimited fields. An ADIF file has tag delimited fields and field order is not important. A Cabrillo file is used for entry into Ham radio contests like the ARRL Field Day. ADIF files are used to import contact data into logging software like This process was used to create(with a Cabrillo log of 200+ entries and then import this file into my log on I prefer to log on paper and I will use this process to enter and import contact data as I fill a log sheet.

    Posted here so it can be found by the search engines. Other utilities that I have found are for Windows only.


    There's never enough time to do it right, but always enough time to do it over...

Linux/Perl Cabrillo Logfile Creation Script
1 direct reply — Read more / Contribute
by jmlynesjr
on Jul 21, 2021 at 16:12

    Script to create a simple Amateur Radio Cabrillo Format Log File

    Not much out there for Linux users, had to roll my own. Log file created with 200+ entries then converted to ADIF format and uploaded to Posted here so it can be found by the search engines.


    There's never enough time to do it right, but always enough time to do it over...

Ajax voting and modern formatting on PerlMonks
No replies — Read more | Post response
by Your Mother
on Jul 18, 2021 at 20:23

    (I reserve the right to make *sensible* silent updates or corrections in code and formatting for a day or two; until I remove this line. No one wants a post that has ďupdate: ÖĒ repeated 20 times and if I have to proof this for an hour right now, I wonít post it.) :P

    This code will give the site a more modern layout and appearance. You can thank tobyink for that part.

    Fair warning

    This code was just written for me. Itís not bombproof, it has no automatic tests, and including external files is a security risk if the source/host decides to exploit it or is itself hacked. I only address problems as they arise so there may be edge cases galore that I donít know. I did not clean-up or check anything and I wrote 95% of it like 2 years ago; generally speaking, I cannot remember code I wrote last week.

    I may not explain much of any of it,

    As it stands, you will have to have a webserver. I am using plackup with https support. If you have your own host or something, you can definitely use that. Without supporting https this stuff wonít work unless you unblock the sources with your browser (a PITA and not a good idea).

    This code does a skosh of dynamic handling of the Chatterbox.

    Nodelet settings

    In your Free Nodelet Settings you will need to add several lines.

    <script src="//" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo= +" crossorigin="anonymous"></script> <script src="// +n.js"></script> <script src="// +ht.min.js"></script> <script src="//"></script> <script src="//localhost:8282/pm/he.js"></script> <script src="//localhost:8282/pm/pm.2.0.js"></script> <script src="//localhost:8282/pm/pm.2.0.cb.js"></script> <link rel="stylesheet" href="//localhost:8282/pm/pm.2.0.css" type="tex +t/css" />

    The jQuery and Bootstrap are from, I think, reliable CDNs. he.js is a library for handling characters and HTML entities; hence ďhe.Ē The main formatting script, pm2.js, is from tobyinkís The next JS and CSS are mine and youíll have to serve them yourself from somewhere. Tobyís code needs Bootstrap. My code needs jQuery.


    If you donít have it installed already via node or something, just take the he.js file to serve:



    Code to try to make the Chatterbox more dynamic. It has bugs, including an initial double display, that havenít bugged me enough to fix yet. If you use/edit it, please be careful not to put a bunch of load on the server with bad timers, etc.


    The only purpose here is to do a sort of anti-spinner. When you click I've checked all of these on the Recently Active Threads page, it blanks the page so you know something happened and shows it when the ajax has loaded it in the background. I probably should have just done it in JS but I thought Iíd be doing more CSS so started a fileÖ

    body { opacity: 0 !important; transition: opacity 0.5s; }

    If you donít have a webserver already, this is how I run mine on :8282; youíll need Plack::App::Directory. Donít ask me how to do your own certs. I do it less than annually and itís always a RTFM situation.

    plackup -p 8282 -MPlack::App::Directory -e \ 'Plack::App::Directory->new({root => q{/path/to/the/files}})->to_app +' \ --enable-ssl \ --ssl-key-file /path/to/certs/localhost.key \ --ssl-cert-file /path/to/certs/localhost.cert - Filter, highlight FreeBSD Ports one-line commit log messages
No replies — Read more | Post response
by parv
on Jul 10, 2021 at 06:42

    Description: Purpose is to remove inane (one-line) commit log messages of FreeBSD Ports Git repository, and highlights some others. It is not currently suitable to filter long form of commit messages.

Compile and possibly run cuda code on the GPU via Perl's Inline::C
1 direct reply — Read more / Contribute
by bliako
on Jul 02, 2021 at 04:48

    Here is my attempt to run Nvidia's cuda code on the GPU via Perl. The motivation is from question Perl GPGPU Modules by kcott (interesting problem, Ken!). The main tool is Inline::C which opens so many doors.

    Cuda is a programming language on top (or extending) C which deals with GPGPU. General-purpose computing on graphics processing units (GPGPU) tries to use graphics cards (GPU) and their highly parallel architecture to run tasks, like (large) matrix multiplication, which a CPU, because of its architecture, runs much slower and inefficiently. The GPU is designed for matrix multiplications and that's what it does frame after frame of what we see on our monitor without sweat. Matrix multiplication is the basis for a lot of numerical applications and can make social planning much easier.

    First the problems:

    • Nvidia provides its own compiler for cuda code: nvcc which compiles only cuda-specific code and the rest is delegated to the system compiler (e.g. gcc). So, as I understand it, both nvcc and gcc will be used to compile a cuda program which does have cuda extensions, i.e. it is not just "plain" C code.
    • Nvidia is very picky about the version of the system compiler. It usually only supports older compilers which must live in your system along with the system/current compiler. That's a bit of a kerfuffle. For example nvcc 11.4 supports up to gcc10, whereas my system compiler is at 11.1. My Linux system does not support installing other compilers via the package manager, or at least I did not find out how. Instead I resorted in building an older version from source with its own --prefix e.g. gcc84 and use that for each nvcc call using nvcc --compiler-bindir /usr/local/gcc84/bin/gcc84. Linking using nvcc requires the same treatment. See this for how to compile and install a second compiler in Linux with its own name-prefix-postfix.
    • nvcc does not take all the flags and parameters gcc takes. Instead, any flag to be passed on to the system compiler must be preceded by -Xcompiler
    • nvcc needs its input files to have the extension .cu

    Here is the general setup:

    Use Inline::C, which is a great and powerful module! thanks!, with specific compiler and linker by providing it (via use Inline C => Config => cc => '...', ld => '...') with two Perl scripts namely and These will remove some incompatible compile/link flags which Inline::C and ExtUtils::MakeMaker use for compiling plain C code. They will also prefix others with -Xcompile ... to pass them on to the system compiler. The first script will also rename one of the temporary files produced in _Inline/build/ directory so that its extension is .cu and not .c. Then compiler and linker scripts proceed in running the actual nvcc command appropriate for compiling or linking. These scripts just worked for me but will probably need tweaking for other compilers and other flags. At least a general setup is in place.

    The two scripts to be provided to Inline::C as compiler and linker are given at the end. Edit: Save them at the same location as the demo script below without changing their names.

    Here is a basic Perl script running a cuda program on the GPU:

    #!/usr/bin/perl # by bliako @ # date: 01-Jul-2021 # see # lame example for utilising GPGPU via Inline::C # TODO: extend to taking params and returning back results use strict; use warnings; use FindBin; use Inline C => Config => cc => $FindBin::Bin.'/', ld => $FindBin::Bin.'/', ; use Inline C => <<'EOC'; // from +-c/ #include <stdio.h> __global__ void saxpy(int n, float a, float *x, float *y) { int i = blockIdx.x*blockDim.x + threadIdx.x; if (i < n) y[i] = a*x[i] + y[i]; } int main() { int N = 1<<20; float *x, *y, *d_x, *d_y; x = (float*)malloc(N*sizeof(float)); y = (float*)malloc(N*sizeof(float)); cudaMalloc(&d_x, N*sizeof(float)); cudaMalloc(&d_y, N*sizeof(float)); for (int i = 0; i < N; i++) { x[i] = 1.0f; y[i] = 2.0f; } cudaMemcpy(d_x, x, N*sizeof(float), cudaMemcpyHostToDevice); cudaMemcpy(d_y, y, N*sizeof(float), cudaMemcpyHostToDevice); // Perform SAXPY on 1M elements saxpy<<<(N+255)/256, 256>>>(N, 2.0f, d_x, d_y); cudaMemcpy(y, d_y, N*sizeof(float), cudaMemcpyDeviceToHost); float maxError = 0.0f; for (int i = 0; i < N; i++) maxError = max(maxError, abs(y[i]-4.0f)); printf("Max error: %f\n", maxError); cudaFree(d_x); cudaFree(d_y); free(x); free(y); return 0; // << late edit! } EOC main;

    At the moment, I have not implemented communicating parameters to and from the inlined cuda code. Feel free to extend.

    Suggestions: Inline::C can be modified in order to avoid my ugly hacks, or a new Inline::Cuda can be built.

    These are interesting times. This is a small step in making them fun-ner and lazy-er too. A big Thank You to the author of Inline::C and Nvidia.

    Tested on Linux with (older) gcc version 8.4, Nvidia's Cuda compilation tools version 11.4.48, Nvidia graphics driver 470.42.01, Perl version 5.32.1, Inline::C version 0.81

    Edits: main demo script added a return 0; at the end of main()

    bw, bliako

Extract/Print Firefox Bookmarks HTML File
2 direct replies — Read more / Contribute
by jmlynesjr
on Jun 25, 2021 at 19:06

    Here's a script to extract and print/save the URLs exported by the Firefox Export Bookmarks to HTML function.

    I know squat about HTML, but seem to have stumbled onto a good example.

    A flakey laptop is the mother of invention.

    #! /usr/bin/perl # - Script to extract and print the URLs created by the F +irefox # Export Bookmarks to HTML feature. # # James M. Lynes Jr. - KE4MIQ # Created: June 25, 2021 # Last Modified: 06/25/2021 - Initial version # Environment: Ubuntu 16.04 LTS # # Note: The raw HTML is very messy as it seems to include long strings # of encoded images. # Working code shamelessly stolen from the perldoc HTML::Element # example. use HTML::TreeBuilder; open(my $outfile, ">", 'bookmarks.txt') or die "Can't open bookmarks.t +xt: $!"; print $outfile "Firefox Bookmark URLs\n"; print $outfile "=====================\n"; my $tree = HTML::TreeBuilder->new(); $tree->parse_file('bookmarks.html'); for (@{ $tree->extract_links('a') }) { my($link, $element, $attr, $tag) = @$_; print "$link\n"; print $outfile "$link\n"; } $tree->delete;


    There's never enough time to do it right, but always enough time to do it over...

3D printing with out slicers and safety nets
No replies — Read more | Post response
by cavac
on Jun 09, 2021 at 12:21

    As some of you might know, i'm running a simulated space agency for fun and non-profit.

    A couple of years ago i came across something called crushable aluminium honeycomb for things like one-time-use super lightweight shock absorbers. ESA also has some version of special aluminium foam for the same purpose. Those super rich engineering departments over at ESA and NASA really have all the coolest toys, though.

    I don't have the metal working tools to replicate that (or a furnace or blocks of aluminium, for that matter). But i do have a couple of 3D printers and i know Perl. That's pretty much the same thing, isn't it?

    Looking at the requirements of how a 3D printed crushable PLA structure could work, it was pretty clear from the start that using a modeling program like OpenSCAD and a slicer software wouldn't work. My plan is to print a hard structure filled with lots of very thin PLA strands that would break under load, therefore absorbing energy. The slicer would either print those strand too thick or would remove them entirely.

    The only option i could see that would generate the results i want was to generate the printer commands myself. After a lot of on-and-off tinkering, i still don't have a working crushable structure, but i decided to post my printer test code now, so you all have a chance to play around with it if you want.

    A word of warning! The code is printer specific (i'm using a modified Creality Ender 5 Pro), so you will have to adapt at least some settings. Most 3D printers are also very dumb and will try to do whatever you tell them to do - most times "no matter what the consequences are". If you tell your printer "move the head 10 meters to the left and then set the extruder temperature to the surface temperature of the sun" it will happily crash the head and then try to burn your house down. I've named my codebase "Project Arcturus", if you are a Stargate Atlantis fan, you'll know why ;-)

    This code will generate my default "test object". Let's dive into it.

    perl -e 'use Crypt::Digest::SHA256 qw[sha256_hex]; print substr(sha256_hex("the Answer To Life, The Universe And Everything"), 6, 2), "\n";'
Compiling and uploading a crontab to my Radioduino
2 direct replies — Read more / Contribute
by cavac
on May 28, 2021 at 04:15

    For background information: I'm working on my Radioduino, a souped up version of an Arduino Uno with lots of inbuild features like a real-time clock and external memory etc. It communicates via nRF24 radio with my nRF24 "modem", which in turn is accessible via Net::Clacks in my local network.

    One of the features is a scheduler, similar to a Linux/Unix crontab. This is stored in FRAM in binary form and basically injects uplink radio commands at specified times into the command sequencer.

    The structure of the crontab in the Radioduino is this:

    typedef struct { uint8_t mode; uint8_t hour; uint8_t minute; uint8_t second; uint16_t offset; uint8_t command; uint8_t datalength; uint8_t data[16]; } SCHEDULEENTRY;

    Of course, this is binary and a pain in the seating arrangement to edit by hand. So i made some perl tools to compile plain ASCII text files and upload them.

    I hope this post isn't too boring and helps inspire some ideas for your own projects.

    perl -e 'use Crypt::Digest::SHA256 qw[sha256_hex]; print substr(sha256_hex("the Answer To Life, The Universe And Everything"), 6, 2), "\n";'
Stylish Tk clock -- oneliner
2 direct replies — Read more / Contribute
by Discipulus
on May 12, 2021 at 08:28
    ..I'm sorry.. I couldn't resist :)

    perl -MTk -e "$w=tkinit;$w->optionAdd('*font','Courier 20 bold');$w->L +abel(-textvariable=>\$n,-background=>'lavender')->pack;$w->repeat(100 +,sub{$n=scalar localtime time});MainLoop"


    PS minimalistic version

    perl -MTk -e "$w=tkinit;$w->geometry('400x1');$w->repeat(100,sub{$w->configure(-title=>scalar localtime time)});MainLoop"

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.

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

  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or or How to display code and escape characters are good places to start.
Log In?

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

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (6)
As of 2021-10-15 23:14 GMT
Find Nodes?
    Voting Booth?
    My first memorable Perl project was:

    Results (69 votes). Check out past polls.