Add handlerviz.pl.
diff --git a/asio/boostify.pl b/asio/boostify.pl
index dae1be9..7155047 100755
--- a/asio/boostify.pl
+++ b/asio/boostify.pl
@@ -472,8 +472,23 @@
   }
 }
 
+sub copy_tools
+{
+  our $boost_dir;
+  my @files = (
+      glob("src/tools/*.pl"));
+  foreach my $file (@files)
+  {
+    my $from = $file;
+    my $to = $file;
+    $to =~ s/^src\/tools\//$boost_dir\/libs\/asio\/tools\//;
+    copy_source_file($from, $to);
+  }
+}
+
 copy_include_files();
 create_lib_directory();
 copy_unit_tests();
 copy_examples();
 copy_doc();
+copy_tools();
diff --git a/asio/src/tools/handlerviz.pl b/asio/src/tools/handlerviz.pl
new file mode 100755
index 0000000..06249a2
--- /dev/null
+++ b/asio/src/tools/handlerviz.pl
@@ -0,0 +1,299 @@
+#!/usr/bin/perl -w
+#
+# handlerviz.pl
+# ~~~~~~~~~~~~~
+#
+# A visualisation tool for post-processing the debug output generated by
+# Asio-based programs. Programs write this output to the standard error stream
+# when compiled with the define `ASIO_ENABLE_HANDLER_TRACKING'.
+#
+# This tool generates output intended for use with the GraphViz tool `dot'. For
+# example, to convert output to a PNG image, use:
+#
+#   perl handlerviz.pl < output.txt | dot -Tpng > output.png
+#
+# To convert to a PDF file, use:
+#
+#   perl handlerviz.pl < output.txt | dot -Tpdf > output.pdf
+#
+# Copyright (c) 2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+#
+# Distributed under the Boost Software License, Version 1.0. (See accompanying
+# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+#
+
+use strict;
+
+my %nodes = ();
+my @edges = ();
+my %anon_nodes = ();
+my $anon_id = 0;
+my %all_nodes = ();
+
+#-------------------------------------------------------------------------------
+# Parse the debugging output and populate the nodes and edges.
+
+sub parse_debug_output()
+{
+  while (my $line = <>)
+  {
+    chomp($line);
+
+    if ($line =~ /\@asio\|([^|]*)\|([^|]*)\|(.*)$/)
+    {
+      my $timestamp = $1;
+      my $action = $2;
+      my $description = $3;
+
+      # Handler creation.
+      if ($action =~ /^([0-9]+)\*([0-9]+)$/)
+      {
+        my $begin = $1;
+        my $end = $2;
+        my $label = $description;
+        $label =~ s/\./\\n/g;
+
+        if ($begin eq "0")
+        {
+          $begin = "a" . $anon_id++;
+          $anon_nodes{$begin} = $timestamp;
+          $all_nodes{"$timestamp-$begin"} = $begin;
+        }
+
+        my %edge = ( begin=>$begin, end=>$end, label=>$label );
+        push(@edges, \%edge);
+      }
+
+      # Begin handler invocation. 
+      elsif ($action =~ /^>([0-9]+)$/)
+      {
+        my %new_node = ( label=>$description, entry=>$timestamp );
+        $new_node{content} = ();
+        $nodes{$1} = \%new_node;
+        $all_nodes{"$timestamp-$1"} = $1;
+      }
+
+      # End handler invocation.
+      elsif ($action =~ /^<([0-9]+)$/)
+      {
+        $nodes{$1}->{exit} = $timestamp;
+      }
+
+      # Handler threw exception.
+      elsif ($action =~ /^!([0-9]+)$/)
+      {
+        push(@{$nodes{$1}->{content}}, "exception");
+      }
+
+      # Handler was destroyed without being invoked.
+      elsif ($action =~ /^~([0-9]+)$/)
+      {
+        my %new_node = ( label=>"$timestamp destroyed" );
+        $new_node{content} = ();
+        $nodes{$1} = \%new_node;
+        $all_nodes{"$timestamp-$1"} = $1;
+      }
+
+      # Handler performed some operation.
+      elsif ($action =~ /^([0-9]+)$/)
+      {
+        if ($1 eq "0")
+        {
+          my $id = "a" . $anon_id++;
+          $anon_nodes{$id} = "$timestamp\\l$description";
+          $all_nodes{"$timestamp-$id"} = $id;
+        }
+        else
+        {
+          push(@{$nodes{$1}->{content}}, "$description");
+        }
+      }
+    }
+  }
+}
+
+#-------------------------------------------------------------------------------
+# Helper function to convert a string to escaped HTML text.
+
+sub escape($)
+{
+  my $text = shift;
+  $text =~ s/&/\&amp\;/g;
+  $text =~ s/</\&lt\;/g;
+  $text =~ s/>/\&gt\;/g;
+  $text =~ s/\t/    /g;
+  return $text;
+}
+
+#-------------------------------------------------------------------------------
+# Templates for dot output.
+
+my $graph_header = <<"EOF";
+/* Generated by asioviz.pl */
+digraph G
+{
+graph [ nodesep="1" ];
+node [ shape="box", fontsize="9" ];
+edge [ arrowtail="dot", fontsize="9" ];
+EOF
+
+my $graph_footer = <<"EOF";
+}
+EOF
+
+my $node_header = <<"EOF";
+"%name%"
+[
+label=<<table border="0" cellspacing="0">
+<tr><td align="left" bgcolor="gray" border="0">%label%</td></tr>
+EOF
+
+my $node_footer = <<"EOF";
+</table>>
+]
+EOF
+
+my $node_content = <<"EOF";
+<tr><td align="left" bgcolor="white" border="0">
+<font face="mono" point-size="9">%content%</font>
+</td></tr>
+EOF
+
+my $anon_nodes_header = <<"EOF";
+{
+node [ shape="record" ];
+EOF
+
+my $anon_nodes_footer = <<"EOF";
+}
+EOF
+
+my $anon_node = <<"EOF";
+"%name%" [ label="%label%", color="gray" ];
+EOF
+
+my $edges_header = <<"EOF";
+{
+edge [ style="dashed", arrowhead="open", weight="100" ];
+EOF
+
+my $edges_footer = <<"EOF";
+}
+EOF
+
+my $edge = <<"EOF";
+"%begin%" -> "%end%" [ label="%label%" ]
+EOF
+
+my $node_order_header = <<"EOF";
+{
+edge [ style="invis", weight="1" ];
+EOF
+
+my $node_order_footer = <<"EOF";
+}
+EOF
+
+my $node_order = <<"EOF";
+"%begin%" -> "%end%"
+EOF
+
+#-------------------------------------------------------------------------------
+# Generate dot output from the nodes and edges.
+
+sub print_nodes()
+{
+  foreach my $name (sort keys %nodes)
+  {
+    my $node = $nodes{$name};
+    my $entry = $node->{entry};
+    my $exit = $node->{exit};
+    my $label = escape($node->{label});
+    my $header = $node_header;
+    $header =~ s/%name%/$name/g;
+    $header =~ s/%label%/$label/g;
+    print($header);
+
+    my $line = $node_content;
+    my $content = $entry . " + " . sprintf("%.6f", $exit - $entry) . "s";
+    $line =~ s/%content%/$content/g;
+    print($line);
+
+    foreach my $content (@{$node->{content}})
+    {
+      $content = escape($content);
+      $content = " " if length($content) == 0;
+      my $line = $node_content;
+      $line =~ s/%content%/$content/g;
+      print($line);
+    }
+
+    print($node_footer);
+  }
+}
+
+sub print_anon_nodes()
+{
+  print($anon_nodes_header);
+  foreach my $name (sort keys %anon_nodes)
+  {
+    my $label = $anon_nodes{$name};
+    my $line = $anon_node;
+    $line =~ s/%name%/$name/g;
+    $line =~ s/%label%/$label/g;
+    print($line);
+  }
+  print($edges_footer);
+}
+
+sub print_edges()
+{
+  print($edges_header);
+  foreach my $e (@edges)
+  {
+    my $begin = $e->{begin};
+    my $end = $e->{end};
+    my $label = $e->{label};
+    my $line = $edge;
+    $line =~ s/%begin%/$begin/g;
+    $line =~ s/%end%/$end/g;
+    $line =~ s/%label%/$label/g;
+    print($line);
+  }
+  print($edges_footer);
+}
+
+sub print_node_order()
+{
+  my $prev = "";
+  print($node_order_header);
+  foreach my $name (sort keys %all_nodes)
+  {
+    if ($prev ne "")
+    {
+      my $begin = $prev;
+      my $end = $all_nodes{$name};
+      my $line = $node_order;
+      $line =~ s/%begin%/$begin/g;
+      $line =~ s/%end%/$end/g;
+      print($line);
+    }
+    $prev = $all_nodes{$name};
+  }
+  print($node_order_footer);
+}
+
+sub generate_dot()
+{
+  print($graph_header);
+  print_nodes();
+  print_anon_nodes();
+  print_edges();
+  print_node_order();
+  print($graph_footer);
+}
+
+#-------------------------------------------------------------------------------
+
+parse_debug_output();
+generate_dot();