<?xml version="1.0" encoding="windows-1252"?>
<node id="358095" title="Corion's scratchpad" created="2004-06-01 10:33:46" updated="2005-08-15 13:13:32">
<type id="182711">
scratchpad</type>
<author id="5348">
Corion</author>
<data>
<field name="doctext">
&lt;h1&gt;DateTime::Range&lt;/h1&gt;
&lt;c&gt;
package DateTime::Range;
use strict;
use DateTime;
use vars '%months';

=head1 NAME

DateTime::Range - decode strings like 2007Q3 to start and end date

=head1 SYNOPSIS

  use DateTime::Range;
  my ($span) = @ARGV;
  # 2007Q3 or 199902
  my ($first,$last) = DateTime::Range::get_days($span);
  printf "Report $part From %s to %s\n", map { $_-&gt;strftime('%Y%m%d') } $first,$last;

=cut

%months = (
    'Q1' =&gt; ['01','03'],
    'Q2' =&gt; ['04','06'],
    'Q3' =&gt; ['07','09'],
    'Q4' =&gt; ['10','12'],
    'H1' =&gt; ['01','06'],
    'H2' =&gt; ['07','12'],
    ''   =&gt; ['01','12'],
);

for (1..12) {
    my $m = sprintf "%02d", $_;
    $months{$m} = [$m,$m];
};

sub get_days {
    my ($yearmonth) = @_;
    if ($yearmonth eq '--letzter-monat') {
        $yearmonth = DateTime-&gt;now;
        $yearmonth-&gt;set_day(1);
        $yearmonth-&gt;add( days =&gt; -1 );
        $yearmonth = $yearmonth-&gt;strftime('%Y%m');
    }
    my ($year,$month,$day) = ($yearmonth =~ /^(\d{4})(\d\d|Q[1234]|H[12]|)(\d\d)?$/);
    die "Weirdo date: '$yearmonth'" unless $year and defined $month;

    my ($start_month,$end_month) = @{$months{ $month }};
    my ($first_day, $last_day);
	if ($day) {
        $first_day = $yearmonth;
        $last_day = $yearmonth;
	} else {
        $first_day = DateTime-&gt;new(year =&gt; $year, month =&gt; $start_month, day =&gt; 1)-&gt;strftime('%Y%m%d');
        $last_day = DateTime-&gt;last_day_of_month(year =&gt; $year, month =&gt; $end_month)-&gt;strftime('%Y%m%d');
	}

    ($first_day, $last_day)
};

1;
&lt;/c&gt;
&lt;h2&gt;Memory consumption with Excel files&lt;/h2&gt;
&lt;p&gt;I rewrote the code so it is somewhat more stand-alone. The results aren't great, as Perl still bloats its process up to 300MB for 50k lines out of a (multi-sheet) 350k line XLS file. Maybe that memory goes out for just storing the file structure.&lt;/p&gt;
&lt;c&gt;
package Interfaces::ExcelBinary;
use strict;
use Spreadsheet::ParseExcel;

warn "Spreadsheet::ParseExcel $Spreadsheet::ParseExcel::VERSION";
use vars qw($Headers $rowcount);

$Headers = [];
# cell_handler (Workbook, Sheet_index, Row, Col, Cell)
# Called by Spreadsheet::ParseExcel for every cell encountered.

sub cell_handler {
	my ($workbook, $sheet_index, $row, $col, $cell) = @_;
	if ($row == 0) {
        push(@{$Interfaces::ExcelBinary::Headers}, $cell-&gt;value);
        $rowcount = 0;
    }
	if ($row &gt; 0) {
        $rowcount++;
		#Data::Dump::dd($Interfaces::ExcelBinary::Headers);
		#$workbook-&gt;ParseAbort(1);
		#exit;
	}
}

# ReadData (Filename, [WorkSheetID]) returns $ar_data
# Reads data from the given file (which should be a BIFF-formatted .xls-file) and the given worksheet (by name or number (0-based)).
# If the supplied worksheetID is a number, a negative number -n will refer to the n-to-last worksheet.
sub ReadData {
	my ($self, $FileName, $WorkSheetID) = @_;
	my $ExcelParser = Spreadsheet::ParseExcel-&gt;new(
		CellHandler =&gt; \&amp;cell_handler,
		NotSetCell =&gt; 1,
	);
print("Parsing $FileName\n");
        main::mem_usage();
	my $WorkBook    = $ExcelParser-&gt;parse($FileName);
print("Done parsing\n");
        main::mem_usage();
    [];
	#exit;
};


package main;
use strict;
use File::Basename;
use Benchmark;

sub ReadXLS {
        my ($interface,$file) = @_;
	my $ar_data;
	print("Reading from xls...");
	my $benchmark = Benchmark::timeit(1, sub { $ar_data = $interface-&gt;ReadData($file); });
	print("$Interfaces::ExcelBinary::rowcount records in [" . $benchmark-&gt;real . " seconds], [" . (scalar @{$ar_data} / ($benchmark-&gt;real+1)) . " records/s]\n");
	return $ar_data;
}

sub mem_usage {
    print for grep {/^perl.exe\s+$$\b/i} `tasklist`;
};

@ARGV = map { glob $_ } @ARGV;
for my $file (@ARGV) {
    printf "%s %d bytes\n", basename($file), -s $file;
    mem_usage();
    ReadXLS(Interfaces::ExcelBinary::, $file);
};
&lt;/c&gt;
&lt;c&gt;
Spreadsheet::ParseExcel 0.58 at q:\tmp.pl line 5.
medium.xls 47344673 bytes
perl.exe                    2940 Console                 0      7.292 K
Reading from xls...Parsing medium.xls
perl.exe                    2940 Console                 0      7.300 K
Done parsing
perl.exe                    2940 Console                 0    331.140 K
54175 records in [34 seconds], [0 records/s]&lt;/c&gt;
&lt;h2&gt;
Having a blocking API and still use AnyEvent
&lt;/h2&gt;&lt;p&gt;

I'm in the process of making (my) modules play nice with [mod://AnyEvent].
Most of the time, I'm content with being &lt;i&gt;compatible&lt;/i&gt; with [mod://AnyEvent], that
means, allowing timers, socket callbacks and other AnyEvent stuff run while
some function call in my preexisting code blocks.
&lt;/p&gt;&lt;p&gt;
The basic approach that [mod://AnyEvent] follows
for asynchronous operation allows two methods. The first is to have
callbacks in your API for the various events that occur. The second is to return
&lt;c&gt;AnyEvent::condvar&lt;/c&gt; objects that represent a future value
to be filled in when the call completes on the "other side". The data
for a condvar can be fetched with 
&lt;c&gt;
my @data = $cv-&gt;recv()
&lt;/c&gt;
While your code waits for the values to be fetched, [mod://AnyEvent] will
dispatch other events and timers to callbacks.
&lt;/p&gt;&lt;p&gt;

In the concrete example of making [mod://WWW::Mechanize::Firefox] (through [mod://MozRepl])
play nice with [mod://AnyEvent], MozRepl has the following API:
&lt;/p&gt;&lt;p&gt;
&lt;c&gt;
my @result = $plugin-&gt;execute('1+1'); # sends data over to Firefox, and returns the response
&lt;/c&gt;
&lt;p&gt;I can't change &lt;i&gt;that&lt;/i&gt; API, but I want to allow timers and callbacks to
be fired while waiting for &lt;c&gt;-&gt;execute()&lt;/c&gt; to complete.&lt;/p&gt;
&lt;p&gt;To that effect, I try the following approach:&lt;/p&gt;
&lt;c&gt;
package My::Plugin::AnyEvent;

...

sub execute_async {
    my ($self,$command, $complete) = @_;
    $complete ||= AnyEvent-&gt;condvar;
    # Send the command to Firefox
    $self-&gt;handle-&gt;push_write($command);
    # Read the response as soon as it becomes available
    $self-&gt;handle-&gt;push_read(line =&gt; sub {
        $complete-&gt;send($_[0]); # send the data to whoever waits
    });
    $complete
};

sub execute {
    my ($self,$command) = @_;
    # synchronously execute the command
    $self-&gt;execute_async($command)-&gt;recv
};
&lt;/c&gt;
&lt;p&gt;This works all nice and dandy, except it does not work well if
I want to do this from a constructor:&lt;/p&gt;
&lt;c&gt;...&lt;/c&gt;
&lt;h2&gt;Archive::Zip::MemberRead::FH&lt;/h2&gt;
&lt;c&gt;
package Archive::Zip::MemberRead::FH;
use strict;
#use parent 'Tie::Handle';
use base 'Tie::Handle';
use Archive::Zip::MemberRead;

=head1 NAME

Archive::Zip::MemberRead::FH - readonly filehandle for zip members

=head1 SYNOPSIS

    require Archive::Zip;
    require Archive::Zip::MemberRead::FH;
    my $ar = Archive::Zip-&gt;new();
    my $file = 'test.zip';
    $ar-&gt;read($file) == Archive::Zip::AZ_OK()
        or die "Couldn't read '$file': $!";
    my @members = $ar-&gt;members();

    print "Reading first file from '$file'\n";
    $fh = Archive::Zip::MemberRead::FH-&gt;new($members[0]);

    while (&lt;$fh&gt;) {
        ...
    };

=head1 NOTES

This is a very crude wrapper that tries to dress up
a L&lt;Archive::Zip::MemberRead&gt; as a read-only
filehandle.

=head1 METHODS

=head2 C&lt;&lt; -&gt;new ReadMember &gt;&gt;

The C&lt;&lt; -&gt;new &gt;&gt; constructor takes the same arguments
as L&lt;Archive::Zip::ReadMember&gt;C&lt;&lt; -&gt;new &gt;&gt;, but returns
a filehandle instead of an object.

=cut

sub new {
    my $class = shift;
    local *ZIPFH;
    tie *ZIPFH, $class, @_;
    return *ZIPFH
};

=head2 C&lt;&lt; -&gt;readmember &gt;&gt;

The C&lt;&lt; -&gt;readmember &gt;&gt; function allows
access to the underlying L&lt;Archive::Zip::ReadMember&gt;.

=cut

sub readmember {
    my ($glob) = @_;
    $$glob
};

sub TIEHANDLE {
    my $class = shift;
    my $m = Archive::Zip::MemberRead-&gt;new(@_);
    return bless \$m, $class;
};

sub reflect {
    my ($name,$args) = @_;
    my $glob = shift @$args;
    my $self = $glob-&gt;readmember;
    unshift @$args, $self;
    return $self-&gt;can($name);
};

=head1 FUNCTIONALITY

The following functionality is implemented for the filehandle:

=cut

=head2 C&lt; read &gt;

Reading octets into a buffer, using the C&lt;&lt; -&gt;read &gt;&gt; method
of the underlying ReadMember object.

=cut

sub READ { goto  &amp;{ reflect('read', \@_) } };

=head2 C&lt; readline &gt;

Reading lines into a buffer, using the C&lt;&lt; -&gt;getline &gt;&gt; method
of the underlying ReadMember object.

No special provision for treating C&lt;$/&gt; properly is made,
the default behaviour of the underlying ReadMember applies.

=cut

sub READLINE { goto &amp;{ reflect('getline', \@_)} };

=head2 C&lt; close &gt;

Closes the filehandle, using the C&lt;&lt; -&gt;close &gt;&gt; method
of the underlying ReadMember object.

=cut

sub CLOSE { goto &amp;{ reflect('close', \@_)} };

=head2 C&lt; binmode &gt;

Not implemented

=cut

#sub BINMODE { goto reflect('binmode', \@_) };

=head2 C&lt; eof &gt;

Not implemented

=cut

#sub EOF { goto reflect('eof', \@_)};

1;

__END__

=head1 AUTHOR

Max Maischein L&lt;corion@cpan.org&gt;

=head1 COPYRIGHT

This file is copyright (2009) Max Maischein L&lt;corion@cpan.org&gt;

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

=cut

&lt;/c&gt;
&lt;h2&gt;Patched &lt;c&gt;expand_macro.pl&lt;/c&gt;&lt;/h2&gt;
&lt;c&gt;
#!perl -w
use strict;

use Pod::Usage;
use Getopt::Std;
use Config;
$Getopt::Std::STANDARD_HELP_VERSION = 1;

my $trysource = "try.c";
my $tryout = "try.i";

getopts('fF:ekvI:X', \my %opt) or pod2usage();

my($expr, @headers) = @ARGV ? splice @ARGV : "-";

pod2usage "-f and -F &lt;tool&gt; are exclusive\n" if $opt{f} and $opt{F};

foreach($trysource, $tryout) {
    unlink $_ if $opt{e};
    die "You already have a $_" if -e $_;
}

if ($expr eq '-') {
    warn "reading from stdin...\n";
    $expr = do { local $/; &lt;&gt; };
}

my($macro, $args) = $expr =~ /^\s*(\w+)((?:\s*\(.*\))?)\s*;?\s*$/s
    or pod2usage "$expr doesn't look like a macro-name or macro-expression to me";

if (!(@ARGV = @headers)) {
    open my $fh, '&lt;', 'MANIFEST' or die "Can't open MANIFEST: $!";
    while (&lt;$fh&gt;) {
	push @ARGV, $1 if m!^([^/]+\.h)\t!;
    }
    push @ARGV, 'config.h' if -f 'config.h';
}

my $header;
while (&lt;&gt;) {
    next unless /^#\s*define\s+$macro\b/;
    my ($def_args) = /^#\s*define\s+$macro\(([^)]*)\)/;
    if (defined $def_args &amp;&amp; !$args) {
	my @args = split ',', $def_args;
	print "# macro: $macro args: @args in $_\n" if $opt{v};
	my $argname = "A0";
	$args = '(' . join (', ', map {$argname++} 1..@args) . ')';
    }
    $header = $ARGV;
    last;
}
die "$macro not found\n" unless defined $header;

if ($^O =~ /MSWin(32|64)/) {
    # The Win32 (and Win64) build process expects to be run from
    # bleadperl/Win32
    chdir "Win32"
	or die "Couldn't chdir to win32: $!";
};

open my $out, '&gt;', $trysource or die "Can't open $trysource: $!";

my $sentinel = "$macro expands to";

my %done_header;

sub do_header {
    my $header = shift;
    return if $done_header{$header}++;
    print $out qq{#include "$header"\n};
}

print $out &lt;&lt;'EOF' if $opt{X};
/* Need to do this like this, as cflags.sh sets it for us come what may.  */
#undef PERL_CORE

EOF

do_header('EXTERN.h');
do_header('perl.h');
do_header($header);
do_header('XSUB.h') if $opt{X};

print $out &lt;&lt;"EOF";
#line 4 "$sentinel"
$macro$args
EOF

close $out or die "Can't close $trysource: $!";

print "doing: $Config{make} $tryout\n" if $opt{v};
my $cmd = "$Config{make} $tryout";
system( $cmd ) == 0
    or die "Couldn't launch [$cmd]: $! / $?";

# if user wants 'indent' formatting ..
my $out_fh;

if ($opt{f} || $opt{F}) {
    # a: indent is a well behaved filter when given 0 arguments, reading from
    #    stdin and writing to stdout
    # b: all our braces should be balanced, indented back to column 0, in the
    #    headers, hence everything before our #line directive can be ignored
    #
    # We can take advantage of this to reduce the work to indent.

    my $indent_command = $opt{f} ? 'indent' : $opt{F};

    if (defined $opt{I}) {
	$indent_command .= " $opt{I}";
    }
    open $out_fh, '|-', $indent_command or die $?;
} else {
    $out_fh = \*STDOUT;
}

{
    open my $fh, '&lt;', $tryout or die "Can't open $tryout: $!";

    while (&lt;$fh&gt;) {
	print $out_fh $_ if /$sentinel/o .. 1;
    }
};

unless ($opt{k}) {
    foreach($trysource, $tryout) {
	die "Can't unlink $_: $!" unless unlink $_;
    }
}

__END__

=head1 NAME

expand-macro.pl - expand C macros using the C preprocessor

=head1 SYNOPSIS

  expand-macro.pl [options] [ &lt; macro-name | macro-expression | - &gt; [headers] ]

  options:
    -f		use 'indent' to format output
    -F	&lt;tool&gt;	use &lt;tool&gt; to format output  (instead of -f)
    -e		erase try.[ic] instead of failing when they're present (errdetect)
    -k		keep them after generating (for handy inspection)
    -v		verbose
    -I &lt;indent-opts&gt;	passed into indent
    -X		include "XSUB.h" (and undefine PERL_CORE)

=cut
&lt;/c&gt;
&lt;h2&gt;Making &lt;c&gt;@ARGV&lt;/c&gt; work better&lt;/h2&gt;
&lt;p&gt;The idea is to [doc://tie] &lt;c&gt;*ARGV&lt;/c&gt; once and then
process &lt;c&gt;@ARGV&lt;/c&gt; one by one when needed, and calling
&lt;c&gt;&amp;ARGV&lt;/c&gt; between the files (or something like that).
&lt;c&gt;
#!perl -w

BEGIN {
    { package My::ARGV;
    use strict;
    use Data::Dumper;
    
    sub TIEHANDLE {
        my ($class,@elts) = @_;
        warn 'TIEHANDLE';
        bless {}; #[@elts]
    };
    
    sub OPEN {
        warn 'OPEN: ' . Dumper \@_;
        1
    };
    
    sub EOF {
        warn 'EOF: ' . Dumper \@_;
        @{ $_[0] }
    };

    sub CLOSE {
        warn 'CLOSE: ' . Dumper \@_;
        1
    };
    sub BINMODE {
        warn 'BINMODE: ' . Dumper \@_;
        @{ $_[0] }
    };

    sub READLINE {
        my ($self) = @_;
        while (@ARGV and (!defined $self-&gt;{curr} or !scalar @{ $self-&gt;{curr}})) {
            $self-&gt;{curr} = shift @ARGV;
        };
        if(scalar @{ $self-&gt;{curr} }) {
            return shift @{ $self-&gt;{curr} }
        } else {
            return $self-&gt;{curr} = undef
        }
    };
    }
    
    tie *ARGV, 'My::ARGV';
}

@ARGV = ([qw(1 2 3)],[qw(4 5 6)],[qw(7 8 9)]);

while (&lt;&gt;) {
    print "$_\n"
};
&lt;/c&gt;
&lt;h2&gt;[http://groups.google.de/group/perl.perl5.porters/msg/fe0b8645e81f3424|Perl Stable release test]&lt;/h2&gt;
&lt;p&gt;
I think that for a stable release the question "is it ready" is more like:
&lt;/p&gt;&lt;blockquote&gt;
    Does CPAN pass?
&lt;/blockquote&gt;&lt;p&gt;
which comes down to:
&lt;/p&gt;&lt;c&gt;
    for each module that fails its regression tests on $current
      did it fail identically on $previous?
      if yes, "SEP"
      else work out why it failed (a bisect is useful for this)

    attempt to group failure causes

    for each failure cause
      is that a regression?
      if yes, figure out how to fix it
        (more code? revert the code that broke it)
      else
        (presumably) it's relying on something un-or-under-documented
        should the existing behaviour stay?
          yes - goto "regression"
          no - note it in perldelta as a significant bugfix
          (also, try to inform the module's author)
&lt;/c&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;ol start=11&gt;
&lt;li&gt;check that &lt;c&gt;./Configure -des &amp;&amp; make all test&lt;/c&gt; works in one place
&lt;li&gt;check that &lt;c&gt;./Configure ... &amp;&amp; make all test_harness install&lt;/c&gt; works
&lt;blockquote&gt;
    that's likely something that needs fixing in the Parrot checklist -
     there's no step to check that it installs, that the installed parrot runs,
     or that the installed parrot can be used to build a third-party language
     such as Rakudo or Pynie]
&lt;/blockquote&gt;
&lt;li&gt;bootstrap the CPAN client on the clean install
&lt;li&gt;install CPANPLUS
&lt;li&gt;bootstrap the CPANPLUS client
&lt;li&gt;install an XS module
&lt;li&gt;if this is good, commit this.
    sit, and wait. 
&lt;/ol&gt;
&lt;h2&gt;&lt;tt&gt;grate.pl&lt;/tt&gt; - grep rate&lt;/h2&gt;
&lt;c&gt;
#!/usr/bin/perl -w
use strict;
use Getopt::Long;
use Time::HiRes;
use List::Util qw( sum );
use Data::Dumper;
#use IO::Select; # does not work the way I want on Windows

GetOptions(
    'debug|d'    =&gt; \my $debug,
    're:s'       =&gt; \my @buckets,
    'totals|t'   =&gt; \my $totals,
    'window|w:s' =&gt; \my @windows, # in seconds
    'update|u:i' =&gt; \my $update,
);

if (! @windows) {
    @windows = qw(1 5 60);
};

@windows = sort { $a &lt;=&gt; $b } @windows;

$update ||= 1;

@buckets = map { s/:(\w+)$// ? [ $1 =&gt; qr/$_/ ] : [$_ =&gt; qr/$_/ ] } @buckets;
if ($totals) {
    unshift @buckets, ['totals' =&gt; qr/(?!)/ ];
};

my @names = map { $_-&gt;[0] } @buckets;

my @slots;

my $last = 0;
my $last_update = 0;
while (&lt;&gt;) {
    my $now = time;
    $last ||= $now - $windows[-1];
    my $elapsed = $now - $last;
    #print "Elapsed: $elapsed ($slots[0]-&gt;{totals})\n";
    chomp;

    # Check how many buckets have passed without data
    for (0..int($now - $last)-1) {
        unshift @slots, +{ map {; $_ =&gt; 0 } @names };
    };
    # Limit slots to maximum reporting size
    splice @slots, $windows[-1]+1;

    if ($totals) {
        $slots[0]-&gt;{totals}++;
    };
    BUCKET: for my $b (@buckets) {
        my ($n,$r) = @$b;
        if (/$r/) {
            $slots[0]-&gt;{ $n }++;
            last BUCKET;
        };
    };

    $last = $now;
    if ($now - $last_update &gt;= $update) {
        local $" = "\t";
        print "\t@windows\n";
        for my $n (@names) {
            print "$n\t";
            for my $w (@windows) {
                print sprintf "%0.2f\t", sum( map { $_-&gt;{ $n } } @slots[ 1.. $w ] ) / $w;
            };
            print "\n";
        };
        $last_update = $now;
    };
};
&lt;/c&gt;
&lt;h2&gt;Parallel map&lt;/h2&gt;
&lt;c&gt;
use strict;
use threads;
use Thread::Queue;

my $threadcount = 4;

=head2 C&lt;qmap CODE ARGS&gt;

Launches C&lt;$threadcount&gt; threads that 
process the items in C&lt;ARGS&gt; in parallel.
Returns
the input queue, output queue and
an array reference to the threads.

The aliasing effect of C&lt;map&gt; on C&lt;$_&gt; is not preserved.

=cut

sub qmap(&amp;;@) {
    my $cb = shift;
    my $in = Thread::Queue-&gt;new(@_);
    my $out = Thread::Queue-&gt;new();
    my $handler = sub {
        while (defined(my $args = $in-&gt;dequeue())) {
            local $_ = $args;
            $out-&gt;enqueue($cb-&gt;());
        };
    };
    my @threads = map { threads-&gt;new($handler) } 1..$threadcount;
    $in,$out,\@threads
};

=head2 C&lt;pmap CODE ARGS&gt;

Processes a list in parallel and returns
the results in the order they were finished.

The aliasing effect of C&lt;map&gt; on C&lt;$_&gt; is not preserved.

=cut

sub pmap(&amp;;@) {
    my ($in,$out,$threads) = &amp;qmap(@_);
    $in-&gt;enqueue((undef) x scalar @$threads);
    $_-&gt;join for @$threads;
    return $out-&gt;dequeue( scalar @$out )
};

=head2 C&lt;smap CODE ARGS&gt;

Processes a list in parallel and returns
the results in the order they were input.
This is slightly more processing intensive,
as the results are sorted after having been processed.

The aliasing effect of C&lt;map&gt; on C&lt;$_&gt; is not preserved.

=cut

sub smap(&amp;;@) {
    my $user_cb = shift;
    my $cb = sub {
        my $args = $_;
        local $_ = $args-&gt;[1];
        [ $args-&gt;[0], $user_cb-&gt;() ];
    };
    my $pos = 0;
    my ($in,$out,$threads) = &amp;qmap($cb, map {[ $pos++, $_ ]} @_);
    $in-&gt;enqueue((undef) x scalar @$threads);
    $_-&gt;join for @$threads;
    return map { shift @$_; @$_ } sort { $a-&gt;[0] &lt;=&gt; $b-&gt;[0] } $out-&gt;dequeue( scalar @$out )
};

print "Got $_\n" for smap {
    sleep rand 10;
    printf "%d %d\n", threads-&gt;tid, $_;
    $_
} (1..10);
&lt;/c&gt;
&lt;h2&gt;Environment Setup for Strawberry Perl&lt;/h2&gt;
&lt;p&gt;Put this into &lt;c&gt;C:\Strawberry\Path.cmd&lt;/c&gt; and call it to add the relevant directories to &lt;c&gt;$ENV{PATH}&lt;/c&gt;. You can also move Strawberry Perl away from &lt;c&gt;C:\Strawberry&lt;/c&gt; with that.
&lt;c&gt;
@echo off
set base=%~dp0
path %BASE%\perl\bin;%BASE%\c\bin;%PATH%
set CCACHE_DIR=C:\temp\ccache
set CCACHE_LOGFILE=%CCACHE_DIR%\ccache.log
&lt;/c&gt;
&lt;h2&gt;WMI queries for Chronic::Win32&lt;/h2&gt;
&lt;c&gt;
#!perl -w
use strict;
use DBI;
use Data::Dumper;

my $dbh = DBI-&gt;connect('dbi:WMI:', undef, undef, {RaiseError =&gt; 1});

sub dump_wql {
    my $res = $dbh-&gt;selectall_arrayref($_[1], {});
    print $_[0], Dumper $res;
};

dump_wql('Ping 192.168.1.1', &lt;&lt;'');
    select responsetime
    from Win32_PingStatus
    where Address = '192.168.1.1'

dump_wql('CPU load', &lt;&lt;'');
    select Name,LoadPercentage
    from Win32_Processor

dump_wql('Network connections', &lt;&lt;'');
    select RemotePath,ConnectionState
    from Win32_NetworkConnection

&lt;/c&gt;
&lt;h2&gt;Capturing STDERR via backticks&lt;/h2&gt;
&lt;p&gt;Stolen from [dave_the_m] in [http://groups.google.de/group/perl.perl5.porters/browse_thread/thread/326aa5b020a746d1/00cec87e7e400efa#00cec87e7e400efa| a p5p post]
&lt;c&gt;
   sub GimmeStdErr(@){  # ... bangles, tangles and spaghetti!
         local *R, *W;
         pipe R,W;
         if(fork){
             close W;
             &lt;R&gt;
         }else{
             close R;
             open STDERR, "&gt;&amp;W";
             exec @_
         }
   };
&lt;/c&gt;
&lt;h2&gt;An ugly nest of map&lt;/h2&gt;
&lt;p&gt;I think the &lt;c&gt;map&lt;/c&gt; invocation in &lt;c&gt;flatten()&lt;/c&gt; needs a bit of documentation...&lt;/p&gt;
&lt;c&gt;
=head2 C&lt;&lt; flatten LISTNAME CHILDLIST $var &gt;&gt;

Removes one level of hierarchy and merges all keys from the current hierarchy
into the elements below it:

  $VAR1 = {
    user =&gt; 'corion',
    pages =&gt; [
        { title =&gt; 'This is page 1', 
          url =&gt; '/pages/1', 
          items =&gt; [
            { url =&gt; '/items/1', description =&gt; 'A brand new item' },
            { url =&gt; '/items/2', description =&gt; 'A brand new item' },
          ],
        },
        { title =&gt; 'This is page 2',
          url =&gt; '/pages/2',
          items =&gt; [
            { url =&gt; '/items/3', description =&gt; 'A brand new item' },
            { url =&gt; '/items/4', description =&gt; 'A brand new item' },
          ],
        },
        { title =&gt; 'This is page 3', url =&gt; '/pages/3', items =&gt; [] },
    ],
  }

  flatten 'pages' =&gt; 'items', $VAR1

becomes

  $VAR1 = {
      user =&gt; 'corion',
      items =&gt; [
        { title =&gt; 'This is page 1', 
          url =&gt; '/items/1',
          description =&gt; 'A brand new item'
        },
        { title =&gt; 'This is page 1', 
          url =&gt; '/items/2',
          description =&gt; 'A brand new item'
        },
        { title =&gt; 'This is page 2',
          url =&gt; '/items/3', 
          description =&gt; 'A brand new item'
        },
        { title =&gt; 'This is page 2',
          url =&gt; '/items/4',
          description =&gt; 'A brand new item' },
        },
      ],
  }

=cut

sub flatten($$$) {
    my ($key,$child,$items) = @_;
    if (! exists $items-&gt;{$key}) {
        croak "Cannot flatten '$key': The entry does not exist";
    };

    $items-&gt;{ $child } = [ 
        map {
              my $p = $_; 
              (exists $p-&gt;{ $child } &amp;&amp; ref $p-&gt;{ $child } eq 'ARRAY')
              ? (map {; +{%$p,%$_} } @{ delete $p-&gt;{ $child }} )
              : ()
            } @{ delete $items-&gt;{ $key }}
    ];
    
    $items
};

&lt;/c&gt;
&lt;h2&gt;Load trace/timing information&lt;/h2&gt;
&lt;p&gt;This is the short hack I came up with but it's substantially longer than 4 lines :)&lt;/p&gt;
&lt;c&gt;
Q:\&gt;perl -e "my%l;BEGIN{unshift@INC,sub{my($s,$m)=@_;return if $l{$m};local $l{$
m}=$m;warn localtime().qq[ $m loading\n];require $m;warn localtime().qq[ $m done
.\n];}}" -e "use strict; use warnings;use LWP::UserAgent;"
&lt;/c&gt;
&lt;c&gt;
package Devel::Timings;
# or maybe B::Timings, so you can load it with -MO=Timings...

my %loading;
BEGIN{
    unshift @INC, sub{
        my ($self,$module) = @_;
        return if $loading{$m}; # reentrancy guard
        local $loading{$module} = $module;
        warn localtime().qq[ $module loading\n];
        require $module;
        warn localtime().qq[ $module done.\n];
    }
}
&lt;/c&gt;
&lt;h2&gt;Check that &lt;tt&gt;[cpan://File::Spec]-&amp;gt;path&lt;/tt&gt; works sanely on Win32&lt;/h2&gt;
&lt;c&gt;
use Test::More tests =&gt; 4;
use Data::Dumper;
use Config;

=head1 DESCRIPTION

This test checks whether the current directory
(".") is included in the list returned from
File::Spec-&gt;path and whether a program in the
current directory can be run. The test
succeeds when both match.

=cut

use_ok 'File::Spec';
diag "\$File::Spec::VERSION is $File::Spec::VERSION";

my $tempfile = 'does_only_exist_in_current_directory.cmd';

$/ = "";

my %os = map { split /\r?\n/, $_, 2 } &lt;DATA&gt;;

my $os = $os{$^O} || $os{'fallback'};

open my $fh, "&gt;", $tempfile
    or die "Couldn't create '$tempfile': $!";
print {$fh} $os;
close $fh;

chmod 700, $tempfile;

ok -x $tempfile, "'$tempfile' is executable";

my $explicit = File::Spec-&gt;catfile( ".", $tempfile );
is system($explicit), 0, "'$tempfile' can be executed as '$explicit'";

my $dot_in_path = grep { $_ eq '.'} File::Spec-&gt;path;
my $implicit_execution = system( $tempfile ) == 0;

diag "The current directory is " . ($dot_in_path ? "" : "not ") . "in File::Spec-&gt;path.";
diag $_ for File::Spec-&gt;path;
diag "---";
diag $_ for split /$Config{path_sep}/, $ENV{PATH};
diag "Programs in the current directory can " . ($implicit_execution ? "" : "not ") . "be launched.";

is (($dot_in_path xor $implicit_execution), '', "dot is in File::Spec-&gt;path or files in the current directory don't get launched")
    or do {
    };

END {
    unlink $tempfile
        or diag "Couldn't remove '$tempfile': $!";
};

__DATA__
MSWin32
@echo off

fallback
#!/bin/sh

&lt;/c&gt;
&lt;h2&gt;Using [cpan://DBD::WMI] to get (and reconfigure) the DNS resolution order&lt;/h2&gt;
&lt;c&gt;
#!/usr/bin/perl -w
package main;
use strict;
use Data::Dumper;

use DBI;

my ($machine,$user,$pass) = @ARGV;
$machine ||= ".";

my $target_ip = '192.168.1.13';

my $dbh = DBI-&gt;connect("dbi:WMI:$machine",$user,$pass);

my $sth = $dbh-&gt;prepare(&lt;&lt;WQL);
    SELECT * FROM Win32_NetworkAdapterConfiguration 
        WHERE IPEnabled = 1
WQL

$sth-&gt;execute();
while (defined (my $row = $sth-&gt;fetchrow_arrayref())) {
    my $conf = $row-&gt;[0];
    
    print join "\t", @{ $conf-&gt;{IPAddress} }, "\n";
    if ($conf-&gt;{IPAddress}-&gt;[0] ne $target_ip) {
        print "Skipped\n";
        next
    };
        
    my $order = $conf-&gt;{DNSServerSearchOrder};
    if ($order) {
      print join "\t", @$order;
    } else {
        print "No DNS servers defined";
    };
    print "\n";
    $conf-&gt;SetDNSServerSearchOrder(['192.168.1.102', '127.0.0.1']);
}
&lt;/c&gt;
&lt;h2&gt;The Revolution Will Not Be In A Bulleted List&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The Revolution Will Not Be Televised&lt;/li&gt;
&lt;li&gt;The Revolution Will Not Be Webcast&lt;/li&gt;
&lt;li&gt;The Revolution Will Not Have Rounded Corners&lt;/li&gt;
&lt;li&gt;The Revolution Will Not Be Verified&lt;/li&gt;
&lt;li&gt;The Revolution's FAQ Will Not Be Archived At &lt;c&gt;rtfm.mit.edu&lt;/c&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Grand pile of projects&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Optimize &lt;c&gt;&lt;&gt;&lt;/c&gt; in void context so it just skips forward to the next occurrence of &lt;c&gt;$/&lt;/c&gt; without wasting memory.&lt;/li&gt;
&lt;li&gt;Hack OpenOffice.org so the PDF-printing engine becomes available as a command line tool. This means ripping out the import/export filter engines and glueing them together into a trivial pipeline that will read a Word/Excel/whatever file and turn it into PDF.&lt;/li&gt;
&lt;li&gt;Write a test for Perl as outlined in [http://www.nntp.perl.org/group/perl.perl5.porters/114256]&lt;/li&gt;
&lt;li&gt;Create [google://Google Sitemap] files from PM:
    &lt;ul&gt;
        &lt;li&gt;Users should be "fairly recent", based on their lastedit times&lt;/li&gt;
        &lt;li&gt;Nonuser nodes older than a month should become virtually static&lt;/li&gt;
        &lt;li&gt;All items should live in the robot playpen&lt;/li&gt;
    &lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Look at [cpan://App::Info] to let &lt;c&gt;Alien::Util&lt;/c&gt; offer locally installed versions instead of building perl-owned versions&lt;/li&gt;
&lt;/ol&gt;
&lt;li&gt;Create a (offline) (mp4) video mogrifier in Perl, to extract "sprites"/sprite sequences from video and to recreate a static "scene" image from a sequence of images, with all moving parts eliminated:
  &lt;ol&gt;
    &lt;li&gt;Use [http://ffmpeg.mplayerhq.hu/|ffmpeg] or ImageMagick to extract frames from video&lt;/li&gt;
    &lt;li&gt;Detect moving parts ("actors") on the image by xor-ing two frames of the movie that are "close" together (5 seconds apart maybe, or maybe two I-frames apart)&lt;/li&gt;
    &lt;li&gt;Then track the moving parts (as rectangular boxes) between adjactent frames, adding some fudge value and output them into a new video so they become actors&lt;/li&gt;
    &lt;li&gt;Recomposite the movie, inserting actors at will&lt;/li&gt;
    &lt;li&gt;[http://www.ee.iitb.ac.in/~icvgip/PAPERS/154.pdf|Paper on sprite/mosaic generation from movies] - a "sprite" in their lingo is the background, not the actor in the foreground&lt;/li&gt;
     &lt;li&gt;[http://www-static.cc.gatech.edu/gvu/perception//projects/videotexture/SIGGRAPH2000/vtbody.htm|Automatically creating random looped videos] by estimating the cost between frames to generate split/cut points&lt;/li&gt;
  &lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;How to construct a static query for dynamic parameters&lt;/h2&gt;
&lt;p&gt;The problem is that you know on the Perl side which parameters
are valid/given for a query, but you want to run one (and only one)
SQL statement against the database, to return every row only
once.&lt;/p&gt;&lt;p&gt;
The idea is to guard all query parameters with a second parameter
indicating if that parameter is to be used. Starting from:
&lt;/p&gt;
&lt;c&gt;
    SELECT COUNT(*) 
    FROM mx_forums
    WHERE id=? OR category = ? 
    -- $q-&gt;param('forum'), $q-&gt;param('category')
&lt;/c&gt;
&lt;p&gt;we want to add a second clause guarding the &lt;c&gt;id&lt;/c&gt;
and another one guarding &lt;c&gt;category&lt;/c&gt;:&lt;/p&gt; 
&lt;c&gt;
    SELECT COUNT(*) 
    FROM mx_forums
    WHERE 
         ((1 = ?) AND (id       = ?)) 
      OR ((1 = ?) AND (category = ?))
    -- defined $q-&gt;param('forum'), $q-&gt;param('forum')
    -- defined $q-&gt;param('category'), $q-&gt;param('category')
&lt;/c&gt;
&lt;p&gt;Now you need to pass the two additional parameters:&lt;/p&gt;
&lt;c&gt;
my $sql = q{ ... };
if ( $dbh-&gt;selectrow_array(
       $sql,
       { 
        Slice =&gt; {}
       },
       (defined $q-&gt;param('forum'))+0,
       $q-&gt;param('forum'),  
       (defined $q-&gt;param('category'))+0,
       $q-&gt;param('category')
    ) &gt;= 1 
     ) { ... }
&lt;/c&gt;
&lt;h2&gt;Using clauses with [cpan://SQL::Abstract]::Clauses (yet-to-be released)&lt;/h2&gt;
&lt;p&gt;The following statement is used to find all values for the columns &lt;tt&gt;artist&lt;/tt&gt; and &lt;tt&gt;album&lt;/tt&gt; that refine/subdivide the current result set.
&lt;/p&gt;
&lt;code&gt;
use strict;
use lib '.';
use Clauses;
#use SQL::Abstract::Clauses;

my $s = SQL::Abstract::Clauses-&gt;new();

my $where = { 1 =&gt; 0 }; # some preexisting where clause
my $total_count = 13;

for my $column (qw(artist album)) {
  my ($sql,@bind) = $s-&gt;select('foo',[ $column, 'count(*) as col_count' ],
                          where =&gt; $where, 
                          order_by =&gt; [ "$column asc", 'col_count desc' ],
                          having  =&gt; { col_count =&gt; [ -and =&gt; { '&gt;' =&gt; 0 }, { '&lt;' =&gt; $total_count }]},);
  print $sql,"\n";
}
&lt;/code&gt;
&lt;hr /&gt;

&lt;h2&gt;Another stab at making IPC::Open3 &lt;c&gt;select&lt;/c&gt;able&lt;/h2&gt;
&lt;c&gt;
#!/usr/bin/perl
use warnings;
use strict;

use IO::Handle;
use IO::Select;

use IPC::Open3;
BEGIN {
      eval "sub WSAEINVAL      () { 10022 }";
      eval "sub WSAEWOULDBLOCK () { 10035 }";
      eval "sub WSAEINPROGRESS () { 10036 }";
      };
BEGIN {
    # cribbed from AnyEvent::Util
    use Socket;
    sub _win32_socketpair {
       # perl's socketpair emulation fails on many vista machines, because
       # vista returns fantasy port numbers.
    
       for (1..10) {
          socket my $l, &amp;Socket::AF_INET, &amp;Socket::SOCK_STREAM, 0
             or next;
    
          bind $l, Socket::pack_sockaddr_in 0, "\x7f\x00\x00\x01"
             or next;
    
          my $sa = getsockname $l
             or next;
    
          listen $l, 1
             or next;
    
          socket my $r, &amp;Socket::AF_INET, &amp;Socket::SOCK_STREAM, 0
             or next;
    
          bind $r, Socket::pack_sockaddr_in 0, "\x7f\x00\x00\x01"
             or next;
    
          connect $r, $sa
             or next;
    
          accept my $w, $l
             or next;
    
          # vista has completely broken peername/sockname that return
          # fantasy ports. this combo seems to work, though.
          #
          (Socket::unpack_sockaddr_in getpeername $r)[0]
          == (Socket::unpack_sockaddr_in getsockname $w)[0]
             or (($! = WSAEINVAL), next);
    
          # vista example (you can't make this shit up...):
          #(Socket::unpack_sockaddr_in getsockname $r)[0] == 53364
          #(Socket::unpack_sockaddr_in getpeername $r)[0] == 53363
          #(Socket::unpack_sockaddr_in getsockname $w)[0] == 53363
          #(Socket::unpack_sockaddr_in getpeername $w)[0] == 53365
    
          return ($r, $w);
       };
       ()
    };

*IPC::Open3::xpipe = sub {
        use Socket qw(AF_UNIX SOCK_STREAM PF_UNSPEC);
        
        use IO::Handle;
        
        #socketpair $_[0], $_[1], AF_UNIX, SOCK_STREAM, PF_UNSPEC
        #    or die "socketpair: $!";
        (*{$_[0]},*{$_[1]}) = _win32_socketpair();
        #    or die "socketpair: $!";
        # stop reading on the write handle:
         shutdown $_[1], 0 or die "shutdown: $!";
         # stop writing on the read handle:
         shutdown $_[0], 1 or die "shutdown: $!";
    };
    
};

my $expected = 100;

#my $cat_self = q{"%s" -ple "$|++;sleep(rand(0));$_=qq{%s_$_};END{sleep 5}" %s};
#my $cat_self = q{"%s" -ple "$|++;sleep(rand(0));$_=qq{%s_$_};" %s};
my $proc = q{"%s" -le "$|=1;$n=shift;for(shift..shift){sleep(rand(3));print+qq($n $_)};" %s %s %s};
my @procs = (
    sprintf( $proc, $^X, 'child_1', 1,$expected),
    sprintf( $proc, $^X, 'child_2', 1,$expected),
    sprintf( $proc, $^X, 'child_3', 1,$expected),
);

my @kill_pids;
END { print "Cleaning up children @kill_pids\n"; kill 9 =&gt; @kill_pids };

my %children;

my $select = IO::Select-&gt;new;
for my $child (@procs) {
    my $child_err = IO::Handle-&gt;new();
    my $pid= open3 my $child_in, my $child_out, $child_err, $child
        or die "Launching $child: $!";
    push @kill_pids,$pid;
    $children{ $child_out } = $pid;

    print "[$pid] $child launched\n";
    $select-&gt;add($child_out);
};

print "Launched children, waiting for things to become readable\n";
print "Expecting $expected lines\n", ;
my %buffer;
my %received;
$SIG{CHLD} = sub { warn "Child: " . wait };
$SIG{PIPE} = sub { warn "Child: $_" };
warn $select-&gt;count() . " children to read from.";
while ($select-&gt;count) {
    my @ready = $select-&gt;can_read();
    #warn "Got " . scalar(@ready) . " handles ready.\n";
    for my $fh (@ready) {
        if (not exists $buffer{$fh}) {
            $buffer{$fh} = "";
        };
        my $bytesread = sysread($fh,$buffer{$fh},1024,length($buffer{$fh}));
        if ($bytesread == 0) {
            use POSIX ':sys_wait_h';
            if ((my $state = waitpid($children{ $fh }, WNOHANG)) &lt;= 0) {
                print "\n$children{ $fh } is done\n";
            } else {
                #print "\n$children{ $fh } is still alive :(\n";
            }
            $select-&gt;remove($fh);
        } elsif (! defined $bytesread) {
            #print "\nError on reading from $fh: $! / $^E\n";
            $select-&gt;remove($fh);
        } elsif (! $bytesread) {
            print "The lights are on but nobody's home for $fh\n";
        } elsif ($buffer{$fh} =~ /\n$/) {
            $received{$fh}++
                for split /\n/, $buffer{$fh};
            #print $buffer{$fh};
            $buffer{$fh} = "";
        }
    };
    for (sort keys %received) {
        print "[$children{ $_ }]\t$received{$_} lines\t";
    }
    print "\n";
};


print "Waitpid-dding for children\n";
for (@kill_pids) { waitpid $_,0 };

for (sort keys %received) {
    print "$children{$_}\t$received{$_}\n";
}

print "Done.";
&lt;/c&gt;

&lt;h2&gt;Nodes whose content was overwritten and which can't be restored&lt;/h2&gt;
&lt;br /&gt;[id://641995]
</field>
</data>
</node>
