[Orca-checkins] rev 107 - in trunk/orca: . config lib src docs packages packages/Storable-0.6 at 3 packages/Storable-0.6 at 3/t packages/Digest-MD5-2.07 packages/Digest-MD5-2.07/MD2 packages/Digest-MD5-2.07/MD2/t packages/Digest-MD5-2.07/t packages/Digest-MD5-2.07/hints packages/Digest-MD5-2.07/lib packages/Digest-MD5-2.07/lib/Digest packages/Digest-MD5-2.07/SHA1 packages/Digest-MD5-2.07/SHA1/t packages/Digest-MD5-2.07/SHA1/lib packages/Digest-MD5-2.07/examples packages/rrdtool-0.99.29.1 packages/rrdtool-0.99.29.1/src packages/rrdtool-0.99.29.1/contrib packages/rrdtool-0.99.29.1/contrib/log2rrd packages/rrdtool-0.99.29.1/contrib/trytime packages/rrdtool-0.99.29.1/perl-piped packages/rrdtool-0.99.29.1/perl-piped/t packages/rrdtool-0.99.29.1/perl-piped/examples packages/rrdtool-0.99.29.1/doc packages/rrdtool-0.99.29.1/perl-shared packages/rrdtool-0.99.29.1/perl-shared/t packages/rrdtool-0.99.29.1/perl-shared/examples packages/rrdtool-0.99.29.1/gd1.2 packages/Math-Interpolate-1.02 packages/Math-Interpolate-1.02/t packages/Math-Interpolate-1.02/lib packages/Math-Interpolate-1.02/lib/Math

blair at orcaware.com blair at orcaware.com
Sat Jul 13 18:47:03 PDT 2002


Author: blair
Date: Fri, 28 Jun 2002 21:58:34 -0700
New Revision: 107

Added:
   trunk/orca/NEWS
   trunk/orca/config/check_for_perl_mod
   trunk/orca/packages/
   trunk/orca/packages/Digest-MD5-2.07/
   trunk/orca/packages/Digest-MD5-2.07/Changes
   trunk/orca/packages/Digest-MD5-2.07/MANIFEST
   trunk/orca/packages/Digest-MD5-2.07/MD2/
   trunk/orca/packages/Digest-MD5-2.07/MD2/MD2.pm
   trunk/orca/packages/Digest-MD5-2.07/MD2/MD2.xs
   trunk/orca/packages/Digest-MD5-2.07/MD2/Makefile.PL
   trunk/orca/packages/Digest-MD5-2.07/MD2/rfc1319.txt
   trunk/orca/packages/Digest-MD5-2.07/MD2/t/
   trunk/orca/packages/Digest-MD5-2.07/MD2/t/md2.t
   trunk/orca/packages/Digest-MD5-2.07/MD2/typemap
   trunk/orca/packages/Digest-MD5-2.07/MD5.pm
   trunk/orca/packages/Digest-MD5-2.07/MD5.xs
   trunk/orca/packages/Digest-MD5-2.07/Makefile.PL
   trunk/orca/packages/Digest-MD5-2.07/README
   trunk/orca/packages/Digest-MD5-2.07/SHA1/
   trunk/orca/packages/Digest-MD5-2.07/SHA1/Makefile.PL
   trunk/orca/packages/Digest-MD5-2.07/SHA1/SHA1.pm
   trunk/orca/packages/Digest-MD5-2.07/SHA1/SHA1.xs
   trunk/orca/packages/Digest-MD5-2.07/SHA1/lib/
   trunk/orca/packages/Digest-MD5-2.07/SHA1/lib/SHA.pm
   trunk/orca/packages/Digest-MD5-2.07/SHA1/t/
   trunk/orca/packages/Digest-MD5-2.07/SHA1/t/sha.t
   trunk/orca/packages/Digest-MD5-2.07/SHA1/t/sha1.t
   trunk/orca/packages/Digest-MD5-2.07/SHA1/typemap
   trunk/orca/packages/Digest-MD5-2.07/examples/
   trunk/orca/packages/Digest-MD5-2.07/examples/mddriver.pl
   trunk/orca/packages/Digest-MD5-2.07/examples/twdigest.pl
   trunk/orca/packages/Digest-MD5-2.07/hints/
   trunk/orca/packages/Digest-MD5-2.07/hints/dec_osf.pl
   trunk/orca/packages/Digest-MD5-2.07/hints/irix_6.pl
   trunk/orca/packages/Digest-MD5-2.07/lib/
   trunk/orca/packages/Digest-MD5-2.07/lib/Digest.pm
   trunk/orca/packages/Digest-MD5-2.07/lib/Digest/
   trunk/orca/packages/Digest-MD5-2.07/lib/Digest/HMAC.pm
   trunk/orca/packages/Digest-MD5-2.07/lib/Digest/HMAC_MD5.pm
   trunk/orca/packages/Digest-MD5-2.07/lib/Digest/HMAC_SHA1.pm
   trunk/orca/packages/Digest-MD5-2.07/lib/MD5.pm
   trunk/orca/packages/Digest-MD5-2.07/rfc1321.txt
   trunk/orca/packages/Digest-MD5-2.07/rfc2104.txt
   trunk/orca/packages/Digest-MD5-2.07/t/
   trunk/orca/packages/Digest-MD5-2.07/t/digest.t
   trunk/orca/packages/Digest-MD5-2.07/t/files.t
   trunk/orca/packages/Digest-MD5-2.07/t/md5-aaa.t
   trunk/orca/packages/Digest-MD5-2.07/t/md5.t
   trunk/orca/packages/Digest-MD5-2.07/t/rfc2202.t
   trunk/orca/packages/Digest-MD5-2.07/typemap
   trunk/orca/packages/Makefile.in
   trunk/orca/packages/Math-Interpolate-1.02/
   trunk/orca/packages/Math-Interpolate-1.02/CHANGES
   trunk/orca/packages/Math-Interpolate-1.02/MANIFEST
   trunk/orca/packages/Math-Interpolate-1.02/Makefile.PL
   trunk/orca/packages/Math-Interpolate-1.02/README
   trunk/orca/packages/Math-Interpolate-1.02/lib/
   trunk/orca/packages/Math-Interpolate-1.02/lib/Math/
   trunk/orca/packages/Math-Interpolate-1.02/lib/Math/Interpolate.pm
   trunk/orca/packages/Math-Interpolate-1.02/lib/Math/IntervalSearch.pm
   trunk/orca/packages/Math-Interpolate-1.02/t/
   trunk/orca/packages/Math-Interpolate-1.02/t/01interval.t
   trunk/orca/packages/Math-Interpolate-1.02/t/02interp.t
   trunk/orca/packages/Storable-0.6 at 3/
   trunk/orca/packages/Storable-0.6 at 3/ChangeLog
   trunk/orca/packages/Storable-0.6 at 3/MANIFEST
   trunk/orca/packages/Storable-0.6 at 3/Makefile.PL
   trunk/orca/packages/Storable-0.6 at 3/README
   trunk/orca/packages/Storable-0.6 at 3/Storable.pm
   trunk/orca/packages/Storable-0.6 at 3/Storable.xs
   trunk/orca/packages/Storable-0.6 at 3/patchlevel.h
   trunk/orca/packages/Storable-0.6 at 3/t/
   trunk/orca/packages/Storable-0.6 at 3/t/canonical.t
   trunk/orca/packages/Storable-0.6 at 3/t/dclone.t
   trunk/orca/packages/Storable-0.6 at 3/t/dump.pl
   trunk/orca/packages/Storable-0.6 at 3/t/forgive.t
   trunk/orca/packages/Storable-0.6 at 3/t/freeze.t
   trunk/orca/packages/Storable-0.6 at 3/t/retrieve.t
   trunk/orca/packages/Storable-0.6 at 3/t/store.t
   trunk/orca/packages/Storable-0.6 at 3/t/tied.t
   trunk/orca/packages/rrdtool-0.99.29.1/
   trunk/orca/packages/rrdtool-0.99.29.1/CHANGES
   trunk/orca/packages/rrdtool-0.99.29.1/CONTRIBUTORS
   trunk/orca/packages/rrdtool-0.99.29.1/COPYING
   trunk/orca/packages/rrdtool-0.99.29.1/COPYRIGHT
   trunk/orca/packages/rrdtool-0.99.29.1/MANIFEST
   trunk/orca/packages/rrdtool-0.99.29.1/Makefile.dist
   trunk/orca/packages/rrdtool-0.99.29.1/Makefile.in
   trunk/orca/packages/rrdtool-0.99.29.1/README
   trunk/orca/packages/rrdtool-0.99.29.1/TODO
   trunk/orca/packages/rrdtool-0.99.29.1/config.h.in
   trunk/orca/packages/rrdtool-0.99.29.1/configure
   trunk/orca/packages/rrdtool-0.99.29.1/configure.in
   trunk/orca/packages/rrdtool-0.99.29.1/contrib/
   trunk/orca/packages/rrdtool-0.99.29.1/contrib/README
   trunk/orca/packages/rrdtool-0.99.29.1/contrib/log2rrd/
   trunk/orca/packages/rrdtool-0.99.29.1/contrib/log2rrd/README
   trunk/orca/packages/rrdtool-0.99.29.1/contrib/log2rrd/log2rrd.pl
   trunk/orca/packages/rrdtool-0.99.29.1/contrib/trytime/
   trunk/orca/packages/rrdtool-0.99.29.1/contrib/trytime/Makefile
   trunk/orca/packages/rrdtool-0.99.29.1/contrib/trytime/README
   trunk/orca/packages/rrdtool-0.99.29.1/contrib/trytime/trytime.c
   trunk/orca/packages/rrdtool-0.99.29.1/doc/
   trunk/orca/packages/rrdtool-0.99.29.1/doc/GNUmakefile.in
   trunk/orca/packages/rrdtool-0.99.29.1/doc/RRDp.3
   trunk/orca/packages/rrdtool-0.99.29.1/doc/RRDp.html
   trunk/orca/packages/rrdtool-0.99.29.1/doc/RRDs.3
   trunk/orca/packages/rrdtool-0.99.29.1/doc/RRDs.html
   trunk/orca/packages/rrdtool-0.99.29.1/doc/bin_dec_hex.1
   trunk/orca/packages/rrdtool-0.99.29.1/doc/bin_dec_hex.html
   trunk/orca/packages/rrdtool-0.99.29.1/doc/bin_dec_hex.pod
   trunk/orca/packages/rrdtool-0.99.29.1/doc/bin_dec_hex.txt
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdcreate.1
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdcreate.html
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdcreate.pod
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdcreate.txt
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrddump.1
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrddump.html
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrddump.pod
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrddump.txt
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdfetch.1
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdfetch.html
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdfetch.pod
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdfetch.txt
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdgraph.1
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdgraph.html
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdgraph.pod
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdgraph.txt
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdintro.pod
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdlast.1
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdlast.html
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdlast.pod
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdlast.txt
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdtool.1
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdtool.html
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdtool.pod
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdtool.txt
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdtune.1
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdtune.html
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdtune.pod
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdtune.txt
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdtutorial.1
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdtutorial.html
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdtutorial.pod
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdtutorial.txt
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdupdate.1
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdupdate.html
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdupdate.pod
   trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdupdate.txt
   trunk/orca/packages/rrdtool-0.99.29.1/gd1.2/
   trunk/orca/packages/rrdtool-0.99.29.1/gd1.2/Makefile.in
   trunk/orca/packages/rrdtool-0.99.29.1/gd1.2/README
   trunk/orca/packages/rrdtool-0.99.29.1/gd1.2/demoin.gif
   trunk/orca/packages/rrdtool-0.99.29.1/gd1.2/gd.c
   trunk/orca/packages/rrdtool-0.99.29.1/gd1.2/gd.dsp
   trunk/orca/packages/rrdtool-0.99.29.1/gd1.2/gd.dsw
   trunk/orca/packages/rrdtool-0.99.29.1/gd1.2/gd.h
   trunk/orca/packages/rrdtool-0.99.29.1/gd1.2/gddemo.c
   trunk/orca/packages/rrdtool-0.99.29.1/gd1.2/gdfontg.c
   trunk/orca/packages/rrdtool-0.99.29.1/gd1.2/gdfontg.h
   trunk/orca/packages/rrdtool-0.99.29.1/gd1.2/gdfontl.c
   trunk/orca/packages/rrdtool-0.99.29.1/gd1.2/gdfontl.h
   trunk/orca/packages/rrdtool-0.99.29.1/gd1.2/gdfontmb.c
   trunk/orca/packages/rrdtool-0.99.29.1/gd1.2/gdfontmb.h
   trunk/orca/packages/rrdtool-0.99.29.1/gd1.2/gdfonts.c
   trunk/orca/packages/rrdtool-0.99.29.1/gd1.2/gdfonts.h
   trunk/orca/packages/rrdtool-0.99.29.1/gd1.2/gdfontt.c
   trunk/orca/packages/rrdtool-0.99.29.1/gd1.2/gdfontt.h
   trunk/orca/packages/rrdtool-0.99.29.1/gd1.2/giftogd.c
   trunk/orca/packages/rrdtool-0.99.29.1/gd1.2/index.html
   trunk/orca/packages/rrdtool-0.99.29.1/gd1.2/mathmake.c
   trunk/orca/packages/rrdtool-0.99.29.1/gd1.2/mtables.c
   trunk/orca/packages/rrdtool-0.99.29.1/gd1.2/webgif.c
   trunk/orca/packages/rrdtool-0.99.29.1/install-sh
   trunk/orca/packages/rrdtool-0.99.29.1/perl-piped/
   trunk/orca/packages/rrdtool-0.99.29.1/perl-piped/MANIFEST
   trunk/orca/packages/rrdtool-0.99.29.1/perl-piped/Makefile.PL
   trunk/orca/packages/rrdtool-0.99.29.1/perl-piped/README
   trunk/orca/packages/rrdtool-0.99.29.1/perl-piped/RRDp.pm
   trunk/orca/packages/rrdtool-0.99.29.1/perl-piped/examples/
   trunk/orca/packages/rrdtool-0.99.29.1/perl-piped/examples/piped-demo.pl.in
   trunk/orca/packages/rrdtool-0.99.29.1/perl-piped/t/
   trunk/orca/packages/rrdtool-0.99.29.1/perl-piped/t/base.t
   trunk/orca/packages/rrdtool-0.99.29.1/perl-shared/
   trunk/orca/packages/rrdtool-0.99.29.1/perl-shared/MANIFEST
   trunk/orca/packages/rrdtool-0.99.29.1/perl-shared/Makefile.PL
   trunk/orca/packages/rrdtool-0.99.29.1/perl-shared/README
   trunk/orca/packages/rrdtool-0.99.29.1/perl-shared/RRDs.pm
   trunk/orca/packages/rrdtool-0.99.29.1/perl-shared/RRDs.xs
   trunk/orca/packages/rrdtool-0.99.29.1/perl-shared/examples/
   trunk/orca/packages/rrdtool-0.99.29.1/perl-shared/examples/shared-demo.pl.in
   trunk/orca/packages/rrdtool-0.99.29.1/perl-shared/t/
   trunk/orca/packages/rrdtool-0.99.29.1/perl-shared/t/base.t
   trunk/orca/packages/rrdtool-0.99.29.1/src/
   trunk/orca/packages/rrdtool-0.99.29.1/src/Makefile.in
   trunk/orca/packages/rrdtool-0.99.29.1/src/getopt.c
   trunk/orca/packages/rrdtool-0.99.29.1/src/getopt.h
   trunk/orca/packages/rrdtool-0.99.29.1/src/getopt1.c
   trunk/orca/packages/rrdtool-0.99.29.1/src/ntconfig.h
   trunk/orca/packages/rrdtool-0.99.29.1/src/parsetime.c
   trunk/orca/packages/rrdtool-0.99.29.1/src/parsetime.h
   trunk/orca/packages/rrdtool-0.99.29.1/src/rrd.dsp
   trunk/orca/packages/rrdtool-0.99.29.1/src/rrd.dsw
   trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_create.c
   trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_diff.c
   trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_dump.c
   trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_error.c
   trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_fetch.c
   trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_format.c
   trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_format.h
   trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_graph.c
   trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_last.c
   trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_open.c
   trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_tool.c
   trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_tool.h
   trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_tune.c
   trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_update.c
   trunk/orca/packages/rrdtool-0.99.29.1/src/rrdtool.dsp
   trunk/orca/packages/rrdtool-0.99.29.1/src/rrdtool.dsw
   trunk/orca/src/migrate_to_orcallator.pl
Modified:
   trunk/orca/CHANGES
   trunk/orca/INSTALL
   trunk/orca/Makefile.in
   trunk/orca/README
   trunk/orca/TODO
   trunk/orca/config/PerlHead1.in
   trunk/orca/config/PerlHead2.in
   trunk/orca/config/acinclude.m4
   trunk/orca/configure
   trunk/orca/configure.in
   trunk/orca/docs/ARCHITECTURE
   trunk/orca/lib/Makefile.in
   trunk/orca/lib/orcallator.cfg.in
   trunk/orca/lib/orcallator.se
   trunk/orca/lib/time_gets.cfg
   trunk/orca/src/Makefile.in
   trunk/orca/src/orca.pl
   trunk/orca/src/orcallator_column.pl
   trunk/orca/src/orcallator_running.pl.in
   trunk/orca/src/restart_orcallator.sh.in
   trunk/orca/src/start_orcallator.sh.in
   trunk/orca/src/stop_orcallator.sh.in
Log:
Load orca-0.21 into trunk/orca.


Modified: trunk/orca/configure
==============================================================================
--- trunk/orca/configure	(original)
+++ trunk/orca/configure	Sat Jul 13 18:45:50 2002
@@ -12,17 +12,17 @@
 ac_default_prefix=/usr/local
 # Any additions from configure.in:
 ac_help="$ac_help
-   --with-rrd-dir=DIR     directory were the RRD data files are stored"
+   --with-rrd-dir=DIR         directory were the RRD data files are stored"
 ac_help="$ac_help
-   --with-html-dir=DIR    location of the root output HTML directory"
+   --with-html-dir=DIR        location of the root output HTML directory"
 ac_help="$ac_help
-   --with-perc-dir=DIR    directory were percollator output is stored"
+   --with-orcallator-dir=DIR  directory were orcallator output is stored"
 ac_help="$ac_help
-   --with-ncsa-log=FILE   location of the NCSA style web server access log"
+   --with-ncsa-log=FILE       location of the NCSA style web server access log"
 ac_help="$ac_help
-   --with-proxy-log=FILE  location of the proxy NCSA style web server access log"
+   --with-proxy-log=FILE      location of the proxy NCSA web server access log"
 ac_help="$ac_help
-   --with-squid-log=FILE  location of the Squid file"
+   --with-squid-log=FILE      location of the Squid file log file"
 
 # Initialize some variables set by options.
 # The variables have the same names as the options, with
@@ -642,10 +642,26 @@
   program_prefix=${target_alias}-
 
 
+# Remember the command line arguments to configure for use when
+# configure is run again.
+CONFIGURE_COMMAND_LINE=${1+"$@"}
+
+
+# Define the directories containing packages that Orca makes use of here.
+# The path packages gets added where necessary.
+DIGEST_MD5_DIR=Digest-MD5-2.07
+MATH_INTERPOLATE_DIR=Math-Interpolate-1.02
+RRDTOOL_DIR=rrdtool-0.99.29.1
+STORABLE_DIR=Storable-0.6 at 3
+
+
+
+
+
 # Minimum Autoconf version required.
 
 
-# Define the directories where the source percollator and RRD data files
+# Define the directories where the source orcallator and RRD data files
 # will be installed.
 # Check whether --with-rrd-dir or --without-rrd-dir was given.
 if test "${with_rrd_dir+set}" = set; then
@@ -690,27 +706,27 @@
 
 
 
-# Check whether --with-perc-dir or --without-perc-dir was given.
-if test "${with_perc_dir+set}" = set; then
-  withval="$with_perc_dir"
+# Check whether --with-orcallator-dir or --without-orcallator-dir was given.
+if test "${with_orcallator_dir+set}" = set; then
+  withval="$with_orcallator_dir"
   
     case "$withval" in
       "" | y | ye | yes | n | no)
-         { echo "configure: error: *** You must supply an argument to the --with-perc-dir option." 1>&2; exit 1; }
+         { echo "configure: error: *** You must supply an argument to the --with-orcallator-dir option." 1>&2; exit 1; }
          ;;
-      *) PERCOLLATOR_DIR="$withval"
+      *) ORCALLATOR_DIR="$withval"
          ;;
     esac
   
 else
-  : ${PERCOLLATOR_DIR=$localstatedir/orca/percollator}
+  : ${ORCALLATOR_DIR=$localstatedir/orca/orcallator}
 
 fi
 
-PERCOLLATOR_DIR=`(
+ORCALLATOR_DIR=`(
     test "x$prefix" = xNONE && prefix=$ac_default_prefix
     test "x$exec_prefix" = xNONE && exec_prefix=${prefix}
-    eval echo "$PERCOLLATOR_DIR"
+    eval echo "$ORCALLATOR_DIR"
 )`
 
 
@@ -782,6 +798,258 @@
 
 
 
+# To get a default CFLAGS for this build, check for a C compiler.  This
+# is also needed to be ready to compile any Perl modules.
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:807: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="gcc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:837: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_prog_rejected=no
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+        ac_prog_rejected=yes
+	continue
+      fi
+      ac_cv_prog_CC="cc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# -gt 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    set dummy "$ac_dir/$ac_word" "$@"
+    shift
+    ac_cv_prog_CC="$@"
+  fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+  if test -z "$CC"; then
+    case "`uname -s`" in
+    *win32* | *WIN32*)
+      # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:888: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="cl"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+ ;;
+    esac
+  fi
+  test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:920: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 931 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:936: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  ac_cv_prog_cc_works=yes
+  # If we can't run a trivial program, we are probably using a cross compiler.
+  if (./conftest; exit) 2>/dev/null; then
+    ac_cv_prog_cc_cross=no
+  else
+    ac_cv_prog_cc_cross=yes
+  fi
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+  { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:962: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:967: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.c <<EOF
+#ifdef __GNUC__
+  yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:976: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+  ac_cv_prog_gcc=yes
+else
+  ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:995: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+  ac_cv_prog_cc_g=yes
+else
+  ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:1028: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftestmake <<\EOF
+all:
+	@echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+  eval ac_cv_prog_make_${ac_make}_set=yes
+else
+  eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  SET_MAKE=
+else
+  echo "$ac_t""no" 1>&6
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
 if test "$program_transform_name" = s,x,x,; then
   program_transform_name=
 else
@@ -806,7 +1074,7 @@
 # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:810: checking for $ac_word" >&5
+echo "configure:1078: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_path_AWK'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -844,7 +1112,7 @@
 # Extract the first word of "cut", so it can be a program name with args.
 set dummy cut; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:848: checking for $ac_word" >&5
+echo "configure:1116: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_path_CUT'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -880,7 +1148,7 @@
 # Extract the first word of "expr", so it can be a program name with args.
 set dummy expr; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:884: checking for $ac_word" >&5
+echo "configure:1152: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_path_EXPR'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -916,7 +1184,7 @@
 # Extract the first word of "se", so it can be a program name with args.
 set dummy se; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:920: checking for $ac_word" >&5
+echo "configure:1188: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_path_SE'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -951,7 +1219,7 @@
 # Extract the first word of "uname", so it can be a program name with args.
 set dummy uname; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:955: checking for $ac_word" >&5
+echo "configure:1223: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_path_UNAME'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -985,13 +1253,15 @@
 fi
 
 
-# Include the file that defined BORP_PERL_RUN.
+# Include the file that defines BORP_PERL_RUN.
+
+
 
 
 # Extract the first word of "perl", so it can be a program name with args.
 set dummy perl; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:995: checking for $ac_word" >&5
+echo "configure:1265: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_path_PERL'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1024,11 +1294,12 @@
   echo "$ac_t""no" 1>&6
 fi
 
-if test "x$PERL" != "xNOT_FOUND"; then
-  PERL="$PERL -w"
+if test "x$PERL" = "xNOT_FOUND"; then
+  { echo "configure: error: *** Perl not found.  Please install Perl.  See INSTALL how to do this." 1>&2; exit 1; }
+else
   
   echo $ac_n "checking if '$PERL' will run Perl scripts""... $ac_c" 1>&6
-echo "configure:1032: checking if '$PERL' will run Perl scripts" >&5
+echo "configure:1303: checking if '$PERL' will run Perl scripts" >&5
   rm -f conftest.BZ
   cat > conftest.BZ <<EOF
 #!$PERL
@@ -1045,12 +1316,112 @@
   fi
   rm -f conftest.BZ
 
-else
-  PERLHEAD=PerlHead2
 fi
 PERL_HEAD="../config/$PERL_HEAD"
 
 
+# Check for necessary Perl modules.
+
+  echo $ac_n "checking if Perl module Digest::MD5 version 2.00 is installed""... $ac_c" 1>&6
+echo "configure:1327: checking if Perl module Digest::MD5 version 2.00 is installed" >&5
+  if $PERL ./config/check_for_perl_mod Digest::MD5 2.00; then
+    borp_cv_perl_digest_md5=yes
+    
+  else
+    borp_cv_perl_digest_md5=no
+    
+  fi
+  echo "$ac_t""$borp_cv_perl_digest_md5" 1>&6
+
+if test "$borp_cv_perl_digest_md5" = no; then
+  MAKE_DIGEST_MD5=make_digest_md5
+  TEST_DIGEST_MD5=test_digest_md5
+  INSTALL_DIGEST_MD5=install_digest_md5
+  CLEAN_DIGEST_MD5=clean_digest_md5
+  DISTCLEAN_DIGEST_MD5=distclean_digest_md5
+fi
+
+
+
+
+
+
+
+  echo $ac_n "checking if Perl module Math::Interpolate version 1.00 is installed""... $ac_c" 1>&6
+echo "configure:1352: checking if Perl module Math::Interpolate version 1.00 is installed" >&5
+  if $PERL ./config/check_for_perl_mod Math::Interpolate 1.00; then
+    borp_cv_perl_math_interpolate=yes
+    
+  else
+    borp_cv_perl_math_interpolate=no
+    
+  fi
+  echo "$ac_t""$borp_cv_perl_math_interpolate" 1>&6
+
+if test "$borp_cv_perl_math_interpolate" = no; then
+  MAKE_MATH_INTERPOLATE=make_math_interpolate
+  TEST_MATH_INTERPOLATE=test_math_interpolate
+  INSTALL_MATH_INTERPOLATE=install_math_interpolate
+  CLEAN_MATH_INTERPOLATE=clean_math_interpolate
+  DISTCLEAN_MATH_INTERPOLATE=distclean_math_interpolate
+fi
+
+
+
+
+
+
+
+  echo $ac_n "checking if Perl module RRDs version 0.99029 is installed""... $ac_c" 1>&6
+echo "configure:1377: checking if Perl module RRDs version 0.99029 is installed" >&5
+  if $PERL ./config/check_for_perl_mod RRDs 0.99029; then
+    borp_cv_perl_rdds=yes
+    
+  else
+    borp_cv_perl_rdds=no
+    
+  fi
+  echo "$ac_t""$borp_cv_perl_rdds" 1>&6
+
+if test "$borp_cv_perl_rdds" = no; then
+  MAKE_RRDTOOL=make_rrdtool
+  TEST_RRDTOOL=test_rrdtool
+  INSTALL_RRDTOOL=install_rrdtool
+  CLEAN_RRDTOOL=clean_rrdtool
+  DISTCLEAN_RRDTOOL=distclean_rrdtool
+fi
+
+
+
+
+
+
+
+  echo $ac_n "checking if Perl module Storable version 0.603 is installed""... $ac_c" 1>&6
+echo "configure:1402: checking if Perl module Storable version 0.603 is installed" >&5
+  if $PERL ./config/check_for_perl_mod Storable 0.603; then
+    borp_cv_perl_storable=yes
+    
+  else
+    borp_cv_perl_storable=no
+    
+  fi
+  echo "$ac_t""$borp_cv_perl_storable" 1>&6
+
+if test "$borp_cv_perl_storable" = no; then
+  MAKE_STORABLE=make_storable
+  TEST_STORABLE=test_storable
+  INSTALL_STORABLE=install_storable
+  CLEAN_STORABLE=clean_storable
+  DISTCLEAN_STORABLE=distclean_storable
+fi
+
+
+
+
+
+
+
 # Define the INSTALL and MKDIR variables to point to the scripts in
 # the config directory.
 INSTALL="../config/install-sh -c"
@@ -1176,12 +1547,13 @@
 
 trap 'rm -fr `echo "config/PerlHead1
 	  config/PerlHead2
-	  src/percol_running.pl
-	  src/restart_percol.sh
-	  src/start_percol.sh
-	  src/stop_percol.sh
+	  packages/Makefile
+	  src/orcallator_running.pl
+	  src/restart_orcallator.sh
+	  src/start_orcallator.sh
+	  src/stop_orcallator.sh
 	  src/Makefile
-	  lib/percollator.cfg
+	  lib/orcallator.cfg
 	  lib/Makefile
 	  docs/Makefile
 	  Makefile" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
@@ -1231,11 +1603,18 @@
 s%@build_cpu@%$build_cpu%g
 s%@build_vendor@%$build_vendor%g
 s%@build_os@%$build_os%g
+s%@CONFIGURE_COMMAND_LINE@%$CONFIGURE_COMMAND_LINE%g
+s%@DIGEST_MD5_DIR@%$DIGEST_MD5_DIR%g
+s%@MATH_INTERPOLATE_DIR@%$MATH_INTERPOLATE_DIR%g
+s%@RRDTOOL_DIR@%$RRDTOOL_DIR%g
+s%@STORABLE_DIR@%$STORABLE_DIR%g
 s%@RRD_DIR@%$RRD_DIR%g
 s%@HTML_DIR@%$HTML_DIR%g
-s%@PERCOLLATOR_DIR@%$PERCOLLATOR_DIR%g
+s%@ORCALLATOR_DIR@%$ORCALLATOR_DIR%g
 s%@WATCH_HTTPD@%$WATCH_HTTPD%g
 s%@WEB_LOG@%$WEB_LOG%g
+s%@CC@%$CC%g
+s%@SET_MAKE@%$SET_MAKE%g
 s%@AWK@%$AWK%g
 s%@CUT@%$CUT%g
 s%@EXPR@%$EXPR%g
@@ -1243,6 +1622,26 @@
 s%@UNAME@%$UNAME%g
 s%@PERL@%$PERL%g
 s%@PERL_HEAD@%$PERL_HEAD%g
+s%@MAKE_DIGEST_MD5@%$MAKE_DIGEST_MD5%g
+s%@TEST_DIGEST_MD5@%$TEST_DIGEST_MD5%g
+s%@INSTALL_DIGEST_MD5@%$INSTALL_DIGEST_MD5%g
+s%@CLEAN_DIGEST_MD5@%$CLEAN_DIGEST_MD5%g
+s%@DISTCLEAN_DIGEST_MD5@%$DISTCLEAN_DIGEST_MD5%g
+s%@MAKE_MATH_INTERPOLATE@%$MAKE_MATH_INTERPOLATE%g
+s%@TEST_MATH_INTERPOLATE@%$TEST_MATH_INTERPOLATE%g
+s%@INSTALL_MATH_INTERPOLATE@%$INSTALL_MATH_INTERPOLATE%g
+s%@CLEAN_MATH_INTERPOLATE@%$CLEAN_MATH_INTERPOLATE%g
+s%@DISTCLEAN_MATH_INTERPOLATE@%$DISTCLEAN_MATH_INTERPOLATE%g
+s%@MAKE_RRDTOOL@%$MAKE_RRDTOOL%g
+s%@TEST_RRDTOOL@%$TEST_RRDTOOL%g
+s%@INSTALL_RRDTOOL@%$INSTALL_RRDTOOL%g
+s%@CLEAN_RRDTOOL@%$CLEAN_RRDTOOL%g
+s%@DISTCLEAN_RRDTOOL@%$DISTCLEAN_RRDTOOL%g
+s%@MAKE_STORABLE@%$MAKE_STORABLE%g
+s%@TEST_STORABLE@%$TEST_STORABLE%g
+s%@INSTALL_STORABLE@%$INSTALL_STORABLE%g
+s%@CLEAN_STORABLE@%$CLEAN_STORABLE%g
+s%@DISTCLEAN_STORABLE@%$DISTCLEAN_STORABLE%g
 s%@INSTALL@%$INSTALL%g
 s%@MKDIR@%$MKDIR%g
 
@@ -1288,12 +1687,13 @@
 
 CONFIG_FILES=\${CONFIG_FILES-"config/PerlHead1
 	  config/PerlHead2
-	  src/percol_running.pl
-	  src/restart_percol.sh
-	  src/start_percol.sh
-	  src/stop_percol.sh
+	  packages/Makefile
+	  src/orcallator_running.pl
+	  src/restart_orcallator.sh
+	  src/start_orcallator.sh
+	  src/stop_orcallator.sh
 	  src/Makefile
-	  lib/percollator.cfg
+	  lib/orcallator.cfg
 	  lib/Makefile
 	  docs/Makefile
 	  Makefile"}
@@ -1363,6 +1763,15 @@
 test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
 
 
+if test "$borp_cv_perl_rdds" != "yes"; then
+  echo ""
+  echo "Running configure in packages/$RRDTOOL_DIR to create RRDtool and RRDs.pm."
+  echo ""
+  echo "(cd packages/$RRDTOOL_DIR; ./configure $CONFIGURE_COMMAND_LINE --cache-file=../../config.cache)"
+  echo ""
+  (cd packages/$RRDTOOL_DIR; ./configure $CONFIGURE_COMMAND_LINE --cache-file=../../config.cache)
+fi
+
 if test -z "$WEB_LOG"; then
   echo "configure: warning: *** Unless you use a --with-*-log option you will not gather WWW log data." 1>&2
 fi

Modified: trunk/orca/Makefile.in
==============================================================================
--- trunk/orca/Makefile.in	(original)
+++ trunk/orca/Makefile.in	Sat Jul 13 18:45:51 2002
@@ -1,32 +1,50 @@
-SUBDIRS 	= lib src docs
+ at SET_MAKE@
+
+SUBDIRS 	= packages lib src docs
 PREFIX		= @prefix@
-PERCOLLATOR_DIR	= @PERCOLLATOR_DIR@
+ORCALLATOR_DIR	= @ORCALLATOR_DIR@
 RRD_DIR		= @RRD_DIR@
+CFLAGS		= @CFLAGS@
 
-all:	configure
-	@for dir in $(SUBDIRS); do			\
-		echo "cd $$dir; $(MAKE)";		\
-		(cd $$dir; $(MAKE));			\
+all:	configure Makefile
+	@for dir in $(SUBDIRS); do				\
+		echo "cd $$dir && $(MAKE) CFLAGS=$(CFLAGS)";	\
+		(cd $$dir && $(MAKE) CFLAGS="$(CFLAGS)");	\
 	done
 
+test:
+	(cd packages; $(MAKE) CFLAGS="$(CFLAGS)" test)
+
+migrate:
+	(cd src; $(MAKE) migrate)
+
 install:
-	./config/mkinstalldirs $(PERCOLLATOR_DIR)
+	./config/mkinstalldirs $(ORCALLATOR_DIR)
 	./config/mkinstalldirs $(RRD_DIR)
 	@for dir in $(SUBDIRS); do			\
-		echo "cd $$dir; $(MAKE) install";	\
-		(cd $$dir; $(MAKE) install);		\
+		echo "cd $$dir && $(MAKE) install";	\
+		(cd $$dir && $(MAKE) install);		\
 	done
 
+modules:
+	(cd packages && $(MAKE) CFLAGS="$(CFLAGS)" modules)
+
+test_modules:
+	(cd packages && $(MAKE) CFLAGS="$(CFLAGS)" test_modules)
+
+install_modules:
+	(cd packages && $(MAKE) CFLAGS="$(CFLAGS)" install_modules)
+
 clean:
 	@for dir in $(SUBDIRS); do			\
-		echo "cd $$dir; $(MAKE) clean";		\
-		(cd $$dir; $(MAKE) clean);		\
+		echo "cd $$dir && $(MAKE) clean";	\
+		(cd $$dir && $(MAKE) clean);		\
 	done
 
 distclean:
 	@for dir in $(SUBDIRS); do			\
-		echo "cd $$dir; $(MAKE) distclean";	\
-		(cd $$dir; $(MAKE) distclean);		\
+		echo "cd $$dir && $(MAKE) distclean";	\
+		(cd $$dir && $(MAKE) distclean);	\
 	done
 	$(RM) config/PerlHead1 config/PerlHead2
 	$(RM) config.cache config.log config.status Makefile
@@ -34,3 +52,6 @@
 configure: configure.in
 	autoconf
 	./config.status
+
+Makefile: Makefile.in
+	./config.status

Modified: trunk/orca/TODO
==============================================================================
--- trunk/orca/TODO	(original)
+++ trunk/orca/TODO	Sat Jul 13 18:45:51 2002
@@ -2,7 +2,7 @@
 	Come up with a better error scheme than using warn() for some
 		errors and the email warn for others.
 	Do something better if the number of columns changes in a single
-		percollator file.
+		orcallator file.
 	Have a scheme were at any point of time a data file may add or
 		change the number of columns of data and column names.
 	Lock file.
@@ -13,7 +13,7 @@
 	Make plots from multiple files sets: delete source files_key and put
 		it into data.
 	Update HTML files if a new file is found with a new group.
-	Update percollator.cfg.in for caching and proxy stuff.
+	Update orcallator.cfg.in for caching and proxy stuff.
 
-percollator.se:
+orcallator.se:
 	Better documentation.

Added: trunk/orca/config/check_for_perl_mod
==============================================================================
--- trunk/orca/config/check_for_perl_mod	(original)
+++ trunk/orca/config/check_for_perl_mod	Sat Jul 13 18:45:51 2002
@@ -0,0 +1,31 @@
+use strict;
+
+my $verbose = 0;
+
+# Subroutine to check for installed modules.
+sub check_version
+{
+  my ($pkg, $wanted) = @_;
+
+  local($|) = 1;
+  print "Checking for $pkg..." if $verbose;
+
+  eval { my $p; ($p = $pkg . ".pm") =~ s#::#/#g; require $p; };
+
+  no strict 'refs';
+
+  my $vstr = ${"${pkg}::VERSION"} ? "found v" . ${"${pkg}::VERSION"}
+                                 : "not found";
+  my $vnum = ${"${pkg}::VERSION"} || 0;
+
+  if ($verbose) {
+    print $vnum >= $wanted ? "ok\n" : " " . $vstr . "\n";
+  }
+
+  $vnum >= $wanted;
+}
+
+die "usage: $0 package_name version" unless @ARGV == 2;
+
+# Return 0 if the necessary version was found, 1 otherwise.
+exit(!check_version(@ARGV));

Modified: trunk/orca/config/acinclude.m4
==============================================================================
--- trunk/orca/config/acinclude.m4	(original)
+++ trunk/orca/config/acinclude.m4	Sat Jul 13 18:45:51 2002
@@ -1,3 +1,21 @@
+dnl Check if the requested modules are install in this perl module.
+dnl Do not cache this result, since the user may easy install the
+dnl modules and rerun configure.  We do not want to remember if
+dnl the module is not installed.
+dnl BORP_PERL_MODULE(DEFINE, PATH_TO_PERL, MODULE_NAME, MODULE_VERSION,
+dnl    [ACTION_IF_FOUND, [ACTION_IF_NOT_FOUND]]
+AC_DEFUN(BORP_PERL_MODULE, [
+  AC_MSG_CHECKING([if Perl module $3 version $4 is installed])
+  if $2 ./config/check_for_perl_mod $3 $4; then
+    $1=yes
+    ifelse([$5], , , [$5])
+  else
+    $1=no
+    ifelse([$6], , , [$6])
+  fi
+  AC_MSG_RESULT([$]$1)
+])
+
 dnl Check if the whole path to Perl can be placed on the #! line
 dnl of a shell script.  Some systems have length restrictions
 dnl so some paths to programs may be too long.

Modified: trunk/orca/config/PerlHead1.in
==============================================================================
--- trunk/orca/config/PerlHead1.in	(original)
+++ trunk/orca/config/PerlHead1.in	Sat Jul 13 18:45:51 2002
@@ -1,4 +1,4 @@
-#!@PERL@ # -*- perl -*-
+#!@PERL@ -w # -*- perl -*-
 
 require 5.005;
 

Modified: trunk/orca/config/PerlHead2.in
==============================================================================
--- trunk/orca/config/PerlHead2.in	(original)
+++ trunk/orca/config/PerlHead2.in	Sat Jul 13 18:45:51 2002
@@ -1,8 +1,8 @@
 #!/bin/sh -- # -*- perl -*- -w
 
 # Catch for sh/csh on systems without #! ability.
-eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}'
-& eval 'exec perl -S $0 $argv:q'
+eval '(exit $?0)' && eval 'exec perl -w -S $0 ${1+"$@"}'
+& eval 'exec perl -w -S $0 $argv:q'
     if 0;
 
 require 5.005;

Modified: trunk/orca/configure.in
==============================================================================
--- trunk/orca/configure.in	(original)
+++ trunk/orca/configure.in	Sat Jul 13 18:45:51 2002
@@ -5,13 +5,29 @@
 AC_CONFIG_AUX_DIR(config)
 AC_CANONICAL_SYSTEM
 
+# Remember the command line arguments to configure for use when
+# configure is run again.
+CONFIGURE_COMMAND_LINE=${1+"$@"}
+AC_SUBST(CONFIGURE_COMMAND_LINE)
+
+# Define the directories containing packages that Orca makes use of here.
+# The path packages gets added where necessary.
+DIGEST_MD5_DIR=Digest-MD5-2.07
+MATH_INTERPOLATE_DIR=Math-Interpolate-1.02
+RRDTOOL_DIR=rrdtool-0.99.29.1
+STORABLE_DIR=Storable-0.6 at 3
+AC_SUBST(DIGEST_MD5_DIR)
+AC_SUBST(MATH_INTERPOLATE_DIR)
+AC_SUBST(RRDTOOL_DIR)
+AC_SUBST(STORABLE_DIR)
+
 # Minimum Autoconf version required.
 AC_PREREQ(2.13)
 
-# Define the directories where the source percollator and RRD data files
+# Define the directories where the source orcallator and RRD data files
 # will be installed.
 AC_ARG_WITH(rrd-dir,
-  [   --with-rrd-dir=DIR     directory were the RRD data files are stored],
+  [   --with-rrd-dir=DIR         directory were the RRD data files are stored],
   [
     case "$withval" in
       "" | y | ye | yes | n | no)
@@ -31,7 +47,7 @@
 AC_SUBST(RRD_DIR)
 
 AC_ARG_WITH(html-dir,
-  [   --with-html-dir=DIR    location of the root output HTML directory],
+  [   --with-html-dir=DIR        location of the root output HTML directory],
   [
     case "$withval" in
       "" | y | ye | yes | n | no)
@@ -45,30 +61,30 @@
 )
 AC_SUBST(HTML_DIR)
 
-AC_ARG_WITH(perc-dir,
-  [   --with-perc-dir=DIR    directory were percollator output is stored],
+AC_ARG_WITH(orcallator-dir,
+  [   --with-orcallator-dir=DIR  directory were orcallator output is stored],
   [
     case "$withval" in
       "" | y | ye | yes | n | no)
-         AC_MSG_ERROR([*** You must supply an argument to the --with-perc-dir option.])
+         AC_MSG_ERROR([*** You must supply an argument to the --with-orcallator-dir option.])
          ;;
-      *) PERCOLLATOR_DIR="$withval"
+      *) ORCALLATOR_DIR="$withval"
          ;;
     esac
   ],
-  : ${PERCOLLATOR_DIR=$localstatedir/orca/percollator}
+  : ${ORCALLATOR_DIR=$localstatedir/orca/orcallator}
 )
-PERCOLLATOR_DIR=`(
+ORCALLATOR_DIR=`(
     test "x$prefix" = xNONE && prefix=$ac_default_prefix
     test "x$exec_prefix" = xNONE && exec_prefix=${prefix}
-    eval echo "$PERCOLLATOR_DIR"
+    eval echo "$ORCALLATOR_DIR"
 )`
-AC_SUBST(PERCOLLATOR_DIR)
+AC_SUBST(ORCALLATOR_DIR)
 
 WATCH_HTTPD=
 NCSA_LOG=
 AC_ARG_WITH(ncsa-log,
-  [   --with-ncsa-log=FILE   location of the NCSA style web server access log],
+  [   --with-ncsa-log=FILE       location of the NCSA style web server access log],
   [
     case "$withval" in
       "" | y | ye | yes | n | no)
@@ -84,7 +100,7 @@
 
 PROXY_LOG=
 AC_ARG_WITH(proxy-log,
-  [   --with-proxy-log=FILE  location of the proxy NCSA style web server access log],
+  [   --with-proxy-log=FILE      location of the proxy NCSA web server access log],
   [
     if test "$NCSA_LOG"; then
       AC_MSG_ERROR([*** You cannot use both --with-ncsa-log and --with-proxy-log.])
@@ -102,7 +118,7 @@
 )
 
 AC_ARG_WITH(squid-log,
-  [   --with-squid-log=FILE  location of the Squid file],
+  [   --with-squid-log=FILE      location of the Squid file log file],
   [
     if test "$NCSA_LOG"; then
       AC_MSG_ERROR([*** You cannot use both --with-ncsa-log and --with-squid-log.])
@@ -124,6 +140,11 @@
 AC_SUBST(WATCH_HTTPD)
 AC_SUBST(WEB_LOG)
 
+# To get a default CFLAGS for this build, check for a C compiler.  This
+# is also needed to be ready to compile any Perl modules.
+AC_PROG_CC
+
+AC_PROG_MAKE_SET
 AC_ARG_PROGRAM
 AC_PATH_PROGS(AWK,mawk gawk nawk awk)
 AC_PATH_PROG(CUT, cut, cut)
@@ -131,18 +152,75 @@
 AC_PATH_PROG(SE, se,,/opt/RICHPse/bin:$PATH)
 AC_PATH_PROG(UNAME, uname, uname)
 
-# Include the file that defined BORP_PERL_RUN.
+# Include the file that defines BORP_PERL_RUN.
 sinclude(config/acinclude.m4)
 AC_PATH_PROG(PERL, perl, NOT_FOUND)
-if test "x$PERL" != "xNOT_FOUND"; then
-  PERL="$PERL -w"
-  BORP_PERL_RUN($PERL, PERL_HEAD=PerlHead1, PERL_HEAD=PerlHead2)
+if test "x$PERL" = "xNOT_FOUND"; then
+  AC_MSG_ERROR([*** Perl not found.  Please install Perl.  See INSTALL how to do this.])
 else
-  PERLHEAD=PerlHead2
+  BORP_PERL_RUN($PERL, PERL_HEAD=PerlHead1, PERL_HEAD=PerlHead2)
 fi
 PERL_HEAD="../config/$PERL_HEAD"
 AC_SUBST(PERL_HEAD)
 
+# Check for necessary Perl modules.
+BORP_PERL_MODULE(borp_cv_perl_digest_md5, $PERL, Digest::MD5, 2.00)
+if test "$borp_cv_perl_digest_md5" = no; then
+  MAKE_DIGEST_MD5=make_digest_md5
+  TEST_DIGEST_MD5=test_digest_md5
+  INSTALL_DIGEST_MD5=install_digest_md5
+  CLEAN_DIGEST_MD5=clean_digest_md5
+  DISTCLEAN_DIGEST_MD5=distclean_digest_md5
+fi
+AC_SUBST(MAKE_DIGEST_MD5)
+AC_SUBST(TEST_DIGEST_MD5)
+AC_SUBST(INSTALL_DIGEST_MD5)
+AC_SUBST(CLEAN_DIGEST_MD5)
+AC_SUBST(DISTCLEAN_DIGEST_MD5)
+
+BORP_PERL_MODULE(borp_cv_perl_math_interpolate, $PERL, Math::Interpolate, 1.00)
+if test "$borp_cv_perl_math_interpolate" = no; then
+  MAKE_MATH_INTERPOLATE=make_math_interpolate
+  TEST_MATH_INTERPOLATE=test_math_interpolate
+  INSTALL_MATH_INTERPOLATE=install_math_interpolate
+  CLEAN_MATH_INTERPOLATE=clean_math_interpolate
+  DISTCLEAN_MATH_INTERPOLATE=distclean_math_interpolate
+fi
+AC_SUBST(MAKE_MATH_INTERPOLATE)
+AC_SUBST(TEST_MATH_INTERPOLATE)
+AC_SUBST(INSTALL_MATH_INTERPOLATE)
+AC_SUBST(CLEAN_MATH_INTERPOLATE)
+AC_SUBST(DISTCLEAN_MATH_INTERPOLATE)
+
+BORP_PERL_MODULE(borp_cv_perl_rdds, $PERL, RRDs, 0.99029)
+if test "$borp_cv_perl_rdds" = no; then
+  MAKE_RRDTOOL=make_rrdtool
+  TEST_RRDTOOL=test_rrdtool
+  INSTALL_RRDTOOL=install_rrdtool
+  CLEAN_RRDTOOL=clean_rrdtool
+  DISTCLEAN_RRDTOOL=distclean_rrdtool
+fi
+AC_SUBST(MAKE_RRDTOOL)
+AC_SUBST(TEST_RRDTOOL)
+AC_SUBST(INSTALL_RRDTOOL)
+AC_SUBST(CLEAN_RRDTOOL)
+AC_SUBST(DISTCLEAN_RRDTOOL)
+
+BORP_PERL_MODULE(borp_cv_perl_storable, $PERL, Storable, 0.603)
+if test "$borp_cv_perl_storable" = no; then
+  MAKE_STORABLE=make_storable
+  TEST_STORABLE=test_storable
+  INSTALL_STORABLE=install_storable
+  CLEAN_STORABLE=clean_storable
+  DISTCLEAN_STORABLE=distclean_storable
+fi
+AC_SUBST(MAKE_STORABLE)
+AC_SUBST(TEST_STORABLE)
+AC_SUBST(INSTALL_STORABLE)
+AC_SUBST(CLEAN_STORABLE)
+AC_SUBST(DISTCLEAN_STORABLE)
+
+
 # Define the INSTALL and MKDIR variables to point to the scripts in
 # the config directory.
 INSTALL="../config/install-sh -c"
@@ -156,16 +234,26 @@
 #--------------------------------------------------------------------
 AC_OUTPUT(config/PerlHead1
 	  config/PerlHead2
-	  src/percol_running.pl
-	  src/restart_percol.sh
-	  src/start_percol.sh
-	  src/stop_percol.sh
+	  packages/Makefile
+	  src/orcallator_running.pl
+	  src/restart_orcallator.sh
+	  src/start_orcallator.sh
+	  src/stop_orcallator.sh
 	  src/Makefile
-	  lib/percollator.cfg
+	  lib/orcallator.cfg
 	  lib/Makefile
 	  docs/Makefile
 	  Makefile)
 
+if test "$borp_cv_perl_rdds" != "yes"; then
+  echo ""
+  echo "Running configure in packages/$RRDTOOL_DIR to create RRDtool and RRDs.pm."
+  echo ""
+  echo "(cd packages/$RRDTOOL_DIR; ./configure $CONFIGURE_COMMAND_LINE --cache-file=../../config.cache)"
+  echo ""
+  (cd packages/$RRDTOOL_DIR; ./configure $CONFIGURE_COMMAND_LINE --cache-file=../../config.cache)
+fi
+
 if test -z "$WEB_LOG"; then
   AC_MSG_WARN([*** Unless you use a --with-*-log option you will not gather WWW log data.])
 fi

Modified: trunk/orca/lib/Makefile.in
==============================================================================
--- trunk/orca/lib/Makefile.in	(original)
+++ trunk/orca/lib/Makefile.in	Sat Jul 13 18:45:51 2002
@@ -1,13 +1,16 @@
+ at SET_MAKE@
+
 prefix		= @prefix@
 exec_prefix	= @exec_prefix@
 libdir		= @libdir@
 MKDIR		= @MKDIR@
 INSTALL		= @INSTALL@
 
-all:	percollator.cfg orca.gif.hex rrdtool.gif.hex
+all:	orcallator.cfg orca.gif.hex rrdtool.gif.hex
 
-percollator.cfg: percollator.cfg.in
-	cd ..; ./config.status
+orcallator.cfg: orcallator.cfg.in
+	(cd ..; ./config.status)
+	$(MAKE)
 
 # Create a hex file representation of orca.gif that can be stored inside
 # orca.pl.
@@ -21,12 +24,12 @@
 
 install: all
 	$(MKDIR) $(libdir)
-	-cp -p $(libdir)/percollator.cfg $(libdir)/percollator.cfg.`date +%Y-%m-%d-%H:%M:%S`
-	$(INSTALL) -m 0644 percollator.cfg $(libdir)
-	$(INSTALL) -m 0644 percollator.se $(libdir)
+	-cp -p $(libdir)/orcallator.cfg $(libdir)/orcallator.cfg.`date +%Y-%m-%d-%H:%M:%S`
+	$(INSTALL) -m 0644 orcallator.cfg $(libdir)
+	$(INSTALL) -m 0644 orcallator.se $(libdir)
 
 clean:
-	$(RM) percollator.cfg
+	$(RM) orcallator.cfg
 
 distclean: clean
 	$(RM) Makefile

Modified: trunk/orca/lib/orcallator.cfg.in
==============================================================================
--- trunk/orca/lib/orcallator.cfg.in	(original)
+++ trunk/orca/lib/orcallator.cfg.in	Sat Jul 13 18:45:51 2002
@@ -1,13 +1,13 @@
-# Orca configuration file for Percollator files.
+# Orca configuration file for orcallator files.
 
-base_dir		@RRD_DIR@/percollator
+base_dir		@RRD_DIR@/orcallator
 state_file		orca.state
 html_dir		@HTML_DIR@
 expire_gifs		1
 
 # Find files at the following times:
-#    0:10 to pick up new percollator files for the new day.
-#    1:00 to pick up late comer percollator files for the new day.
+#    0:10 to pick up new orcallator files for the new day.
+#    1:00 to pick up late comer orcallator files for the new day.
 #    6:00 to pick up new files before the working day.
 #   12:00 to pick up new files during the working day.
 #   19:00 to pick up new files after the working day.
@@ -22,8 +22,8 @@
 
 # This defines where the find the source data files and the format of those
 # files.
-files percol {
-find_files		@PERCOLLATOR_DIR@/(.*)/percol-\d{4}-\d{2}-\d{2}
+files orcallator {
+find_files		@ORCALLATOR_DIR@/(.*)/(?:(?:orcallator)|(?:percol))-\d{4}-\d{2}-\d{2}
 column_description	first_line
 date_source		column_name timestamp
 date_format		%s
@@ -60,7 +60,7 @@
 
 plot {
 title			%g Average # Processes in Run Queue
-source			percol
+source			orcallator
 data			1runq
 data			5runq
 data			15runq
@@ -74,7 +74,7 @@
 
 plot {
 title			%g System Load
-source			percol
+source			orcallator
 data			1load
 data			5load
 data			15load
@@ -88,7 +88,7 @@
 
 plot {
 title			%g Number of System & Httpd Processes
-source			percol
+source			orcallator
 data			#proc
 data			#httpds
 line_type		line1
@@ -102,7 +102,7 @@
 
 plot {
 title			%g CPU Usage
-source			percol
+source			orcallator
 data			usr%
 data			sys%
 data			100 - usr% - sys%
@@ -122,7 +122,7 @@
 
 plot {
 title			%g Web Server Hit Rate
-source			percol
+source			orcallator
 data			httpop/s
 data			http/p5s
 legend			5 min average hits/s
@@ -134,7 +134,7 @@
 
 plot {
 title			%g Web Server File Size
-source			percol
+source			orcallator
 data			%to1KB
 data			%to10KB
 data			%to100KB
@@ -160,7 +160,7 @@
 
 plot {
 title			%g Web Server Data Transfer Rate
-source			percol
+source			orcallator
 data			httpb/s
 legend			Bytes/s
 y_legend		Bytes/s
@@ -169,7 +169,7 @@
 
 plot {
 title			%g Web Server HTTP Error Rate
-source			percol
+source			orcallator
 data			htErr/s
 legend			HTTP Errors/s
 y_legend		Errors/s
@@ -178,7 +178,7 @@
 
 plot {
 title			%g Bits Per Second: be0
-source			percol
+source			orcallator
 data			1024 * 8 * be0InKB/s
 data			1024 * 8 * be0OuKB/s
 line_type		area
@@ -191,8 +191,22 @@
 }
 
 plot {
+title			%g Bits Per Second: elxl0
+source			orcallator
+data			1024 * 8 * elxl0InKB/s
+data			1024 * 8 * elxl0OuKB/s
+line_type		area
+legend			Input
+legend			Output
+y_legend		bits/s
+data_min		0
+data_max		100000000
+optional
+}
+
+plot {
 title			%g Bits Per Second: hme0
-source			percol
+source			orcallator
 data			1024 * 8 * hme0InKB/s
 data			1024 * 8 * hme0OuKB/s
 line_type		area
@@ -206,7 +220,7 @@
 
 plot {
 title			%g Bits Per Second: hme1
-source			percol
+source			orcallator
 data			1024 * 8 * hme1InKB/s
 data			1024 * 8 * hme1OuKB/s
 line_type		area
@@ -220,7 +234,7 @@
 
 plot {
 title			%g Bits Per Second: hme2
-source			percol
+source			orcallator
 data			1024 * 8 * hme2InKB/s
 data			1024 * 8 * hme2OuKB/s
 line_type		area
@@ -234,7 +248,7 @@
 
 plot {
 title			%g Bits Per Second: le0
-source			percol
+source			orcallator
 data			1024 * 8 * le0InKB/s
 data			1024 * 8 * le0OuKB/s
 line_type		area
@@ -248,7 +262,7 @@
 
 plot {
 title			%g Bits Per Second: le1
-source			percol
+source			orcallator
 data			1024 * 8 * le1InKB/s
 data			1024 * 8 * le1OuKB/s
 line_type		area
@@ -262,7 +276,7 @@
 
 plot {
 title			%g Packets Per Second: $1
-source			percol
+source			orcallator
 data			(.*\d)Ipkt/s
 data			$1Opkt/s
 line_type		area
@@ -276,7 +290,7 @@
 
 plot {
 title			%g Errors Per Second: $1
-source			percol
+source			orcallator
 data			(.*\d)IErr/s
 data			$1OErr/s
 line_type		area
@@ -289,7 +303,7 @@
 
 plot {
 title			%g Ethernet Nocanput Rate
-source			percol
+source			orcallator
 data			(.*\d)NoCP/s
 legend			$1
 y_legend		Nocanput/s
@@ -299,7 +313,7 @@
 
 plot {
 title			%g Ethernet Deferred Packet Rate
-source			percol
+source			orcallator
 data			(.*\d)Defr/s
 legend			$1
 y_legend		Defers/s
@@ -309,7 +323,7 @@
 
 plot {
 title			%g Ethernet Collisions
-source			percol
+source			orcallator
 data			(.*\d)Coll%
 legend			$1
 y_legend		Percent
@@ -320,7 +334,7 @@
 
 plot {
 title			%g TCP Bits Per Second
-source			percol
+source			orcallator
 data			1024 * 8 * tcp_InKB/s
 data			1024 * 8 * tcp_OuKB/s
 line_type		area
@@ -333,7 +347,7 @@
 
 plot {
 title			%g TCP Segments Per Second
-source			percol
+source			orcallator
 data			tcp_Iseg/s
 data			tcp_Oseg/s
 line_type		area
@@ -346,7 +360,7 @@
 
 plot {
 title			%g TCP Retransmission & Duplicate Received Percentage
-source			percol
+source			orcallator
 data			tcp_Ret%
 data			tcp_Dup%
 legend			Retransmission
@@ -358,7 +372,7 @@
 
 plot {
 title			%g TCP New Connection Rate
-source			percol
+source			orcallator
 data			tcp_Icn/s
 data			tcp_Ocn/s
 legend			Input - Passive
@@ -370,7 +384,7 @@
 
 plot {
 title			%g TCP Number Open Connections
-source			percol
+source			orcallator
 data			tcp_estb
 legend			# Open Connections
 y_legend		Number Open TCP Connections
@@ -380,7 +394,7 @@
 
 plot {
 title			%g TCP Reset Rate
-source			percol
+source			orcallator
 data			tcp_Rst/s
 legend			Number TCP Resets/s
 y_legend		Resets/s
@@ -389,7 +403,7 @@
 
 plot {
 title			%g TCP Attempt Fail Rate
-source			percol
+source			orcallator
 data			tcp_Atf/s
 legend			TCP Attempt Fails/s
 y_legend		Atf/s
@@ -398,7 +412,7 @@
 
 plot {
 title			%g TCP Listen Drop Rate
-source			percol
+source			orcallator
 data			tcp_Ldrp/s
 data			tcp_LdQ0/s
 data			tcp_HOdp/s
@@ -410,7 +424,7 @@
 
 plot {
 title			%g Sleeps on Mutex Rate
-source			percol
+source			orcallator
 data			smtx
 data			smtx/cpu
 legend			Sleeps on mutex
@@ -421,7 +435,7 @@
 
 plot {
 title			%g NFS Call Rate
-source			percol
+source			orcallator
 data			nfs_call/s
 legend			NFS Calls/s
 y_legend		Calls/s
@@ -430,7 +444,7 @@
 
 plot {
 title			%g NFS Timeouts & Bad Transmits Rate
-source			percol
+source			orcallator
 data			nfs_timo/s
 data			nfs_badx/s
 legend			NFS Timeouts
@@ -441,7 +455,7 @@
 
 plot {
 title			%g Peak & Mean Disk Busy
-source			percol
+source			orcallator
 data			disk_peak
 data			disk_mean
 line_type		line1
@@ -454,7 +468,7 @@
 
 plot {
 title			%g Cache Hit Percentages
-source			percol
+source			orcallator
 data			dnlc_hit%
 data			inod_hit%
 legend			DNLC
@@ -466,7 +480,7 @@
 
 plot {
 title			%g Cache Reference Rate
-source			percol
+source			orcallator
 data			dnlc_ref/s
 data			inod_ref/s
 line_type		line1
@@ -479,7 +493,7 @@
 
 plot {
 title			%g Inode Steal Rate
-source			percol
+source			orcallator
 data			inod_stl/s
 legend			Inode w/page steals/s
 y_legend		Steals/s
@@ -488,7 +502,7 @@
 
 plot {
 title			%g Available Swap Space
-source			percol
+source			orcallator
 data			1024 * swap_avail
 legend			Available Swap Space
 y_legend		Bytes
@@ -497,7 +511,7 @@
 
 plot {
 title			%g Page Residence Time
-source			percol
+source			orcallator
 data			page_rstim
 legend			Page Residence Time
 y_legend		Seconds
@@ -506,7 +520,7 @@
 
 plot {
 title			%g Page Usage
-source			percol
+source			orcallator
 data			pp_kernel
 data			free_pages
 data			pagestotl - pp_kernel - free_pages
@@ -529,7 +543,7 @@
 
 plot {
 title			%g Pages Locked & IO
-source			percol
+source			orcallator
 data			pageslock
 data			pagesio
 legend			Locked

Modified: trunk/orca/lib/orcallator.se
==============================================================================
--- trunk/orca/lib/orcallator.se	(original)
+++ trunk/orca/lib/orcallator.se	Sat Jul 13 18:45:52 2002
@@ -1,5 +1,5 @@
 //
-// Percollator.se, a log generating performance monitor.
+// Orcallator.se, a log generating performance monitor.
 //
 // This program logs many different system quantities to a log file
 // for later processing.
@@ -8,11 +8,14 @@
 //
 // Portions copied from percollator.se written by Adrian Cockroft.
 //
+// Version 1.7: Mar 25, 1999	Speed up by 20% and simplify count_proc.
+// Version 1.6: Feb 23, 1999	Print pvm.user_time and system_time correctly.
+// Version 1.5: Feb 23, 1999	Always write header to a new file.
 // Version 1.4: Feb 19, 1999	Handle missing HTTP/1.x in access log.
 // Version 1.3: Feb 18, 1999	On busy machines httpops5 will be enlarged.
 // Version 1.2: Feb 18, 1999	Output data on integral multiples of interval.
 // Version 1.1:	Feb 18, 1999	Integrate Squid log processing from SE 3.1.
-// Version 1.0:	Sep 9, 1998	Initial version.
+// Version 1.0:	Sep  9, 1998	Initial version.
 //
 
 // The default sampling interval in seconds.
@@ -34,9 +37,6 @@
 #define WATCH_PAGES
 #endif
 
-// The ioctl version of the psinfo structure is needed.
-#define PSINFO_IOCTL
-
 #include <stdio.se>
 #include <stdlib.se>
 #include <unistd.se>
@@ -55,7 +55,6 @@
 #include <tcp_rules.se>
 
 #ifdef WATCH_HTTPD
-#include <fcntl.se>
 #include <proc.se>
 #include <stat.se>
 #endif
@@ -200,7 +199,6 @@
    starts new logfile each day
 */
 ulong checkoutput(tm_t now) {
-  int    exists;
   string outdir = getenv("OUTDIR");
   string outname;
   ulong  ofile;
@@ -225,16 +223,13 @@
     }
     strftime(tm_buf, sizeof(tm_buf), "%Y-%m-%d", now);
     outname = sprintf("%s/percol-%s", outdir, tm_buf);
-    exists = access(outname, F_OK); /* see if file already exists */
     ofile = fopen(outname, "a"); /* open for append either way */
     if (ofile == 0) {
       perror("can't open output logfile");
       exit(1);
     }
-    /* if didn't exist write header */
-    if (exists == -1) {
-      print_columns(ofile, col_comment);
-    }
+    // Always write header.
+    print_columns(ofile, col_comment);
     then = now;
   }
   return ofile;
@@ -266,7 +261,7 @@
       fprintf(stderr, "%s can use the following environmental variables:\n", program_name);
       fprintf(stderr, "   setenv WEB_LOG     /ns-home/httpd-80/logs/access - location of web server log\n");
       fprintf(stderr, "   setenv GATEWAY     some.where.com - special address to monitor\n");
-      fprintf(stderr, "   setenv OUTDIR      /ns-home/docs/percollator/logs - default stdout\n");
+      fprintf(stderr, "   setenv OUTDIR      /ns-home/docs/orcallator/logs - default stdout\n");
       fprintf(stderr, "   setenv SEARCHURL   srch.cgi - match for search scripts, default is search.cgi\n");
       fprintf(stderr, "Defines:\n");
       fprintf(stderr, "   -DWATCH_HTTPD watch httpd access log\n");
@@ -511,8 +506,8 @@
 
   // In SE 3.0 user_time and system_time are int and in SE 3.1 they are
   // double, so cast everything to double using + 0.0.
-  put_output("usr%",   sprintf("%4.0f", pvm.user_time + 0.0));
-  put_output("sys%",   sprintf("%4.0f", pvm.system_time + 0.0));
+  put_output(" usr%",  sprintf("%5.1f", pvm.user_time + 0.0));
+  put_output(" sys%",  sprintf("%5.1f", pvm.system_time + 0.0));
   put_output(" 1load", sprintf("%6.2f", tmp_kstat_misc.avenrun_1min/256.0));
   put_output(" 5load", sprintf("%6.2f", tmp_kstat_misc.avenrun_5min/256.0));
   put_output("15load", sprintf("%6.2f", tmp_kstat_misc.avenrun_15min/256.0));
@@ -1003,83 +998,23 @@
 #endif
 }
 
-long count_proc(string name)
+int count_proc(string name)
 {
-  ulong      directory_pointer;
-  ulong      directory_entry;
-  dirent_t   directory_data;
-  int        process_number;
-  char       process_name[64];
-  long       num_proc;
-  int        process_fd;
-  int        err;
-#if MINOR_VERSION < 60
-  prpsinfo_t ps[1];	// format for ioctl
-#else
-  psinfo_t   ps[1];	// format changes when read used
-  ulong      pps = 0;
-
-  if (pps == 0) {
-    pps = malloc(sizeof(ps));
-  }
-#endif
-
-  directory_pointer = opendir("/proc");
-  if (directory_pointer == 0) {
-    fprintf(stderr, "%s: cannot open /proc for reading.\n", program_name);
-    return 0;
-  }
-
-  rewinddir(directory_pointer);
-
-  num_proc = 0;
+  int count;
+  prpsinfo_t p;
 
-  // Go through all processes.
-  directory_entry = readdir(directory_pointer);
-  for (; directory_entry != NULL; ) {
-    struct_fill(directory_data, directory_entry);
-    directory_entry = readdir(directory_pointer);
-
-    process_number = atoi(directory_data.d_name);
-#if MINOR_VERSION < 60
-    process_name = sprintf("/proc/%d", process_number);
-#else
-    process_name = sprintf("/proc/%d/psinfo", process_number);
-#endif
-    process_fd = open(process_name, O_RDONLY, 0);
-    if (process_fd == -1) {
-      continue;
-    }
-
-#if MINOR_VERSION < 60
-    // Read the process info and accumulate errors.
-    err += ioctl(process_fd, PIOCPSINFO, ps);
-    if (err != 0) {
-#else
-    err += read(process_fd, pps, sizeof(ps));
-    struct_fill(ps, pps);
-    if (err == 0) {
-#endif
-
-      // Process went away since the directory was opened.
-      close(process_fd);
-      continue;
-    }
-
-    close(process_fd);
-    if (ps[0].pr_fname =~ name) {
-      ++num_proc;
+  count = 0;
+  for (p=first_proc(); p.pr_pid != -1; p=next_proc()) {
+    if (p.pr_fname =~ name) {
+      count++;
     }
   }
-
-  closedir(directory_pointer);
-
-  return num_proc;
+  return count;
 }
 
 put_httpd()
 {
-  put_output("#httpds",   sprintf("%7ld",  count_proc("httpd")));
+  put_output("#httpds",   sprintf("%7d",   count_proc("httpd")));
   put_output("httpop/s",  sprintf("%8.2f", httpops/log_interval));
   put_output("http/p5s",  sprintf("%8.2f", httpops5));
   put_output("cndget/s",  sprintf("%8.2f", httpop_condgets/log_interval));

Modified: trunk/orca/lib/time_gets.cfg
==============================================================================
--- trunk/orca/lib/time_gets.cfg	(original)
+++ trunk/orca/lib/time_gets.cfg	Sat Jul 13 18:45:53 2002
@@ -6,8 +6,8 @@
 expire_gifs		1
 
 # Find files at the following times:
-#    0:10 to pick up new percollator files for the new day.
-#    1:00 to pick up late comer percollator files for the new day.
+#    0:10 to pick up new orcallator files for the new day.
+#    1:00 to pick up late comer orcallator files for the new day.
 #    6:00 to pick up new files before the working day.
 #   12:00 to pick up new files during the working day.
 #   19:00 to pick up new files after the working day.
@@ -57,484 +57,3 @@
   <font face="Arial,Helvetica">
     These plots brought to you by your local system administrator.
   </font>
-
-plot {
-title			%g Average # Processes in Run Queue
-source			percol
-data			1runq
-data			5runq
-data			15runq
-legend			1 Minute Average
-legend			5 Minute Average
-legend			15 Minute Average
-y_legend		# Processes
-data_min		0
-data_max		100
-}
-
-plot {
-title			%g System Load
-source			percol
-data			1load
-data			5load
-data			15load
-legend			1 Minute Average
-legend			5 Minute Average
-legend			15 Minute Average
-y_legend		Load
-data_min		0
-data_max		200
-}
-
-plot {
-title			%g Number of System & Httpd Processes
-source			percol
-data			#proc
-data			#httpds
-line_type		line1
-line_type		area
-legend			System total
-legend			Number httpds
-y_legend		# Processes
-data_min		0
-data_max		10000
-}
-
-plot {
-title			%g CPU Usage
-source			percol
-data			usr%
-data			sys%
-data			100 - usr% - sys%
-legend			User
-legend			System
-legend			Idle
-line_type		area
-line_type		stack
-line_type		stack
-y_legend		Percent
-data_min		0
-data_max		100
-plot_min		0
-plot_max		100
-rigid_min_max		1
-}
-
-plot {
-title			%g Web Server Hit Rate
-source			percol
-data			httpop/s
-data			http/p5s
-legend			5 minute average hits/s
-legend			Peak 5 second interval hits/s
-y_legend		Hits/second
-data_min		0
-optional
-}
-
-plot {
-title			%g Web Server File Size
-source			percol
-data			%to1KB
-data			%to10KB
-data			%to100KB
-data			%to1MB
-data			%over1MB
-line_type		area
-line_type		stack
-line_type		stack
-line_type		stack
-line_type		stack
-legend			0 - 1 KB
-legend			1 - 10 KB
-legend			10 - 100 KB
-legend			100 - 1000 KB
-legend			Greater than 1 MB
-y_legend		Percent
-data_min		0
-data_max		100
-plot_min		0
-plot_max		100
-rigid_min_max		1
-}
-
-plot {
-title			%g Web Server Data Transfer Rate
-source			percol
-data			httpb/s
-legend			Bytes/s
-y_legend		Bytes/s
-data_min		0
-}
-
-plot {
-title			%g Web Server HTTP Error Rate
-source			percol
-data			htErr/s
-legend			HTTP Errors/s
-y_legend		Errors/s
-data_min		0
-}
-
-plot {
-title			%g Bits Per Second: be0
-source			percol
-data			1024 * 8 * be0InKB/s
-data			1024 * 8 * be0OuKB/s
-line_type		area
-legend			Input
-legend			Output
-y_legend		bits/s
-data_min		0
-data_max		100000000
-optional
-}
-
-plot {
-title			%g Bits Per Second: hme0
-source			percol
-data			1024 * 8 * hme0InKB/s
-data			1024 * 8 * hme0OuKB/s
-line_type		area
-legend			Input
-legend			Output
-y_legend		bits/s
-data_min		0
-data_max		100000000
-optional
-}
-
-plot {
-title			%g Bits Per Second: hme1
-source			percol
-data			1024 * 8 * hme1InKB/s
-data			1024 * 8 * hme1OuKB/s
-line_type		area
-legend			Input
-legend			Output
-y_legend		bits/s
-data_min		0
-data_max		100000000
-optional
-}
-
-plot {
-title			%g Bits Per Second: hme2
-source			percol
-data			1024 * 8 * hme2InKB/s
-data			1024 * 8 * hme2OuKB/s
-line_type		area
-legend			Input
-legend			Output
-y_legend		bits/s
-data_min		0
-data_max		100000000
-optional
-}
-
-plot {
-title			%g Bits Per Second: le0
-source			percol
-data			1024 * 8 * le0InKB/s
-data			1024 * 8 * le0OuKB/s
-line_type		area
-legend			Input
-legend			Output
-y_legend		bits/s
-data_min		0
-data_max		10000000
-optional
-}
-
-plot {
-title			%g Bits Per Second: le1
-source			percol
-data			1024 * 8 * le1InKB/s
-data			1024 * 8 * le1OuKB/s
-line_type		area
-legend			Input
-legend			Output
-y_legend		bits/s
-data_min		0
-data_max		10000000
-optional
-}
-
-plot {
-title			%g Packets Per Second: $1
-source			percol
-data			(.*\d)Ipkt/s
-data			$1Opkt/s
-line_type		area
-legend			Input
-legend			Output
-y_legend		Packets/s
-data_min		0
-data_max		100000
-flush_regexps		1
-}
-
-plot {
-title			%g Errors Per Second: $1
-source			percol
-data			(.*\d)IErr/s
-data			$1OErr/s
-line_type		area
-legend			Input
-legend			Output
-y_legend		Errors/s
-data_min		0
-flush_regexps		1
-}
-
-plot {
-title			%g Ethernet Nocanput Rate
-source			percol
-data			(.*\d)NoCP/s
-legend			$1
-y_legend		Nocanput/s
-data_min		0
-flush_regexps		1
-}
-
-plot {
-title			%g Ethernet Deferred Packet Rate
-source			percol
-data			(.*\d)Defr/s
-legend			$1
-y_legend		Defers/s
-data_min		0
-flush_regexps		1
-}
-
-plot {
-title			%g Ethernet Collisions
-source			percol
-data			(.*\d)Coll%
-legend			$1
-y_legend		Percent
-data_min		0
-data_max		200
-flush_regexps		1
-}
-
-plot {
-title			%g TCP Bits Per Second
-source			percol
-data			1024 * 8 * tcp_InKB/s
-data			1024 * 8 * tcp_OuKB/s
-line_type		area
-legend			Input
-legend			Output
-y_legend		bits/s
-data_min		0
-data_max		1000000000
-}
-
-plot {
-title			%g TCP Segments Per Second
-source			percol
-data			tcp_Iseg/s
-data			tcp_Oseg/s
-line_type		area
-legend			Input
-legend			Output
-y_legend		Segments/s
-data_min		0
-data_max		20000
-}
-
-plot {
-title			%g TCP Retransmission & Duplicate Received Percentage
-source			percol
-data			tcp_Ret%
-data			tcp_Dup%
-legend			Retransmission
-legend			Duplicate Received
-y_legend		Percent
-data_min		0
-data_max		200
-}
-
-plot {
-title			%g TCP New Connection Rate
-source			percol
-data			tcp_Icn/s
-data			tcp_Ocn/s
-legend			Input - Passive
-legend			Output - Active
-y_legend		Connections/s
-data_min		0
-data_max		10000
-}
-
-plot {
-title			%g TCP Number Open Connections
-source			percol
-data			tcp_estb
-legend			Number Open TCP Connections
-y_legend		Number Open Connections
-data_min		0
-data_max		50000
-}
-
-plot {
-title			%g TCP Reset Rate
-source			percol
-data			tcp_Rst/s
-legend			Number TCP Resets/s
-y_legend		Resets/s
-data_min		0
-}
-
-plot {
-title			%g TCP Attempt Fail Rate
-source			percol
-data			tcp_Atf/s
-legend			TCP Attempt Fails/s
-y_legend		Atf/s
-data_min		0
-}
-
-plot {
-title			%g TCP Listen Drop Rate
-source			percol
-data			tcp_Ldrp/s
-data			tcp_LdQ0/s
-data			tcp_HOdp/s
-legend			TCP Listen Drops
-legend			TCP Listen Drop Q0
-legend			TCP Half Open Drops
-data_min		0
-}
-
-plot {
-title			%g Sleeps on Mutex Rate
-source			percol
-data			smtx
-data			smtx/cpu
-legend			Sleeps on mutex
-legend			Sleeps on mutex/cpu
-y_legend		Smtx/s
-data_min		0
-}
-
-plot {
-title			%g NFS Call Rate
-source			percol
-data			nfs_call/s
-legend			NFS Calls/s
-y_legend		Calls/s
-data_min		0
-}
-
-plot {
-title			%g NFS Timeouts & Bad Transmits Rate
-source			percol
-data			nfs_timo/s
-data			nfs_badx/s
-legend			NFS Timeouts
-legend			Bad Transmits
-y_legend		Count/s
-data_min		0
-}
-
-plot {
-title			%g Peak & Mean Disk Busy
-source			percol
-data			disk_peak
-data			disk_mean
-line_type		line1
-line_type		area
-legend			Peak Disk Busy
-legend			Mean Disk Busy
-y_legend		Disk Busy Measure
-data_min		0
-}
-
-plot {
-title			%g Cache Hit Percentages
-source			percol
-data			dnlc_hit%
-data			inod_hit%
-legend			DNLC
-legend			Inode Cache
-y_legend		Percent
-data_min		0
-data_max		100
-}
-
-plot {
-title			%g Cache Reference Rate
-source			percol
-data			dnlc_ref/s
-data			inod_ref/s
-line_type		line1
-line_type		area
-legend			DNLC
-legend			Inode Cache
-y_legend		References/s
-data_min		0
-}
-
-plot {
-title			%g Inode Steal Rate
-source			percol
-data			inod_stl/s
-legend			Inode w/page steal rate
-y_legend		Steals/s
-data_min		0
-}
-
-plot {
-title			%g Available Swap Space
-source			percol
-data			1024 * swap_avail
-legend			Available Swap Space
-y_legend		Bytes
-data_min		0
-}
-
-plot {
-title			%g Page Residence Time
-source			percol
-data			page_rstim
-legend			Page Residence Time
-y_legend		Seconds
-data_min		0
-}
-
-plot {
-title			%g Page Usage
-source			percol
-data			pp_kernel
-data			free_pages
-data			pagestotl - pp_kernel - free_pages
-data			pagestotl
-line_type		area
-line_type		stack
-line_type		stack
-line_type		line2
-legend			Kernel
-legend			Free List
-legend			Other
-legend			System Total
-y_legend		Number of Pages
-data_min		0
-plot_min		0
-color			00ff00
-color			ff0000
-color			0000ff
-}
-
-plot {
-title			%g Pages Locked & IO
-source			percol
-data			pageslock
-data			pagesio
-legend			Locked
-legend			IO
-y_legend		Number of Pages
-data_min		0
-plot_min		0
-}

Modified: trunk/orca/INSTALL
==============================================================================
--- trunk/orca/INSTALL	(original)
+++ trunk/orca/INSTALL	Sat Jul 13 18:45:53 2002
@@ -1,92 +1,58 @@
 Outline:
-1) Install Perl 5.005_02.
-2) Install necessary Perl modules.
-   a) Install Math::IntervalSearch version 1.00 or greater.
-   b) Install Digest::MD5 version 2.00 or greater.
-   c) Install RRDs version 0.99.6 or greater.
-3) Decide where Orca's binaries, RRD, HTML, and percollator directories
-   will reside.  Make sure performance concerns are handled.
-4) Configure Orca.
-5) Install Orca.
-6) [Optional] Install percollator.
-   a) Install the SE toolkit.
-   b) Apply a patch to the SE 3.0 toolkit.
-   c) Examine Orca/percollator programs.
-   d) Run start_percol on all systems.
-   e) Edit percollator.cfg.
-   f) Run Orca.
 
-1) Install Perl 5.005_02.
+1) Install Perl 5.005_0[23].
 
-   I have used only version version 5.005_02 of Perl with Orca.
-   Because Orca makes very heavy use of references, it may or may not
-   work with older versions of Perl.  I welcome feedback if Orca works
-   with older Perls.
-
-   This step is too large to go into here.  The bottom line is to
-   follow the instructions at
+2) Decide where Orca's binaries, RRD, HTML, and orcallator directories
+   will reside.  Make sure performance concerns are handled.
 
-      http://language.perl.com/info/software.html
+3) Configure Orca.
 
-2) Install necessary Perl modules.
+4) Make, test and install necessary Perl modules.
+   b) Install Digest::MD5 version 2.00 or greater.
    a) Install Math::IntervalSearch version 1.00 or greater.
+   c) Install RRDs version 0.99.29 or greater.
+   d) Install Storable 0.603 or greater.
 
-      Download Math::IntervalSearch from either:
+5) Make Orca.
 
-         ftp://ftp.gps.caltech.edu/pub/blair/Perl/Math-Interpolate-1.01.tar.gz
-         http://www.perl.com/CPAN/authors/id/B/BZ/BZAJAC/Math-Interpolate-1.01.tar.gz
+6) Install Orca.
 
-      % gunzip -c Math-Interpolate-1.01.tar.gz | tar xvf -
-      % cd Math-Interpolate-1.01
-      % perl Makefile.PL
-      % make
-      % make test
-      % make install
+7) [Optional] Install orcallator.
+   a) If required, rename all percollator, percol and perc filenames to
+      orcallator.
+   b) Install the SE toolkit.
+   c) Apply a patch to the SE 3.0 toolkit.
+   d) Examine Orca/orcallator programs.
+   e) Run start_orcallator on all systems.
+   f) Edit orcallator.cfg.
+   g) Run Orca.
 
-   b) Install Digest::MD5 version 2.00 or greater.
 
-      Download Digest::MD5 from:
 
-         http://www.perl.com/CPAN/authors/id/GAAS/Digest-MD5-2.02.tar.gz
 
-      % gunzip -c Digest-MD5-2.02.tar.gz | tar xvf -
-      % cd Digest-MD5-2.02
-      % perl Makefile.PL
-      % make
-      % make test
-      % make install
+1) Install Perl 5.005_0[23].
 
-   c) Install RRDs version 0.99.6 or greater.
+   I have used only version 5.005_0[23] of Perl with Orca.  Because Orca
+   makes very heavy use of references, it may or may not work with older
+   versions of Perl.  I welcome feedback if Orca works with older Perls.
 
-      Download RRDs from:
+   This step is too large to go into here.  The bottom line is to follow
+   the instructions at
 
-         http://ee-staff.ethz.ch/~oetiker/webtools/rrdtool/pub/
-
-      % gunzip -c rrdtool-?.??.?.tar.gz | tar xvf -
-      % cd rrdtool-?.??.?
-      % sh configure --verbose
-      % make                                [ To optimize: make CFLAGS=-O ]
-      % cd perl-shared
-      % perl Makefile.PL
-      % make                                [ To optimize: make OPTIMIZE=-O ]
-      % make test
-      % make install
-
-      For large installations, I recommend that RRD be compiled with
-      optimization turned on.
+      http://language.perl.com/info/software.html
 
-3) Decide where Orca's binaries, RRD, HTML, and percollator directories
+2) Decide where Orca's binaries, RRD, HTML, and orcallator directories
    will reside.  Make sure performance concerns are handled.
 
    First choose the location where Orca will be installed.  By default,
    Orca will install into the following structure:
 
-   $prefix                      Prefix, set with --prefix=
-   $prefix/bin                  Binaries, set with --bindir=
-   $prefix/lib                  Libraries, set with --libdir=
-   $prefix/man                  Manual pages, set with --mandir=
-   $prefix/var/orca/rrd         RRD directory, set with --with-rrd-dir
-   $prefix/var/orca/percollator Percollator directory, set with --with-perc-dir
+   $prefix                     Prefix, set with --prefix=
+   $prefix/bin                 Binaries, set with --bindir=
+   $prefix/lib                 Libraries, set with --libdir=
+   $prefix/man                 Manual pages, set with --mandir=
+   $prefix/var/orca/rrd        RRD directory, set with --with-rrd-dir
+   $prefix/var/orca/orcallator Orcallator directory, set with --with-orcallator-dir
 
    By default $prefix is set to /usr/local.  The -- arguments shown
    above should be given to the configure script described below which
@@ -102,37 +68,37 @@
    concerns it is more important this directory be locally stored than
    HTML directory where the resulting HTML and GIF files are written.
 
-   If you are going to use the percollator Orca addon to monitor your
+   If you are going to use the orcallator Orca addon to monitor your
    Sun Solaris systems, then you will in addition need to decide where
-   to have percollator store its data files.  By default, these data
+   to have orcallator store its data files.  By default, these data
    files are written to once every 5 minutes, so IO is not an issue.
-   The issue here is that percollator needs to run as root and all of
-   the percollator output files from all your hosts need to be written
+   The issue here is that orcallator needs to run as root and all of
+   the orcallator output files from all your hosts need to be written
    into the same NFS shared directory that Orca can read.  It is not too
-   important that the directory that percollator writes into be mounted
+   important that the directory that orcallator writes into be mounted
    locally on the machine that Orca will run on, since Orca will only
    read each file every five minutes.
 
-   If you are running percollator on a system running a web, proxy,
-   or Squid server, you can have percollator watch the logs generated
-   by these programs.  In this case, note the location of the log file
-   for the configure script.
+   If you are running orcallator on a system running a web, proxy, or
+   Squid server, you can have orcallator watch the logs generated by
+   these programs.  In this case, note the location of the log file for
+   the configure script.
 
-4) Configure Orca.
+3) Configure Orca.
 
    Now that you have decided where the RRD, HTML, and optionally the
-   percollator data files and the web server access logs, are located,
+   orcallator data files and the web server access logs, are located,
    run the configure script with the following arguments:
 
    % ./configure --prefix=ORCA_PREFIX_DIRECTORY \
                  --with-rrd-dir=RRD_DIR_LOCATION \
                  --with-html-dir=HTML_DIR_LOCATION \
-                 --with-perc-dir=PERCOLLATOR_DIR_LOCATION \
+                 --with-orcallator-dir=ORCALLATOR_DIR_LOCATION \
                  --with-TYPE-log=LOG_LOCATION
 
    If you choose nothing else, the --with-html-dir must always be used.
 
-   If you use a web, proxy, or Squid server, you can have percollator
+   If you use a web, proxy, or Squid server, you can have orcallator
    gather statistics from the log file.  Use this table to decide which
    configure option to use:
 
@@ -145,16 +111,126 @@
    Configure will let you use only one of these --with-TYPE-log options.
 
    The configure script will find where your version of Perl and some
-   other assorted programs are located.
+   other assorted programs are located.  It will also determine if you
+   have the necessary Perl modules to run Orca.  If it does not find
+   the required modules, the modules that are included with the Orca
+   distribution will be built.
+
+4) Make, test and install necessary Perl modules.
+
+   Orca requires the following modules at the specified version number:
+
+   Name				Required Version	Included With Orca
+   -----------------------------------------------------------------------
+   Digest::MD5 version		2.00 or greater		2.07
+   Math::IntervalSearch		1.00 or greater		1.02
+   RRDs version			0.99.29 or greater	0.99.29
+   Storable			0.603 or greater	0.603
+
+   All four of these modules are included with the Orca distribution
+   in the packages directory.  When you configured Orca in step 3),
+   configure should have determined if you need any of these modules
+   installed in the version of Perl that configure found.  configure will
+   then modify the packages/Makefile file to only build those modules
+   that need to be installed.
+
+   All of the modules except for Math::IntervalSearch require a compiler
+   and generate shared libraries by default.
+
+   To make these modules run the following command:
+
+   % make modules			[ To optimize: make modules CFLAGS=-O ]
 
-5) Install Orca.
+   To test if the modules are working properly, run the following command:
 
-   Now run make and make install:
+   % make test_modules
+
+   To automatically install these modules into Perl run the following
+   command:
+
+   % make install_modules
+
+   If you want newer version of these modules, get them from the following
+   locations:
+
+   Math::IntervalSearch
+
+      ftp://ftp.gps.caltech.edu/pub/blair/Perl/Math-Interpolate-1.02.tar.gz
+      http://www.perl.com/CPAN/authors/id/B/BZ/BZAJAC/Math-Interpolate-1.02.tar.gz
+
+      % gunzip -c Math-Interpolate-1.02.tar.gz | tar xvf -
+      % cd Math-Interpolate-1.02
+      % perl Makefile.PL
+      % make
+      % make test
+      % make install
+
+   Digest::MD5
+
+      http://www.perl.com/CPAN/authors/id/GAAS/Digest-MD5-2.07.tar.gz
+
+      % gunzip -c Digest-MD5-2.07.tar.gz | tar xvf -
+      % cd Digest-MD5-2.07
+      % perl Makefile.PL
+      % make
+      % make test
+      % make install
+
+   RRDs
+
+      http://ee-staff.ethz.ch/~oetiker/webtools/rrdtool/pub/
+
+      RRDs is the Perl module that comes with RRDtool, a package written
+      by Tobias Oetiker.  RRDtool contains a copy of the gd1.2 library
+      and is installed automatically into the RRDtool shared library that
+      is used by the RRDs Perl module.  While gd1.3 exists, according
+      to its README file it generates larger GIFs.  I see no reason to
+      link RRDtool with gd1.3.
+
+      % gunzip -c rrdtool-?.??.??.tar.gz | tar xvf -
+      % cd rrdtool-?.??.??
+      % sh configure --verbose
+      % make                                [ To optimize: make CFLAGS=-O ]
+      % cd perl-shared
+      % make test
+      % make install
+
+      For large installations, I recommend that RRDs be compiled with
+      optimization turned on.
+
+5) Make Orca.
+
+   Build Orca by running the following command:
 
    % make
+
+6) Install Orca.
+
+   Between version 0.20 and 0.21 of Orca, a major name change occurred in
+   all of the installed and generated files.  Any filenames containing
+   percollator, percol, and perc had the name orcallator substituted in
+   place.  Percollator.se has been renamed to orcallator.se and its output
+   files are now named orcallator.  The default percollator.cfg has been
+   renamed to orcallator.cfg and the version of orcallator.cfg included
+   here now looks for data filenames of the form orcallator-1999-05-08
+   and percol-1999-05-8.  If you are running an Orca installation 0.20 or
+   older and want to rename all of the files and directories in your Orca
+   installation to the new scheme, then kill any running percollator.se's
+   and Orca processes.  Then run
+
+   % make migrate
+
+   This will look through the all of the directories that Orca will
+   install into and use (namely the $prefix, $exec_prefix, $bindir,
+   $libdir, $ORCALLATOR_DIR, and $RRD_DIR directories) and perform any
+   necessary file renaming.  Filenamess containing the word percent will
+   not have be modified to contain the word orcallatorent.
+
+   Now run the following command to install Orca:
+
    % make install
 
-6) [Optional] Install percollator.
+7) [Optional] Install orcallator.
    a) Install the SE toolkit.
 
       Perform the installation instructions as listed on the web page
@@ -173,7 +249,7 @@
       % cd /opt/RICHPse
       % patch -s < THIS_DIR/patches/p_netstat_class.se.diff
 
-   c) Examine Orca/percollator programs.
+   c) Examine Orca/orcallator programs.
 
       Orca's installation scripts also installs several programs and
       configuration files necessary to have Orca monitor many different
@@ -181,29 +257,33 @@
 
       The following tools are installed in the $prefix/bin directory:
 
-         start_percol   - start percollator on a system
-         stop_precol    - stop percollator on a system
-         restart_percol - restart percollator on a system
-         percol_column  - print selected columns from percollator output
-         percol_running - run to see if any percollators are not running
+         start_orcallator   - start orcallator on a system
+         stop_precol        - stop orcallator on a system
+         restart_orcallator - restart orcallator on a system
+         orcallator_column  - print selected columns from orcallator output
+         orcallator_running - run to see if any orcallators are not running
 
-   d) Run start_percol on all systems.
+   d) Run start_orcallator on all systems.
 
       Log in as root on all the systems you want to watch and run:
 
-      % $prefix/bin/start_percol
+      % $prefix/bin/start_orcallator
+
+      Orcallator will not generate an output data file until the first
+      update interval, which will be between 2.5 to 7.5 minutes after
+      orcallator is started.
 
-   e) Edit percollator.cfg.
+   e) Edit orcallator.cfg.
 
-      You need to edit the installed percollator.cfg file and remove
+      You need to edit the installed orcallator.cfg file and remove
       all unneeded references.  In particular, you'll want to change
       warn_email, which is the email address that receives emails when
-      percollator generated files are out of date, which may signify a
-      percollator program that has died and is no longer gathering data.
+      orcallator generated files are out of date, which may signify a
+      orcallator program that has died and is no longer gathering data.
 
    f) Run Orca.
 
       Log into the system that will run Orca and run the command:
 
       % cd $prefix
-      % ./bin/orca -v lib/percollator.cfg
+      % ./bin/orca -v lib/orcallator.cfg

Modified: trunk/orca/src/orcallator_running.pl.in
==============================================================================
--- trunk/orca/src/orcallator_running.pl.in	(original)
+++ trunk/orca/src/orcallator_running.pl.in	Sat Jul 13 18:45:53 2002
@@ -1,4 +1,4 @@
-# not_running: warn if percollator files are not up to date.
+# orcallator_running: warn if orcallator files are not up to date.
 #
 # Copyright (C) 1998, 1999 Blair Zajac and GeoCities, Inc.
 

Modified: trunk/orca/src/Makefile.in
==============================================================================
--- trunk/orca/src/Makefile.in	(original)
+++ trunk/orca/src/Makefile.in	Sat Jul 13 18:45:53 2002
@@ -1,14 +1,18 @@
+ at SET_MAKE@
+
 prefix		= @prefix@
 exec_prefix	= @exec_prefix@
 bindir		= @bindir@
 MKDIR		= @MKDIR@
 INSTALL		= @INSTALL@
 PERL_HEAD	= @PERL_HEAD@
-PERL_SCRIPTS	= percol_running orca percol_column
-SHELL_SCRIPTS	= restart_percol stop_percol start_percol
+ORCALLATOR_DIR	= @ORCALLATOR_DIR@
+RRD_DIR		= @RRD_DIR@
+PERL_SCRIPTS	= orcallator_running orca orcallator_column
+SHELL_SCRIPTS	= restart_orcallator stop_orcallator start_orcallator
 TARGETS		= $(PERL_SCRIPTS) $(SHELL_SCRIPTS)
 
-all:		$(TARGETS)
+all:		$(TARGETS) migrate_to_orcallator
 
 install: all
 		$(MKDIR) $(bindir)
@@ -17,11 +21,14 @@
 			$(INSTALL) $$file $(bindir);		\
 		done
 
+migrate:	migrate_to_orcallator
+		./migrate_to_orcallator $(prefix) $(exec_prefix) $(bindir) $(libdir) $(ORCALLATOR_DIR) $(RRD_DIR)
+
 clean:
 		$(RM) $(TARGETS)
 
 distclean:	clean
-		$(RM) *.sh percol_running.pl Makefile
+		$(RM) *.sh orcallator_running.pl Makefile
 
 .SUFFIXES:	.pl .sh
 
@@ -33,5 +40,22 @@
 		cp $< $@
 		chmod 0755 $@
 
-percol_running.pl: percol_running.pl.in
-		cd ..; ./config.status
+Makefile:	Makefile.in
+		(cd ..; ./config.status)
+		$(MAKE)
+
+orcallator_running.pl:		orcallator_running.pl.in
+		(cd ..; ./config.status)
+		$(MAKE)
+
+restart_orcallator.sh:		restart_orcallator.sh.in
+		(cd ..; ./config.status)
+		$(MAKE)
+
+start_orcallator.sh:		start_orcallator.sh.in
+		(cd ..; ./config.status)
+		$(MAKE)
+
+stop_orcallator.sh:		stop_orcallator.sh.in
+		(cd ..; ./config.status)
+		$(MAKE)

Modified: trunk/orca/src/restart_orcallator.sh.in
==============================================================================
--- trunk/orca/src/restart_orcallator.sh.in	(original)
+++ trunk/orca/src/restart_orcallator.sh.in	Sat Jul 13 18:45:53 2002
@@ -1,12 +1,12 @@
 #!/bin/sh
 
-# This stops and restarts percollator.se.
+# This stops and restarts orcallator.se.
 prefix=@prefix@
 exec_prefix=@exec_prefix@
 bindir=@bindir@
 
-# Kill any running percollators.
-$bindir/stop_percol
+# Kill any running orcallators.
+$bindir/stop_orcallator
 
-# Start the percollator.
-$bindir/start_percol
+# Start the orcallator.
+$bindir/start_orcallator

Modified: trunk/orca/src/stop_orcallator.sh.in
==============================================================================
--- trunk/orca/src/stop_orcallator.sh.in	(original)
+++ trunk/orca/src/stop_orcallator.sh.in	Sat Jul 13 18:45:53 2002
@@ -2,17 +2,17 @@
 
 AWK=@AWK@
 
-# Kill any running percollators.
-pids=`/usr/ucb/ps auxww | $AWK '/percollator.se/ && !/awk/ {print $2}'`
+# Kill any running orcallators.
+pids=`/usr/ucb/ps auxww | $AWK '/orcallator.se/ && !/awk/ {print $2}'`
 if test "$pids" != ""; then
   echo "Killing pids $pids."
   kill -HUP $pids
   sleep 1
-  pids=`/usr/ucb/ps auxww | $AWK '/percollator.se/ && !/awk/ {print $2}'`
+  pids=`/usr/ucb/ps auxww | $AWK '/orcallator.se/ && !/awk/ {print $2}'`
   if test "$pids" != ""; then
     kill -TERM $pids
     sleep 1
-    pids=`/usr/ucb/ps auxww | $AWK '/percollator.se/ && !/awk/ {print $2}'`
+    pids=`/usr/ucb/ps auxww | $AWK '/orcallator.se/ && !/awk/ {print $2}'`
     if test "$pids" != ""; then
       kill -9 $pids
       sleep 1

Added: trunk/orca/src/migrate_to_orcallator.pl
==============================================================================
--- trunk/orca/src/migrate_to_orcallator.pl	(original)
+++ trunk/orca/src/migrate_to_orcallator.pl	Sat Jul 13 18:45:53 2002
@@ -0,0 +1,34 @@
+# migrate_to_orcallator: migrate from a percollator named installation to
+# an orcallator named install.
+#
+# Copyright (C) 1999 Blair Zajac and GeoCities, Inc.
+
+use strict;
+use File::Find;
+
+$| = 1;
+
+# Take a list of directories and rename every file in the directory using
+# the following translation in the following order:
+#   percollator -> orcallator
+#   percol      -> orcallator
+#   perc        -> orcallator
+# Protect the word percent from this conversion.
+foreach my $dir (@ARGV) {
+  finddepth(\&rename, $dir) if -d $dir;
+}
+
+sub rename {
+  my $old_name = $_;
+  my $new_name = $_;
+  $new_name =~ s/percent/\200/g;
+  $new_name =~ s/percollator/orcallator/g;
+  $new_name =~ s/percol/orcallator/g;
+  $new_name =~ s/perc/orcallator/g;
+  $new_name =~ s/\200/percent/g;
+  if ($old_name ne $new_name) {
+    print "Renaming $File::Find::dir/$old_name\n";
+    rename("$File::Find::dir/$old_name", "$File::Find::dir/$new_name") or
+      warn "$0: cannot rename `$File::Find::dir/$old_name': $!\n";
+  }
+}

Modified: trunk/orca/src/orcallator_column.pl
==============================================================================
--- trunk/orca/src/orcallator_column.pl	(original)
+++ trunk/orca/src/orcallator_column.pl	Sat Jul 13 18:45:53 2002
@@ -1,4 +1,4 @@
-# percol_column: display selected columns from percollator output.
+# orcallator_column: display selected columns from orcallator output.
 #
 # Copyright (C) 1998, 1999 Blair Zajac and GeoCities, Inc.
 

Modified: trunk/orca/src/start_orcallator.sh.in
==============================================================================
--- trunk/orca/src/start_orcallator.sh.in	(original)
+++ trunk/orca/src/start_orcallator.sh.in	Sat Jul 13 18:45:53 2002
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-# This script runs percollator.se with the proper options for your site.
+# This script runs orcallator.se with the proper options for your site.
 
 # Define program locations that will be needed.
 prefix=@prefix@
@@ -25,8 +25,8 @@
 # Export the environmental variables.
 export OUTDIR WEB_LOG
 
-# Check if percollator is already running.
-pids=`/usr/ucb/ps auxww | $AWK '/percollator.se/ && !/awk/ {print $2}'`
+# Check if orcallator is already running.
+pids=`/usr/ucb/ps auxww | $AWK '/orcallator.se/ && !/awk/ {print $2}'`
 if test "$pids" != ""; then
   echo "Percollator already running.  Exiting."
   exit 1
@@ -53,11 +53,11 @@
 
 # Now start the logging.
 echo "Starting logging"
-$SE $LE_PATCH -DWATCH_OS $WATCH_HTTPD $libdir/percollator.se &
+$SE $LE_PATCH -DWATCH_OS $WATCH_HTTPD $libdir/orcallator.se &
 
-# Write the PID of percollator to a file to make killing easier.
+# Write the PID of orcallator to a file to make killing easier.
 pid=$!
-echo $pid > $OUTDIR/percollator.pid
+echo $pid > $OUTDIR/orcallator.pid
 
-# Sleep for a couple of seconds to allow any percollator warnings to appear.
+# Sleep for a couple of seconds to allow any orcallator warnings to appear.
 sleep 5

Modified: trunk/orca/src/orca.pl
==============================================================================
--- trunk/orca/src/orca.pl	(original)
+++ trunk/orca/src/orca.pl	Sat Jul 13 18:45:53 2002
@@ -17,13 +17,13 @@
 
 # This is the version of Orca.
 use vars qw($VERSION);
-$VERSION = '0.20';
+$VERSION = '0.21';
 
 # This is the version number used in creating the DS names in RRDs.
-# This should be updated any time a new version of Orca needs some
-# new content in its RRD files.  The DS name is a concatentation of
-# the string Orca with this string of digits.
-my $ORCA_RRD_VERSION = 19990215;
+# This should be updated any time a new version of Orca needs some new
+# content in its RRD files.  The DS name is a concatentation of the
+# string Orca with this string of digits.
+my $ORCA_RRD_VERSION = 19990222;
 
 # The number of seconds in one day.
 my $day_seconds = 24*60*60;
@@ -31,19 +31,20 @@
 # These define the different RRAs to create, how far back in time they
 # go, how many primary data points go into a consolidated data point,
 # and the default how to create RRAs.  The first array holds the names
-# of the different plot types to create.  The second array holds the number of
-# 300 intervals are used to create a consolidated data point.  The third
-# array is the number of consolidated data points held in the RRA. The
-# first one is every 5 minutes for 200 hours, the second is every 30 minutes
-# for 31 days, the third is every 2 hours for 100 days, and the last is
-# every day for 3 years.  The last array holds the number of days back in
-# time to plot in the GIF.  Be careful to not increase this so much that the
-# number of data points to plot are greater than the number of pixels
-# available for the GIF, otherwise there will be a 30% slowdown due to
-# a reduction calculation to resample the data to the lower resolution for
-# the plot.  For example, with 40 days of 2 hour data, there are 480 data
-# points.  For no slowdown to occur, the GIF should be atleast 480 pixels
-# wide.
+# of the different plot types to create.  The second array holds the
+# number of 300 intervals are used to create a consolidated data
+# point.  The third array is the number of consolidated data points
+# held in the RRA. The first one is every 5 minutes for 200 hours, the
+# second is every 30 minutes for 31 days, the third is every 2 hours
+# for 100 days, and the last is every day for 3 years.  The last array
+# holds the number of days back in time to plot in the GIF.  Be
+# careful to not increase this so much that the number of data points
+# to plot are greater than the number of pixels available for the GIF,
+# otherwise there will be a 30% slowdown due to a reduction
+# calculation to resample the data to the lower resolution for the
+# plot.  For example, with 40 days of 2 hour data, there are 480 data
+# points.  For no slowdown to occur, the GIF should be atleast 480
+# pixels wide.
 my @rra_plot_type = qw(daily weekly monthly yearly);
 my @rra_pdp_count =   (    1,     6,     24,   288);
 my @rra_row_count =   ( 2400,  1488,   1200,  1098);
@@ -106,20 +107,18 @@
 <table cellpadding=0 border=0>
   <tr>
     <td width=350 valign=center>
-      <a href="http://www.geocities.com/ResearchTriangle/Thinktank/4996/">
-        <img width=186 height=45 border=0 src="orca.gif" alt="Orca Home Page" >
-      </a>
+      <a href="http://www.geocities.com/~bzking/">
+        <img width=186 height=45 border=0 src="orca.gif" alt="Orca Home Page"></a>
       <br>
-      <font FACE="Arial,Helvetica" SIZE=2>
+      <font FACE="Arial,Helvetica" size=2>
         Orca-$::VERSION by
-        <a href="http://www.geocities.com/ResearchTriangle/Thinktank/4996/">Blair Zajac</a>
+        <a href="http://www.geocities.com/~bzking/">Blair Zajac</a>
         <a href="mailto:bzajac\@geostaff.com">bzajac\@geostaff.com</a>.
       </font>
     </td>
     <td width=120 valign=center>
       <a href="http://ee-staff.ethz.ch/~oetiker/webtools/rrdtool">
-        <img width=120 height=34 border=0 src="rrdtool.gif" alt="RRDTool Home Page">
-      </a>
+        <img width=120 height=34 border=0 src="rrdtool.gif" alt="RRDTool Home Page"></a>
     </td>
   </tr>
 </table>
@@ -140,9 +139,9 @@
     confess "$0: Orca::OpenFileHash::new passed wrong number of arguments.\n";
   }
 
-  my $class        = shift;
+  my ($class, $max_elements) = @_;
 
-  bless {_max_elements => shift,
+  bless {_max_elements => $max_elements,
          _hash         => {},
          _weights      => {},
          _filenos      => {},
@@ -173,8 +172,9 @@
 sub add {
   my ($self, $filename, $weight, $fd) = @_;
 
-  # If there is an open file descriptor for this filename, then force it to
-  # close.  Then make space for the new file descriptor in the cache.
+  # If there is an open file descriptor for this filename, then force
+  # it to close.  Then make space for the new file descriptor in the
+  # cache.
   $self->close($filename);
   $self->_close_extra($self->{_max_elements} - 1);
 
@@ -319,8 +319,8 @@
     $self->{_buffer}{$filename} .= $buffer;
   }
 
-  # Find the first \n and return all the characters up to and including
-  # that point.
+  # Find the first \n and return all the characters up to and
+  # including that point.
   $pos = index($self->{_buffer}{$filename}, "\n");
   my $line = '';
   if ($pos != -1) {
@@ -340,8 +340,8 @@
 
 package main;
 
-# Set up a cache of 150 open file descriptors.  This leaves 255-150-3 = 102
-# file descriptors for other use in the program.
+# Set up a cache of 150 open file descriptors.  This leaves 255-150-3
+# = 102 file descriptors for other use in the program.
 use vars qw($open_file_cache);
 $open_file_cache = Orca::OpenFileHash->new(150) unless $open_file_cache;
 
@@ -354,8 +354,8 @@
     confess "$0: Orca::DataFile::new passed wrong number of arguments.\n";
   }
 
-  my $class    = shift;
-  my $filename = shift;
+  my ($class, $filename) = @_;
+
   confess "$0: filename not passed to $class.\n" unless $filename;
   my $self = bless {_filename       => $filename,
                     _last_stat_time => -1,
@@ -391,10 +391,11 @@
 sub update_stat {
   my $self = shift;
 
-  # Only update the stat if the previous stat occured more than one second
-  # ago.  This is used when this function is called immediately after the
-  # object has been constructed and when we don't want to call two stat's
-  # immediately.  The tradeoff is to call time() instead.
+  # Only update the stat if the previous stat occured more than one
+  # second ago.  This is used when this function is called immediately
+  # after the object has been constructed and when we don't want to
+  # call two stat's immediately.  The tradeoff is to call time()
+  # instead.
   my $time = time;
   if ($time > $self->{_last_stat_time} + 1) {
     my @stat = stat($self->{_filename});
@@ -445,7 +446,7 @@
 
 package Orca::GIFFile;
 
-use RRDs 0.99011;
+use RRDs 0.99029;
 use Carp;
 
 sub new {
@@ -499,14 +500,16 @@
     _my_rrd_list	=> [ &::unique(@$my_rrds_ref) ],
     _plot_ref           => $plot_ref,
     _interval           => int($config_files->{$files_key}{interval}+0.5),
-    _expire             => $config_options->{expire_gifs}
+    _expire             => $config_options->{expire_gifs},
+    _gif_height         => 0,
+    _gif_width          => 0
   }, $class;
 
   # If the GIF already exists, then use its last modification time to
   # calculate when it was last updated.  If the file modification time
   # is newer than the timestamp of the last data point entered, then
-  # assume that the GIF needs to be recreated.  This data will cause the
-  # GIF to be created if the GIF does not exist.
+  # assume that the GIF needs to be recreated.  This data will cause
+  # the GIF to be created if the GIF does not exist.
   my $plot_end_time = $self->plot_end_time;
   foreach my $plot_type (@rra_plot_type) {
     $self->{"_${plot_type}_update_time"} = -1;
@@ -527,20 +530,32 @@
   $self;
 }
 
-sub rrds {
-  @{$_[0]->{_my_rrd_list}};
+sub files_key {
+  $_[0]->{_files_key};
 }
 
-sub plot_ref {
-  $_[0]->{_plot_ref};
+sub gif_width {
+  $_[0]->{_gif_width};
 }
 
-sub group {
-  $_[0]->{_group};
+sub gif_height {
+  $_[0]->{_gif_height};
 }
 
-sub files_key {
-  $_[0]->{_files_key};
+# For this GIF return a string that can be used to size the image
+# properly in HTML.  The output from this subroutine is either an
+# empty string or the size of the image.
+sub gif_img_src_size {
+  if ($_[0]->{_gif_height} and $_[0]->{_gif_width}) {
+    return "width=$_[0]->{_gif_width} height=$_[0]->{_gif_height}";
+  }
+  else {
+    return "";
+  }
+}
+
+sub group {
+  $_[0]->{_group};
 }
 
 sub name {
@@ -551,6 +566,14 @@
   $_[0]->{_no_group_name};
 }
 
+sub plot_ref {
+  $_[0]->{_plot_ref};
+}
+
+sub rrds {
+  @{$_[0]->{_my_rrd_list}};
+}
+
 # Calculate the time of the last data point entered into the RRD that
 # this gif will use.
 sub plot_end_time {
@@ -584,17 +607,18 @@
 sub _plot {
   my ($self, $plot_type, $days_back, $rra_pdp_count) = @_;
 
-  # Get the time stamp of the last data point entered into the RRDs that
-  # are used to generate this GIF.
+  # Get the time stamp of the last data point entered into the RRDs
+  # that are used to generate this GIF.
   my $plot_end_time = $self->plot_end_time;
 
-  # Determine if the plot needs to be generated.  First see if there has
-  # been data flushed to the RRD that needs to be plotted.  Otherwise,
-  # see if the does not file exists or if the time corresponding to the
-  # last data point is newer than the GIF.  Take into account that a new
-  # plot does not need to be generated until a primary data point has been
-  # added.  Primary data points are added after a data point falls into a
-  # new bin, where the bin ends on multiples of the sampling iterval.
+  # Determine if the plot needs to be generated.  First see if there
+  # has been data flushed to the RRD that needs to be plotted.
+  # Otherwise, see if the does not file exists or if the time
+  # corresponding to the last data point is newer than the GIF.  Take
+  # into account that a new plot does not need to be generated until a
+  # primary data point has been added.  Primary data points are added
+  # after a data point falls into a new bin, where the bin ends on
+  # multiples of the sampling iterval.
   my $interval        = $self->{_interval};
   $rra_pdp_count      = int($rra_pdp_count*300.0/$interval + 0.5);
   $rra_pdp_count      = 1 if $rra_pdp_count < 1;
@@ -609,7 +633,7 @@
   my $group     = $self->{_group};
   my @options = (
     '-e', $plot_end_time,
-    '-v', $plot_ref->{y_legend},
+    '-v', ::replace_group_name($plot_ref->{y_legend}, $group),
     '-t', ::replace_group_name($plot_ref->{title}, $group),
     '-w', $plot_ref->{plot_width},
     '-h', $plot_ref->{plot_height}
@@ -627,38 +651,62 @@
   my $data_sources = @{$self->{_my_rrd_list}};
   for (my $i=0; $i<$data_sources; ++$i) {
     my $rrd_key      = $self->{_my_rrd_list}[$i];
-    my $rrd_filename = $self->{_all_rrd_ref}{$rrd_key}->filename;
-    push(@options, "DEF:source$i=$rrd_filename:Orca$ORCA_RRD_VERSION:AVERAGE");
+    my $rrd          = $self->{_all_rrd_ref}{$rrd_key};
+    my $rrd_filename = $rrd->filename;
+    my $rrd_version  = $rrd->version;
+    push(@options, "DEF:average$i=$rrd_filename:Orca$rrd_version:AVERAGE");
   }
+  my @legends;
+  my $max_legend_length = 0;
   for (my $i=0; $i<$data_sources; ++$i) {
-    my $legend    = ::replace_group_name($plot_ref->{legend}[$i], $group);
-    my $line_type = $plot_ref->{line_type}[$i];
-    my $color     = $plot_ref->{color}[$i];
-    push(@options, "$line_type:source$i#$color:$legend");
+    my $legend         = ::replace_group_name($plot_ref->{legend}[$i], $group);
+    my $line_type      = $plot_ref->{line_type}[$i];
+    my $color          = $plot_ref->{color}[$i];
+    push(@options, "$line_type:average$i#$color:$legend");
+    $legend            =~ s:%:\200:g;
+    $legend            =~ s:\200:%%:g;
+    my $legend_length  = length($legend);
+    $max_legend_length = $legend_length if $legend_length > $max_legend_length;
+    push(@legends, $legend);
   }
+
+  # Force a break between the plot legend and comments.
+  push(@options, 'COMMENT:\s',);
+
+  # Generate the legends containing the current, average, minimum, and
+  # maximum values on the plot.
   for (my $i=0; $i<$data_sources; ++$i) {
-    my $legend = ::replace_group_name($plot_ref->{legend}[$i], $group);
-    $legend    =~ s:%:\200:g;
-    $legend    =~ s:\200:%%:g;
-    push(@options, "GPRINT:source$i:AVERAGE:Average $legend is %f",
-                   "GPRINT:source$i:LAST:Current $legend is %f");
-  }
+    my $legend = $legends[$i];
+    $legend   .= ' ' x ($max_legend_length - length($legend));
+    push(@options, "GPRINT:average$i:LAST:$legend  Current\\: %f",
+                   "GPRINT:average$i:AVERAGE:Average\\: %f",
+                   "GPRINT:average$i:MIN:Min\\: %f",
+                   "GPRINT:average$i:MAX:Max\\: %f\\l"
+        );
+  }
+  push(@options, 'COMMENT:\s',
+                 'COMMENT:Last data entered at ' .
+                 localtime($plot_end_time) . '.');
 
   my $gif_filename = "$self->{_gif_basename}-$plot_type.gif";
   print "  Creating `$gif_filename'.\n" if $opt_verbose > 1;
 
-  my $graph_return = RRDs::graph $gif_filename,
-                                '-s', ($plot_end_time-$days_back*$day_seconds),
-                                @options;
+  my ($graph_return, $gif_width, $gif_height) =
+    RRDs::graph $gif_filename,
+                '-s', ($plot_end_time-$days_back*$day_seconds),
+                @options;
   if (my $error = RRDs::error) {
     warn "$0: warning: cannot create `$gif_filename': $error\n";
   }
   else {
     $self->{$time_update_key} = $plot_end_time;
+    $self->{_gif_height}      = $gif_height;
+    $self->{_gif_width}       = $gif_width;
     utime $plot_end_time, $plot_end_time, $gif_filename or
       warn "$0: warning: cannot change mtime for `$gif_filename': $!\n";
 
-    # Expire the GIF at the correct time using a META file if requested.
+    # Expire the GIF at the correct time using a META file if
+    # requested.
     if ($self->{_expire}) {
       if (open(META, "> $gif_filename.meta")) {
         my $time = 
@@ -678,11 +726,11 @@
 }
 
 sub _expire_string {
-  my @gmtime = gmtime(shift);
-  my ($wday) = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat')[$gmtime[6]];
+  my @gmtime  = gmtime($_[0]);
+  my ($wday)  = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat')[$gmtime[6]];
   my ($month) = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep', 
                  'Oct','Nov','Dec')[$gmtime[4]];
-  my ($mday,$year,$hour,$min,$sec) = @gmtime[3,5,2,1,0];
+  my ($mday, $year, $hour, $min, $sec) = @gmtime[3,5,2,1,0];
   if ($mday<10) {$mday = "0$mday";}
   if ($hour<10) {$hour = "0$hour";}
   if ($min<10)  {$min  = "0$min";}
@@ -712,6 +760,10 @@
       $plot_ref,
       $choose_data_sub) = @_;
 
+  unless (ref($choose_data_sub) eq 'CODE') {
+    confess "$0: Orca::RRDFile::new not passed a valid CODE ref for choosing data.\n";
+  }
+
   # Remove any special characters from the unique name and do some
   # replacements.
   $name = &::strip_key_name($name);
@@ -736,10 +788,11 @@
   $self->{_created_gifs}     = {};
   $self->{_plot_ref}         = $plot_ref;
   $self->{_interval}         = int($config_files->{$files_key}{interval}+0.5);
+  $self->{_rrd_version}      = $ORCA_RRD_VERSION;
 
-  # See if the RRD file meets two requirements. The first is to see
-  # if the last update time can be sucessfully read.  The second is
-  # to see if the RRD has an DS named "Orca$ORCA_RRD_VERSION".  If
+  # See if the RRD file meets two requirements. The first is to see if
+  # the last update time can be sucessfully read.  The second is to
+  # see if the RRD has an DS named "Orca$ORCA_RRD_VERSION".  If
   # neither one of these is true, then create a brand new RRD is
   # created when data is first flushed to it.
   $self->{_rrd_update_time} = -2;
@@ -760,12 +813,15 @@
         close(RRDFILE) or
           warn "$0: error in closing `$rrd_filename' for reading: $!\n";
 
-        # Check the version number of file to the required version.
-        if ($version eq $ORCA_RRD_VERSION) {
-          $self->{_rrd_update_time} = $update_time;
-        }
-        elsif ($version) {
-          warn "$0: old version $version RRD `$rrd_filename' found: will create new version $ORCA_RRD_VERSION file.\n";
+        # Compare the version number of file to the required version.
+        if (length($version)) {
+          if ($version >= $ORCA_RRD_VERSION) {
+            $self->{_rrd_update_time} = $update_time;
+            $self->{_rrd_version}     = $version;
+          }
+          else {
+            warn "$0: old version $version RRD `$rrd_filename' found: will create new version $ORCA_RRD_VERSION file.\n";
+          }
         }
         else {
           warn "$0: unknown version RRD `$rrd_filename' found: will create new version $ORCA_RRD_VERSION file.\n";
@@ -777,6 +833,10 @@
   $self;
 }
 
+sub version {
+  $_[0]->{_rrd_version};
+}
+
 sub name {
   $_[0]->{_name};
 }
@@ -792,8 +852,7 @@
 }
 
 sub created_gifs {
-  my $self = shift;
-  values %{$self->{_created_gifs}};
+  values %{$_[0]->{_created_gifs}};
 }
 
 # Given a row of data from a source data file, take the required data
@@ -851,12 +910,12 @@
                    '-s', $interval,
                    $data_source);
 
-    # Create the round robin archives.  Take special care to not create two
-    # RRA's with the same number of primary data points.  This can happen
-    # if the interval is equal to one of the consoldated intervals.
+    # Create the round robin archives.  Take special care to not
+    # create two RRA's with the same number of primary data points.
+    # This can happen if the interval is equal to one of the
+    # consoldated intervals.
     my $count = int($rra_row_count[0]*300.0/$interval + 0.5);
-    my @one_pdp_option = ("RRA:AVERAGE:0.5:1:$count",
-                          "RRA:LAST:0.5:1:1");
+    my @one_pdp_option = ("RRA:AVERAGE:0.5:1:$count");
 
     for (my $i=1; $i<@rra_pdp_count; ++$i) {
       next if $interval > 300*$rra_pdp_count[$i];
@@ -865,8 +924,7 @@
         push(@options, @one_pdp_option);
       }
       @one_pdp_option = ();
-      push(@options, "RRA:AVERAGE:0.5:$rra_pdp_count:$rra_row_count[$i]",
-                     "RRA:LAST:0.5:$rra_pdp_count:1");
+      push(@options, "RRA:AVERAGE:0.5:$rra_pdp_count:$rra_row_count[$i]");
     }
 
     # Now do the actual creation.
@@ -900,7 +958,8 @@
     return 0;
   }
 
-  # If there were no errors, then totally clear the hash to save memory.
+  # If there were no errors, then totally clear the hash to save
+  # memory.
   delete $self->{_new_data};
   $self->{_new_data} = {};
 
@@ -913,6 +972,7 @@
 
 use Carp;
 use Digest::MD5 qw(md5);
+use Storable 0.603 qw(dclone);
 use vars qw(@ISA);
 
 @ISA = qw(Orca::DataFile);
@@ -921,6 +981,20 @@
 # return the correct data from the input file.
 my %read_value_subs;
 
+# This is a static variable that lists all of the column names for a
+# particular files key.
+my %files_key_column_names;
+
+# This caches the reference to the array holding the column
+# descriptions for files that have their column descriptions in the
+# first line of the file.
+my %first_line_cache;
+
+# These are caches for the different objects that are used to add a
+# plot.
+my %all_rrds_cache;
+my %my_rrds_cache;
+
 sub new {
   unless (@_ == 10) {
     confess "$0: Orca::SourceDataFile::new passed incorrect number of arguments.\n";
@@ -941,33 +1015,35 @@
   $self->{_interval}           = $interval;
   $self->{_late_interval}      = int(&$late_interval($interval) + 0.5);
   $self->{_reopen}             = $reopen;
-  $self->{_column_description} = $column_description;
   $self->{_date_source}        = $date_source;
   $self->{_date_format}        = $date_format;
   $self->{_warn_email}         = $warn_email;
-  $self->{_last_data_time}     =    -1;
-  $self->{_last_read_time}     =    -1;
-  $self->{_my_rrd_hash}        =    {};
+  $self->{_my_rrd_hash}        = {};
   $self->{_all_rrd_ref}        = undef;
-  $self->{_first_line}         =     0;
+  $self->{_files_keys}         = {};
+
+  $self->{_column_description} = $column_description;
+  $self->{_last_data_time}     = -1;
+  $self->{_last_read_time}     = -1;
+  $self->{_first_line}         =  0;
   $self->{_date_column_index}  = undef;
 
-  # There are three intervals associated with each file.  The first is the
-  # data update interval.  This is the same interval used to generate the
-  # RRDs.  The second interval is the interval before the file is considered
-  # late and is larger than the data update interval.  This interval is
-  # calculated by using the mathematical expression given in the
-  # `late_interval' configuration option.  If `late_interval' is not defined,
-  # then it gets defaulted to the data update interval.  The last interval is
-  # the interval to use to tell the program when to attempt to read the file
-  # next.  Because it can take some time for the source files to be updated,
-  # we don't want to read the file immediately after the data update interval
-  # is done.  For this reason, choose a read interval that is somewhere in
-  # between the data source interval and the late interval.  Use the
-  # multiplicative average of the data update interval and the late interval
-  # since the resulting value is closer to the data update interval.  Ie:
-  # (20 + 5)/2 = 12.5.  Sqrt(20*5) = 10.
-  #
+  # There are three intervals associated with each file.  The first is
+  # the data update interval.  This is the same interval used to
+  # generate the RRDs.  The second interval is the interval before the
+  # file is considered late and is larger than the data update
+  # interval.  This interval is calculated by using the mathematical
+  # expression given in the `late_interval' configuration option.  If
+  # `late_interval' is not defined, then it gets defaulted to the data
+  # update interval.  The last interval is the interval to use to tell
+  # the program when to attempt to read the file next.  Because it can
+  # take some time for the source files to be updated, we don't want
+  # to read the file immediately after the data update interval is
+  # done.  For this reason, choose a read interval that is somewhere
+  # in between the data source interval and the late interval.  Use
+  # the multiplicative average of the data update interval and the
+  # late interval since the resulting value is closer to the data
+  # update interval.  Ie: (20 + 5)/2 = 12.5.  Sqrt(20*5) = 10.
   my $read_interval = sqrt($self->{_interval}*$self->{_late_interval});
   $self->{_read_interval} = int($read_interval + 0.5);
 
@@ -978,9 +1054,9 @@
     }
   }
 
-  # Test if the file has been updated in the last _invterval number of
-  # seconds.  If so, then note it so we can see when the file is no longer
-  # being updated.
+  # Test if the file has been updated in the last _interval number of
+  # seconds.  If so, then note it so we can see when the file is no
+  # longer being updated.
   $self->{_is_current} = $self->is_current;
 
   return unless $self->get_column_names;
@@ -989,6 +1065,19 @@
   $self;
 }
 
+# For each files key store make a note of the column description names
+# that appear.
+sub add_files_keys {
+  my $self = shift;
+
+  foreach my $files_key (@_) {
+    $self->{_files_keys}{$files_key} = 1;
+    foreach my $description (@{$self->{_column_description}}) {
+      $files_key_column_names{$files_key}{$description} = 1;
+    }
+  }
+}
+
 # Return 1 if the source data file is current or not.  Alsot note the
 # day that this test was performed.  This lets the code ignore files
 # that are not current because a new file was generated for the next
@@ -1001,16 +1090,17 @@
   $self->last_stat_time <= $self->file_mtime + $self->{_late_interval};
 }
 
-# This returns the time when the file should be next read.  To calculate
-# the next read time, take into the account the time that it takes for
-# the file to be updated.  In some sense, this is measured by the late
-# interval.  Because we won't want to use the complete late interval,
-# take the multiplicative average instead of the summation average, since
-# the multiplicative average will result in an average closer to the smaller
-# of the two values.  If the source file is current, then just add the
-# modified late interval to the last file modification time, otherwise
-# add the late interval to the last file stat time.  Use the late interval
-# to watch old files so we don't spend as much time on them.
+# This returns the time when the file should be next read.  To
+# calculate the next read time, take into the account the time that it
+# takes for the file to be updated.  In some sense, this is measured
+# by the late interval.  Because we won't want to use the complete
+# late interval, take the multiplicative average instead of the
+# summation average, since the multiplicative average will result in
+# an average closer to the smaller of the two values.  If the source
+# file is current, then just add the modified late interval to the
+# last file modification time, otherwise add the late interval to the
+# last file stat time.  Use the late interval to watch old files so we
+# don't spend as much time on them.
 sub next_load_time {
   my $self = shift;
 
@@ -1025,12 +1115,6 @@
   }
 }
 
-
-# This caches the reference to the array holding the column descriptions
-# for files that have their column descriptions in the first line of the
-# file.
-my %first_line_cache;
-
 sub get_column_names {
   my $self = shift;
 
@@ -1088,11 +1172,13 @@
   $self;
 }
 
-# These are caches for the different objects that are used to add a plot.
-my %all_rrds_cache;
-my %my_rrds_cache;
-
 sub add_plots {
+  # Make sure that the user has called the add_files_keys method and
+  # inserted at least one key.
+  unless (keys %files_key_column_names) {
+    confess "$0: Orca::SourceDataFile::add_files_keys must be called before add_plots.\n";
+  }
+
   unless (@_ == 8) {
     confess "$0: Orca::SourceDataFile::add_plots passed wrong number of arguments.\n";
   }
@@ -1106,10 +1192,17 @@
       $rrd_data_files_ref,
       $gif_files_ref) = @_;
 
-  # See if we have already done all the work for a plot with this files_key,
-  # group, and column description.  Use an MD5 hash instead of a very long
-  # key.
+  # See if we have already done all the work for a plot with this
+  # files_key, group, and column description.  Use an MD5 hash instead
+  # of a very long key.  Store into a hash the column names found in
+  # this file for this files key.  Finally, create a hash keyed by
+  # column name with a value of the index into the column description
+  # array.  for this files key.
   my @column_description = @{$self->{_column_description}};
+  my %column_description;
+  for (my $i=0; $i<@column_description; ++$i) {
+    $column_description{$column_description[$i]} = $i;
+  }
   my $plot_key  = join("\200", $files_key, $group, @column_description);
   my $cache_key = md5($plot_key);
   if (defined $all_rrds_cache{$cache_key}) {
@@ -1125,20 +1218,20 @@
   my $i                   = 0;
   my $old_i               = 0;
 
-  # This is the main loop where we keep looking for plots to create until
-  # all of the column descriptions have been compared against.
+  # This is the main loop where we keep looking for plots to create
+  # until all of the column descriptions have been compared against.
   while ($handle_regexps or $i < @$config_plots) {
-    # If we've reached an index value greater than the largest index in
-    # the plots, then reset the index to the oldest regexp that still needs
-    # to be completed.
+    # If we've reached an index value greater than the largest index
+    # in the plots, then reset the index to the oldest regexp that
+    # still needs to be completed.
     if ($handle_regexps and $i >= @$config_plots) {
       $i = $oldest_regexp_index;
     }
 
     my $plot = $config_plots->[$i];
 
-    # Skip this plot if the files_key do not match.  Increment the index
-    # of the next plot to handle.
+    # Skip this plot if the files_key do not match.  Increment the
+    # index of the next plot to handle.
     if ($plot->{source} ne $files_key) {
       if ($oldest_regexp_index == $i) {
         $handle_regexps = 0;
@@ -1148,14 +1241,15 @@
       next;
     }
 
-    # There are three cases to handle.  The first is a single data source
-    # with a single element that has a regular expression.  In this case,
-    # all of the columns are searched to match the regular expression.  The
-    # second case is two or more data sources and with one element in the
-    # first data source that has a regular expression match.  This may
-    # generate more than one plot, while the first one will only generate
-    # one plot.  The final case to handle is when the previous two cases
-    # are not true.  The last column matched on is stored in @regexp_pos.
+    # There are three cases to handle.  The first is a single data
+    # source with a single element that has a regular expression.  In
+    # this case, all of the columns are searched to match the regular
+    # expression.  The second case is two or more data sources and
+    # with one element in the first data source that has a regular
+    # expression match.  This may generate more than one plot, while
+    # the first one will only generate one plot.  The final case to
+    # handle is when the previous two cases are not true.  The last
+    # column matched on is stored in @regexp_pos.
     my $number_datas    = @{$plot->{data}};
     my $number_elements = @{$plot->{data}[0]};
     my $has_regexp      = $plot->{data}[0][0] =~ m:\(.+\):;
@@ -1174,30 +1268,29 @@
 
       # In this case we're creating a whole new plot that will have as
       # many data sources as their are columns that match the regular
-      # expression.  Start by making a deep copy of the plot.  Be careful
-      # not to make a deep copy of the creates reference, since it can
-      # cause recursion in the Data::Dump.
+      # expression.  Start by making a deep copy of the plot.  Be
+      # careful not to make a deep copy of the creates reference,
+      # since it can cause recursion.
       my $creates = delete $plot->{creates};
-      my $d = Data::Dumper->Dump([$plot], [qw(plot)]);
-      $plot->{creates} = $creates;
       {
-        local $SIG{__WARN__} = sub { die $_[0] };
-        eval $d;
+        my $new_plot = dclone($plot);
+        $plot->{creates} = $creates;
+        $new_plot->{creates} = $creates;
+        $plot = $new_plot;
       }
-      die "$0: internal error: eval on\n   $d\nOutput: $@\n" if $@;
 
       # At this point we have a copy of plot.  Now go through looking
-      # for all the columns that match and create an additional data source
-      # for each match.
+      # for all the columns that match and create an additional data
+      # source for each match.
       my $regexp = $plot->{data}[0][0];
       my $new_data_index = 0;
       my $original_legend = $plot->{legend}[0];
-      for (my $j=0; $j<@column_description; ++$j) {
-        my $column_name = $column_description[$j];
+      foreach my $column_name (@column_description) {
         my @matches = $column_name =~ /$regexp/;
         next unless @matches;
 
         $plot->{data}[$new_data_index] = [ $column_name ];
+
         # Copy any items over that haven't been created for this new
         # data source.  Make sure that any new elements added to
         # pcl_plot_append_elements show up here.
@@ -1266,9 +1359,9 @@
       # Make a deep copy of the plot.  In the string form of the plot
       # replace all of the $1, $2, ... with what was matched in the
       # first data source.  The tricky one is to replace the regular
-      # expression that did the match in the first place.  Also, save a
-      # copy of the creates array for this plot so it doesn't also get
-      # dumped.
+      # expression that did the match in the first place.  Also, save
+      # a copy of the creates array for this plot so it doesn't also
+      # get dumped.
       my $creates      =  delete $plot->{creates};
       my $d            =  Data::Dumper->Dump([$plot], [qw(plot)]);
       $plot->{creates} =  $creates;
@@ -1285,7 +1378,8 @@
       }
       die "$0: internal error: eval on\n   $d\nOutput: $@\n" if $@;
 
-      # Either increment the index or reset it to the oldest regexp index.
+      # Either increment the index or reset it to the oldest regexp
+      # index.
       $old_i = $i;
       $i = $plot->{flush_regexps} ? $oldest_regexp_index : $i + 1;
     }
@@ -1294,110 +1388,126 @@
       ++$oldest_regexp_index unless $handle_regexps;
     }
 
-    # Convert the column names to an index into the @_ array.  Make a copy
-    # of the commands so that if we change anything, we're not changing the
-    # original plot structure.
-    my @column_commands;
-    foreach my $command (@{$plot->{data}}) {
-      push(@column_commands, [@$command]);
+    # Make a copy of the data's so that if we change anything, we're
+    # not changing the original plot structure.  Look through each
+    # element of each data and look for names appearing in the column
+    # description array.  If there is a match for this file, then
+    # convert the element to an index the @_ array where the data will
+    # be pulled from.  If there is not a match, then see if the
+    # element matches a name from one of the other column names from
+    # the same files key.  In this case the data argument for this
+    # file will not be used.
+    my @datas;
+    my $optional = $plot->{optional};
+    foreach my $one_data (@{$plot->{data}}) {
+      push(@datas, [@$one_data]);
     }
     my $match_any = 0;
-    for (my $j=0; $j<@column_commands; $j++) {
-      my $match_command = 0;
-      for (my $k=0; $k<@{$column_commands[$j]}; ++$k) {
-        my $element = $column_commands[$j][$k];
-        for (my $l=0; $l<@column_description; ++$l) {
-          if ($element eq $column_description[$l]) {
-            $column_commands[$j][$k] = "\$_[$l]";
-            $match_command = 1;
-          }
+    for (my $j=0; $j<@datas; $j++) {
+      my $match_one_data = 0;
+      for (my $k=0; $k<@{$datas[$j]}; ++$k) {
+        my $element = $datas[$j][$k];
+        my $pos;
+        if (defined ($pos = $column_description{$element})) {
+          $datas[$j][$k] = "\$_[$pos]";
+          $match_one_data = 1;
+        }
+        elsif (defined $files_key_column_names{$files_key}{$element}) {
+          my $m = $old_i + 1;
+          warn "$0: $element in `data @{$plot->{data}[$j]}' in plot #$m not replaced since it is not in file `" . $self->filename . "'.\n" unless $optional;
+          $datas[$j] = undef;
+          last;
         }
       }
       # If there were no substitutions, then warn about it.
-      if (!$match_command and !$plot->{optional}) {
+      if (!$match_one_data and !$optional) {
         my $m = $old_i + 1;
-        warn "$0: warning: no substitutions performed for `@{$column_commands[$j]}' in plot #$m.\n";
+        warn "$0: warning: no substitutions performed for `data @{$plot->{data}[$j]}' in plot #$m in `" . $self->filename . "'.\n";
       }
-      $match_any = $match_any || $match_command;
+      $match_any = $match_any || $match_one_data;
     }
 
-    # Skip this plot if no matches were found and the the plot
-    # is optional.
-    next if (!$match_any and $plot->{optional});
+    # Skip this plot if no matches were found and the plot is
+    # optional.
+    next if (!$match_any and $optional);
 
     # At this point we have a plot to create.
 
-    # For each data source, create an executable subroutine that takes a
-    # row of elements and returns the requested value.  Also create an
-    # unique Orca data file name for this plot and a name for this plot
-    # that does not include the group.
+    # For each data source, create an executable subroutine that takes
+    # a row of elements and returns the requested value.  Also create
+    # an unique Orca data file name for this plot and a name for this
+    # plot that does not include the group.
     my @my_rrds;
     my @no_group_name;
     my @group_name;
-    for (my $j=0; $j<@column_commands; ++$j) {
+    for (my $j=0; $j<@datas; ++$j) {
 
-      my $expr      = "sub {\n  return @{$column_commands[$j]};\n}\n";
-      my $expr_hash = md5($expr);
-
-      my $choose_data_sub;
+      my $working_data    = defined $datas[$j];
+      my $choose_data_sub = undef;
       my $data_name = join('_', @{$plot->{data}[$j]});
-      if (defined $read_value_subs{$expr_hash}) {
-        $choose_data_sub = $read_value_subs{$expr_hash};
-      }
-      else {
-        {
-          local $SIG{__WARN__} = sub { die $_[0] };
-          $choose_data_sub     = eval $expr;
-        }
-        if ($@) {
-          unless ($plot->{optional}) {
-            my $m = $old_i + 1;
-            warn "$0: warning: bad evaluation of commands for plot #$m.\nOutput: $@\n";
+
+      if ($working_data) {
+        my $expr      = "sub {\n  return @{$datas[$j]};\n}\n";
+        my $expr_hash = md5($expr);
+
+        unless (defined ($choose_data_sub = $read_value_subs{$expr_hash})) {
+          {
+            local $SIG{__WARN__} = sub { die $_[0] };
+            $choose_data_sub     = eval $expr;
+          }
+          if ($@) {
+            unless ($optional) {
+              my $m = $old_i + 1;
+              warn "$0: warning: bad evaluation of commands for plot #$m `data @{$plot->{data}[$j]}'.\nOutput: $@\n";
+            }
+            $choose_data_sub = undef;
+          }
+          else {
+            $read_value_subs{$expr_hash} = $choose_data_sub;
           }
-          $choose_data_sub = sub { 0; };
-          $data_name       = 'ALL_ZEROS';
         }
-        $read_value_subs{$expr_hash} = $choose_data_sub;
       }
 
       my $name = "${files_key}_${group}_${data_name}";
       push(@no_group_name, "${files_key}_${data_name}");
       push(@group_name, $name);
 
-      # Create a new RRD only if it doesn't already exist.
-      unless (defined $rrd_data_files_ref->{$name}) {
-        my $rrd_file = Orca::RRDFile->new($config_options,
-                                           $config_files,
-                                           $files_key,
-                                           $group,
-                                           $name,
-                                           $plot,
-                                           $choose_data_sub);
-        $rrd_data_files_ref->{$name} = $rrd_file;
-      }
-      $self->{_all_rrd_ref} = $rrd_data_files_ref;
-      $self->{_my_rrd_hash}{$name}++;
-      push(@my_rrds, $name);
+      # Create a new RRD only if it doesn't already exist and if a
+      # valid get data subroutine is created.
+      if ($choose_data_sub) {
+        unless (defined $rrd_data_files_ref->{$name}) {
+          my $rrd_file = Orca::RRDFile->new($config_options,
+                                            $config_files,
+                                            $files_key,
+                                            $group,
+                                            $name,
+                                            $plot,
+                                            $choose_data_sub);
+          $rrd_data_files_ref->{$name} = $rrd_file;
+        }
+        $self->{_all_rrd_ref} = $rrd_data_files_ref;
+        $self->{_my_rrd_hash}{$name}++;
+        push(@my_rrds, $name);
+      }
     }
 
     # Generate a new plot for these data.
     my $gif;
     my $group_name = join(',', @group_name);
-    if (defined $gif_files_ref->{hash}{$group_name}) {
-      $gif = $gif_files_ref->{hash}{$group_name};
+    if (defined ($gif = $gif_files_ref->{hash}{$group_name})) {
       $gif->add_rrds(@my_rrds);
     }
     else {
       $gif = Orca::GIFFile->new($config_options,
-                                 $config_files,
-                                 $config_plots,
-                                 $files_key,
-                                 $group,
-                                 join(',', @my_rrds),
-                                 join(',', @no_group_name),
-                                 $plot,
-                                 $rrd_data_files_ref,
-                                 \@my_rrds);
+                                $config_files,
+                                $config_plots,
+                                $files_key,
+                                $group,
+                                join(',', @my_rrds),
+                                join(',', @no_group_name),
+                                $plot,
+                                $rrd_data_files_ref,
+                                \@my_rrds);
       $gif_files_ref->{hash}{$group_name} = $gif;
       push(@{$gif_files_ref->{list}}, $gif);
       push(@{$config_plots->[$old_i]{creates}}, $gif);
@@ -1420,9 +1530,10 @@
 
   my $filename = $self->filename;
 
-  # Test to see if we should read the file.  If the file has changed in
-  # any way, then read it.  If the file is now gone and we have an open
-  # file descriptor for it, then read to the end of it and then close it.
+  # Test to see if we should read the file.  If the file has changed
+  # in any way, then read it.  If the file is now gone and we have an
+  # open file descriptor for it, then read to the end of it and then
+  # close it.
   my $file_status = $self->status;
   my $fd          = $::open_file_cache->get_fd($filename);
   my $load_data   = $file_status != 0;
@@ -1436,9 +1547,9 @@
     }
   }
 
-  # Test if the file was up to date and now is not.  If so, then send a
-  # message.  Do not send a message if the file was current in the previous
-  # day is now is not current today.
+  # Test if the file was up to date and now is not.  If so, then send
+  # a message.  Do not send a message if the file was current in the
+  # previous day is now is not current today.
   my $old_is_current     = $self->{_is_current};
   my $old_is_current_day = $self->{_is_current_day};
   my $current_day        = (localtime($self->last_stat_time))[3];
@@ -1474,8 +1585,9 @@
 
   return 0 unless $load_data;
 
-  # Try to get a file descriptor to open the file.  Skip the first line
-  # if the first line is used for column descriptions.
+  # Try to get a file descriptor to open the file.  Skip the first
+  # line if the first line is used for column descriptions.
+
   my $opened_new_fd = !$fd;
   unless ($fd) {
     unless ($fd = $::open_file_cache->open($filename, $file_mtime)) {
@@ -1493,9 +1605,9 @@
   while (my $line = <$fd>) {
     my @line = split(' ', $line);
 
-    # Skip this input line if 1) the file uses the first line to define the
-    # column names, 2) the number of columns loaded is not equal to the
-    # number of columns in the column description.
+    # Skip this input line if 1) the file uses the first line to
+    # define the column names, 2) the number of columns loaded is not
+    # equal to the number of columns in the column description.
     if ($self->{_first_line} and @line != @{$self->{_column_description}}) {
       warn "$0: number of columns in line $. of `$filename' does not match column description.\n";
       next;
@@ -1504,9 +1616,10 @@
     my $time = $use_file_mtime ? $self->file_mtime : $line[$date_column_index];
     $last_data_time = $time if $time > $last_data_time;
 
-    # If the file status from the source data file is greater than zero, then
-    # it means the file has changed in some way, so we need to do updates for
-    # all plots.  Load the available data and push it to the plots.
+    # If the file status from the source data file is greater than
+    # zero, then it means the file has changed in some way, so we need
+    # to do updates for all plots.  Load the available data and push
+    # it to the plots.
     my $add = 0;
     foreach my $rrd_key (keys %{$self->{_my_rrd_hash}}) {
       my $result = $self->{_all_rrd_ref}{$rrd_key}->queue_data($time, @line);
@@ -1529,18 +1642,19 @@
 
   $::open_file_cache->change_weight($filename, $file_mtime);
 
-  # Now two special cases to handle.  First, if the file was removed and
-  # we had an open file descriptor to it, then close the file descriptor.
-  # Second, if the file has a new device number or inode and we had a
-  # already opened file descriptor to the file, then close the descriptor,
-  # reopen it and read all the rest of the data.  If neither of these
-  # cases is true, then close the file if the file should be reopened
-  # next time.
+  # Now two special cases to handle.  First, if the file was removed
+  # and we had an open file descriptor to it, then close the file
+  # descriptor.  Second, if the file has a new device number or inode
+  # and we had a already opened file descriptor to the file, then
+  # close the descriptor, reopen it and read all the rest of the data.
+  # If neither of these cases is true, then close the file if the file
+  # should be reopened next time.
   if ($file_status == -1 or ($file_status == 2 and !$opened_new_fd)) {
     $::open_file_cache->close($filename) or
       warn "$0: warning: cannot close `$filename' for reading: $!\n";
     if ($file_status != -1) {
-      # Setting the last_read_time to -1 will force load_new_data to read it.
+      # Setting the last_read_time to -1 will force load_new_data to
+      # read it.
       $self->{_last_read_time} = -1;
       $number_added += $self->load_new_data;
     }
@@ -1559,15 +1673,28 @@
 
 package main;
 
+sub Usage {
+  die "usage: $0 [-o] [-v] config_file\n";
+}
+
 while (@ARGV and $ARGV[0] =~ /^-\w/) {
   my $arg = shift;
-  ++$opt_verbose   if $arg eq '-v';
-  ++$opt_once_only if $arg eq '-o';
+  if ($arg eq '-o') {
+    ++$opt_once_only;
+  }
+  elsif ($arg eq '-v') {
+    ++$opt_verbose;
+  }
+  else {
+    Usage;
+  }
 }
 
-die "usage: $0 [-o] [-v] config_file\n" unless @ARGV;
+Usage unless @ARGV;
 
-print "Orca Version $VERSION.\n" if $opt_verbose;
+if ($opt_verbose) {
+  print "Orca version $VERSION using RRDs version $RRDs::VERSION.\n";
+}
 
 &main(@ARGV);
 
@@ -1662,13 +1789,13 @@
   my $find_new_files = 1;
   my $time_interval  = get_time_interval($config_options->{find_times});
 
-  # This hash holds the next time to load the data from all the files in
-  # a particular group.
+  # This hash holds the next time to load the data from all the files
+  # in a particular group.
   my %group_load_time;
 
   for (;;) {
-    # If Orca is being forced to find new files, then set up the variables
-    # here.  Determine the current time interval we're in.
+    # If Orca is being forced to find new files, then set up the
+    # variables here.  Determine the current time interval we're in.
     if ($force_find_files) {
       $force_find_files = 0;
       $find_new_files   = 1;
@@ -1683,9 +1810,9 @@
               scalar localtime, ".\n";
       }
 
-      # Get the list of files to watch and the plots that will be created.
-      # If files have been previously found, then use those files in the
-      # search for new ones.
+      # Get the list of files to watch and the plots that will be
+      # created.  If files have been previously found, then use those
+      # files in the search for new ones.
       $old_found_files_ref = $new_found_files_ref if $new_found_files_ref;
       ($found_new_files, $new_found_files_ref, $group_files_ref) =
          &find_files($config_filename,
@@ -1697,8 +1824,8 @@
                      $rrd_data_files_ref,
                      $gif_files_ref);
 
-      # Go through all of the groups and for each group and all of the files
-      # in the group find the next load time in the future.
+      # Go through all of the groups and for each group and all of the
+      # files in the group find the next load time in the future.
       undef %group_load_time;
       foreach my $group (keys %$group_files_ref) {
         my $group_load_time = 1e20;
@@ -1760,7 +1887,8 @@
       $group_load_time{$group} = $group_load_time;
 
       # Now that the source data files have been read, recalculate the
-      # time to sleep to if the load time for this group is in the future.
+      # time to sleep to if the load time for this group is in the
+      # future.
       if (time < $group_load_time) {
         $sleep_till_time = $group_load_time unless $sleep_till_time;
         $sleep_till_time = $group_load_time if $group_load_time < $sleep_till_time;
@@ -1769,11 +1897,11 @@
       next unless $number_new_data_points;
       $updated_source_files = 1;
 
-      # Flush the data that has been loaded for each plot.  To keep the
-      # RRD that was just created in the system's cache, plot GIFs that
-      # only depend on this RRD, since GIFs that depend upon two or more
-      # RRDs will most likely be generated more than once and the other
-      # required RRDs may not exist yet.
+      # Flush the data that has been loaded for each plot.  To keep
+      # the RRD that was just created in the system's cache, plot GIFs
+      # that only depend on this RRD, since GIFs that depend upon two
+      # or more RRDs will most likely be generated more than once and
+      # the other required RRDs may not exist yet.
       if ($opt_verbose) {
         print "Flushing new data", $group ? " from $group" : "", ".\n";
       }
@@ -1811,18 +1939,19 @@
     # Return now if this loop is being run only once.
     last if $opt_once_only;
 
-    # Now decide if we need to find new files.  If the time interval does
-    # change, then find new files only if the new time interval is not -1,
-    # which signifies that the time is before the first find_times.
+    # Now decide if we need to find new files.  If the time interval
+    # does change, then find new files only if the new time interval
+    # is not -1, which signifies that the time is before the first
+    # find_times.
     my $new_time_interval = get_time_interval($config_options->{find_times});
     if ($time_interval != $new_time_interval) {
       $find_new_files = 1 if $new_time_interval != -1;
       $time_interval  = $new_time_interval;
     }
 
-    # Sleep if the sleep_till_time has not passed.  If sleep_till_time is
-    # now defined, then loop immediately.  Sleep at least one second if
-    # we need to sleep at all.
+    # Sleep if the sleep_till_time has not passed.  If sleep_till_time
+    # is now defined, then loop immediately.  Sleep at least one
+    # second if we need to sleep at all.
     if ($sleep_till_time) {
       my $now = time;
       if ($sleep_till_time > $now) {
@@ -1901,137 +2030,145 @@
   }
   $index_html->print("<hr>\n<font size=\"-2\">");
 
-  # The first step is to create the HTML files for each different group.
-  # This is only done if there is more than one group gathered from the
-  # configuration and input data files.  If there is more than one group
-  # first list the different available groups and create for each group
-  # an HTML file that contains HREFs to the GIFs for that group.  Also
-  # create an HTML file for the daily, weekly, monthly, and yearly GIFs.
+  # The first step is to create the HTML files for each different
+  # group.  This is only done if there is more than one group gathered
+  # from the configuration and input data files.  If there is more
+  # than one group first list the different available groups and
+  # create for each group an HTML file that contains HREFs to the GIFs
+  # for that group.  Also create an HTML file for the daily, weekly,
+  # monthly, and yearly GIFs.
 
-  # This variable sets the number of groups to place into a single row.
+  # This variable sets the number of groups to place into a single
+  # row.
   my $table_number_columns = 9;
   my @table_columns;
 
-  # Go through each group.
-  if (keys %$group_files_ref > 1) {
-    $index_html->print("<h2>Available Targets</h2>\n\n<table>\n");
-    foreach my $group (sort sort_group_names keys %$group_files_ref) {
-
-      # Create the HTML code for the main index.html file.
-      my $group_basename = strip_key_name($group);
-      my $element = "<table border=2><tr><td><b>$group</b></td></tr>\n<tr><td>\n";
-      foreach my $plot_type (@rra_plot_type) {
-        $element      .= "<a href=\"$group_basename-$plot_type.html\">";
-        my $Plot_Type  = Capatialize($plot_type);
-        $element      .= "$Plot_Type</a><br>\n";
-      }
-      $element .= "<a href=\"$group_basename-all.html\">All</a></td></tr>\n";
-      $element .= "</table>\n\n";
-
-      push(@table_columns, "<td>$element</td>");
-      if (@table_columns == $table_number_columns) {
-        $index_html->print("<tr valign=top>" . join('', @table_columns) . "</tr>\n");
-        @table_columns = ();
-      }
-
-      # Create the daily, weekly, monthly, yearly, and all HTML files for
-      # this group.
-      my @html_files;
-      foreach my $plot_type (@rra_plot_type, 'all') {
-        my $href      = "$group_basename-$plot_type.html";
-        my $filename  = "$html_dir/$href";
-        my $Plot_Type = Capatialize($plot_type);
-        my $fd = Orca::HTMLFile->new($filename,
-                                     "$Plot_Type $group",
-                                     $config_options->{html_page_header},
-                                     $config_options->{html_page_footer});
-        unless ($fd) {
-          warn "$0: warning: cannot open `$filename' for writing: $!\n";
-          next;
-        }
-        push (@html_files, {fd        => $fd,
-                            href      => $href,
-                            plot_type => $plot_type,
-                            Plot_Type => $Plot_Type});
-      }
-
-      # At the top of the daily, weekly, monthly, yearly, and all HTML files
-      # add HREFs to the other date span HTML files in the same group
-      my $href_html;
-      foreach my $plot_type (@html_files) {
-        $href_html .= "<a href=\"$plot_type->{href}\">" .
-                      "$plot_type->{Plot_Type} $group</a><br>\n";
+  # Go through each group.  If there is only one group and that group
+  # does not have a name, then give the group the name Everything.
+  # However, only refer to the name Everything in naming HTML files
+  # and in HTML content.  Use the original group name as a hash key.
+  my $number_groups = keys %$group_files_ref;
+  $index_html->print("<h2>Available Targets</h2>\n\n<table>\n");
+  foreach my $group (sort sort_group_names keys %$group_files_ref) {
+    my $html_group = ($number_groups == 1 and !$group) ? 'Everything' : $group;
+
+    # Create the HTML code for the main index.html file.
+    my $group_basename = strip_key_name($html_group);
+    my $element = "<table border=2><tr><td><b>$html_group</b></td></tr>\n<tr><td>\n";
+    foreach my $plot_type (@rra_plot_type) {
+      $element      .= "<a href=\"$group_basename-$plot_type.html\">";
+      my $Plot_Type  = Capatialize($plot_type);
+      $element      .= "$Plot_Type</a><br>\n";
+    }
+    $element .= "<a href=\"$group_basename-all.html\">All</a></td></tr>\n";
+    $element .= "</table>\n\n";
+
+    push(@table_columns, "<td>$element</td>");
+    if (@table_columns == $table_number_columns) {
+      $index_html->print("<tr valign=top>" . join('', @table_columns) . "</tr>\n");
+      @table_columns = ();
+    }
+
+    # Create the daily, weekly, monthly, yearly, and all HTML files
+    # for this group.
+    my @html_files;
+    foreach my $plot_type (@rra_plot_type, 'all') {
+      my $href      = "$group_basename-$plot_type.html";
+      my $filename  = "$html_dir/$href";
+      my $Plot_Type = Capatialize($plot_type);
+      my $fd = Orca::HTMLFile->new($filename,
+                                   "$Plot_Type $html_group",
+                                   $config_options->{html_page_header},
+                                   $config_options->{html_page_footer});
+      unless ($fd) {
+        warn "$0: warning: cannot open `$filename' for writing: $!\n";
+        next;
+      }
+      push (@html_files, {fd        => $fd,
+                          href      => $href,
+                          plot_type => $plot_type,
+                          Plot_Type => $Plot_Type});
+    }
+
+    # At the top of the daily, weekly, monthly, yearly, and all HTML
+    # files add HREFs to the other date span HTML files in the same
+    # group.
+    my $href_html;
+    foreach my $plot_type (@html_files) {
+      $href_html .= "<a href=\"$plot_type->{href}\">" .
+                    "$plot_type->{Plot_Type} $group</a><br>\n";
+    }
+    foreach my $html_file (@html_files) {
+      $html_file->{fd}->print($href_html);
+    }
+
+    # Use only those GIFs now that have the same group name as the
+    # HTML files that are being created.
+    my @gifs = grep {$group eq $_->group} @{$gif_files_ref->{list}};
+    if (@gifs > 1) {
+      my $href_html = "<hr>";
+      for (my $i=0; $i<@gifs; ++$i) {
+        $href_html .= "<a href=\"#$i\">[" .
+                      replace_group_name($gifs[$i]->plot_ref->{title}, '') .
+                      "]</a><spacer size=10>\n";
       }
       foreach my $html_file (@html_files) {
         $html_file->{fd}->print($href_html);
       }
+    }
 
-      # Use only those GIFs now that have the same group name as the HTML
-      # files that are being created.
-      my @gifs = grep {$group eq $_->group} @{$gif_files_ref->{list}};
-      if (@gifs > 1) {
-        my $href_html = "<hr>";
-        for (my $i=0; $i<@gifs; ++$i) {
-          $href_html .= "<a href=\"#$i\">[" .
-                        replace_group_name($gifs[$i]->plot_ref->{title}, '') .
-                        "]</a><spacer size=10>\n";
-        }
-        foreach my $html_file (@html_files) {
-          $html_file->{fd}->print($href_html);
-        }
-      }
+    # Add the images to the HTML files.
+    for (my $i=0; $i<@gifs; ++$i) {
+      my $gif      = $gifs[$i];
+      my $name     = $gif->name;
+      my $title    = replace_group_name($gif->plot_ref->{title}, $gif->group);
+      my $href     = "href=\"" . strip_key_name($name) . ".html\"";
+      my $sub_dir  = $config_files->{$gif->files_key}{sub_dir};
+      my $gif_size = $gif->gif_img_src_size;
 
-      # Add the images to the HTML files.
-      for (my $i=0; $i<@gifs; ++$i) {
-        my $gif = $gifs[$i];
-        my $name    = $gif->name;
-        my $title   = replace_group_name($gif->plot_ref->{title}, $gif->group);
-        my $href    = "href=\"" . strip_key_name($name) . ".html\"";
-        my $sub_dir = $config_files->{$gif->files_key}{sub_dir};
-
-        foreach my $html_file (@html_files) {
-          $html_file->{fd}->print("<hr>\n<h2><a ${href} name=\"$i\">$html_file->{Plot_Type} " .
-                                  "$title</a></h2>\n");
-        }
-
-        # Put the proper GIFs into each HTML file.  The all HTML file is
-        # listed last and requires special handling.
-        for (my $j=0; $j<@html_files-1; ++$j) {
-          my $gif_filename = "$name-$html_files[$j]{plot_type}.gif";
-          $gif_filename = "$group/$gif_filename" if $sub_dir;
-          my $html = "<a $href><img src=\"$gif_filename\"" .
-                     "alt=\"$html_files[$j]{Plot_Type} $title\"></a>\n";
-          $html_files[$j]{fd}->print($html);
-          $html_files[-1]{fd}->print($html);
-        }
+      foreach my $html_file (@html_files) {
+        $html_file->{fd}->print("<hr>\n<h2><a ${href} name=\"$i\">$html_file->{Plot_Type} " .
+                                "$title</a></h2>\n");
       }
 
-      foreach my $html_file (@html_files) {
-        $html_file->{fd}->print("<hr>\n");
+      # Put the proper GIFs into each HTML file.  The all HTML file is
+      # listed last and requires special handling.
+      for (my $j=0; $j<@html_files-1; ++$j) {
+        my $gif_filename = "$name-$html_files[$j]{plot_type}.gif";
+        $gif_filename = "$group/$gif_filename" if $sub_dir;
+        my $html = "<a $href><img src=\"$gif_filename\" $gif_size " .
+                   "alt=\"$html_files[$j]{Plot_Type} $title\"></a>\n";
+        $html_files[$j]{fd}->print($html);
+        $html_files[-1]{fd}->print($html);
       }
     }
 
-    # If there are any remaining groups to display, do it now.
-    if (@table_columns) {
-      $index_html->print("<tr valign=top>" .
-                         join('', @table_columns) .
-                         "</tr>\n");
+    foreach my $html_file (@html_files) {
+      $html_file->{fd}->print("<hr>\n");
     }
-    $index_html->print("</table>\n\n\n<br>\n<hr>\n" .
-                       "<h2>Available Data Sets</h2>\n\n");
   }
 
-  # Here the different available plots are listed and the HTML files created
-  # that contain the HREFs to the proper GIFs.  The HTML files created here
-  # HREF to the GIFs that are created for a single plot.  There are several
-  # steps to do here.  First, get a list of the different plots.  For each
-  # different type of plot, create a list GIFs that show that plot.  Use
-  # the @gifs_by_type array to keep the ordering in the type of GIFs and
-  # the %gifs_by_type to hold references to an array for each type of GIF.
+  # If there are any remaining groups to display, do it now.
+  if (@table_columns) {
+    $index_html->print("<tr valign=top>" .
+                       join('', @table_columns) .
+                       "</tr>\n");
+  }
+  $index_html->print("</table>\n\n\n<br>\n<hr>\n" .
+                     "<h2>Available Data Sets</h2>\n\n");
+
+  # Here the different available plots are listed and the HTML files
+  # created that contain the HREFs to the proper GIFs.  The HTML files
+  # created here HREF to the GIFs that are created for a single plot.
+  # There are several steps to do here.  First, get a list of the
+  # different plots.  For each different type of plot, create a list
+  # GIFs that show that plot.  Use the @gifs_by_type array to keep the
+  # ordering in the type of GIFs and the %gifs_by_type to hold
+  # references to an array for each type of GIF.
   $index_html->print("<table>\n");
 
-  # This sets the number of plot types to place into a single row in the
-  # main index.html.
+  # This sets the number of plot types to place into a single row in
+  # the main index.html.
   $table_number_columns = 1;
   @table_columns = ();
 
@@ -2040,13 +2177,14 @@
 
     next unless @{$config_plots->[$i]{creates}};
 
-    # Create an ordered list of GIFs sorted on the legend name for each
-    # GIF.  Remember, each GIF represented here actually represents the
-    # set of daily, weekly, monthly, and yearly GIF files.
-    # %gif_legend_no_group is a hash keyed by the GIF that contains the
-    # legend with no group substitution for the GIF.  The %legends hash
-    # is keyed by the legend name with no group substitution and contains
-    # a reference to an array of GIFs that have the same legend name.
+    # Create an ordered list of GIFs sorted on the legend name for
+    # each GIF.  Remember, each GIF represented here actually
+    # represents the set of daily, weekly, monthly, and yearly GIF
+    # files.  %gif_legend_no_group is a hash keyed by the GIF that
+    # contains the legend with no group substitution for the GIF.  The
+    # %legends hash is keyed by the legend name with no group
+    # substitution and contains a reference to an array of GIFs that
+    # have the same legend name.
     my %gif_legend_no_group;
     my %same_legends_gif_list;
     foreach my $gif (@{$config_plots->[$i]{creates}}) {
@@ -2060,8 +2198,8 @@
     }
 
     # Put together the correctly ordered list of GIFs using the array
-    # references in the legends hash.  Sort the GIFs using the
-    # special sorting routine for group names.
+    # references in the legends hash.  Sort the GIFs using the special
+    # sorting routine for group names.
     my @gifs;
     foreach my $legend_no_group (sort keys %same_legends_gif_list) {
       @{$same_legends_gif_list{$legend_no_group}} =
@@ -2080,13 +2218,15 @@
       my $no_group_name   = strip_key_name($gif->no_group_name);
       my $legend_no_group = $gif_legend_no_group{$gif};
 
-      # If this is the first time that this legend has been seen in for
-      # creating the proper HTML files, then create the new HTML files
-      # and set up the top of them properly and place into the main
-      # index.html the proper HREFs to these files.
+      # If this is the first time that this legend has been seen in
+      # for creating the proper HTML files, then create the new HTML
+      # files and set up the top of them properly and place into the
+      # main index.html the proper HREFs to these files.
       unless (defined $legend_html_files{$legend_no_group}) {
-        # Now create the HTML files for the daily, weekly, monthly, yearly,
-        # and all plots.  Use the legend name to create this list.
+
+        # Now create the HTML files for the daily, weekly, monthly,
+        # yearly, and all plots.  Use the legend name to create this
+        # list.
         $legend_html_files{$legend_no_group} = [];
         foreach my $plot_type (@rra_plot_type, 'all') {
           my $href      = "$no_group_name-$plot_type.html";
@@ -2107,10 +2247,10 @@
                 Plot_Type => $Plot_Type});
         }
 
-        # For each of the daily, weekly, monthy, yearly and all HTML files
-        # add at the top of the file HREFs to all of the daily, weekly,
-        # monthly, yearly and all HTML files.  Also add HREFs to the
-        # different groups later on in the same HTML file.
+        # For each of the daily, weekly, monthy, yearly and all HTML
+        # files add at the top of the file HREFs to all of the daily,
+        # weekly, monthly, yearly and all HTML files.  Also add HREFs
+        # to the different groups later on in the same HTML file.
         my @legend_html_files = @{$legend_html_files{$legend_no_group}};
         my $href_html;
         foreach my $plot_type (@legend_html_files) {
@@ -2118,9 +2258,10 @@
                         "$plot_type->{Plot_Type} $legend_no_group</a><br>\n";
         }
 
-        # Add to the top of the file HREFs to all of the different groups in
-        # the HTML file.  This makes traversing the HTML page easier.  Do
-        # this if there are two or more groups in this HTML page.
+        # Add to the top of the file HREFs to all of the different
+        # groups in the HTML file.  This makes traversing the HTML
+        # page easier.  Do this if there are two or more groups in
+        # this HTML page.
         if (@{$same_legends_gif_list{$legend_no_group}} > 1) {
           $href_html .= "<hr>\n";
           foreach my $legend_gif (@{$same_legends_gif_list{$legend_no_group}}) {
@@ -2146,10 +2287,11 @@
         }
       }
 
-      # At this point the HTML files for this set of daily, weekly, monthly,
-      # and yearly GIFs have been opened.  Now create the summary HTML
-      # file that contains only four GIF images, the daily, weekly, monthly,
-      # and yearly GIFs for a particular plot for a particular group.
+      # At this point the HTML files for this set of daily, weekly,
+      # monthly, and yearly GIFs have been opened.  Now create the
+      # summary HTML file that contains only four GIF images, the
+      # daily, weekly, monthly, and yearly GIFs for a particular plot
+      # for a particular group.
       my $with_group_name   = strip_key_name($gif->name);
       my $legend_with_group = replace_group_name($gif->plot_ref->{title},
                                                  $gif->group);
@@ -2165,10 +2307,12 @@
       my $sub_dir      = $config_files->{$gif->files_key}{sub_dir};
       my $gif_filename = $with_group_name;
       $gif_filename    = $gif->group . "/$gif_filename" if $sub_dir;
+      my $gif_size     = $gif->gif_img_src_size;
       foreach my $plot_type (@rra_plot_type) {
         my $Plot_Type = Capatialize($plot_type);
         $summarize_html->print("<hr>\n<h2>$Plot_Type $legend_with_group</h2>\n",
                                "<img src=\"$gif_filename-$plot_type.gif\"",
+                               $gif_size,
                                "alt=\"$Plot_Type $legend_with_group\">\n");
       }
 
@@ -2184,7 +2328,7 @@
         my $Plot_Type    = $legend_html_files[$i]{Plot_Type};
         my $gif_filename = "$name-$legend_html_files[$i]{plot_type}.gif";
         $gif_filename    = "$group/$gif_filename" if $sub_dir;
-        my $html = "<a $href><img src=\"$gif_filename\"" .
+        my $html = "<a $href><img src=\"$gif_filename\" $gif_size " .
                    "alt=\"$Plot_Type $group $legend_no_group\"></a>\n";
         $legend_html_files[$i]{fd}->print("<hr>\n<h2><a ${href} name=\"$group\">$Plot_Type $group $legend_no_group</a></h2>\n");
         $legend_html_files[$i]{fd}->print($html);
@@ -2202,7 +2346,8 @@
 sub perl_glob {
   my $regexp = shift;
 
-  # The current directory tells where to open the directory for matching.
+  # The current directory tells where to open the directory for
+  # matching.
   my $current_dir = @_ ? shift : '.';
 
   # Remove all multiple /'s, since they will confuse perl_glob.
@@ -2212,32 +2357,37 @@
   # regular expression and set the current directory to /.
   $current_dir = '/' if $regexp =~ s:^/::;
 
-  # Get the first file path element from the regular expression to match.
+  # Get the first file path element from the regular expression to
+  # match.
   my @regexp_elements = split(m:/:, $regexp);
   my $first_regexp = shift(@regexp_elements);
 
-  # Find all of the files in the current directory that match the first
-  # regular expression.
-  opendir(GLOB_DIR, "$current_dir") or
-    die "$0: error: cannot opendir `$current_dir': $!\n";
+  # Find all of the files in the current directory that match the
+  # first regular expression.
+  unless (opendir(GLOB_DIR, "$current_dir")) {
+    warn "$0: error: cannot opendir `$current_dir': $!\n";
+    return ();
+  }
 
   my @matches = grep { /^$first_regexp$/ } readdir(GLOB_DIR);
 
   closedir(GLOB_DIR) or
     warn "$0: warning: cannot closedir `$current_dir': $!\n";
 
-  # If we're in the last regular expression match, then just return the
-  # matches with the current directory prepended.
+  # If the last path element is being used as the regular expression,
+  # then just return the list of matching files with the current
+  # directory prepended.
   unless (@regexp_elements) {
-    return map { "$current_dir/$_" } @matches;
+    return grep { -f } map { "$current_dir/$_" } @matches;
   }
 
   # Otherwise we need to look into the directories below the current
-  # directory.  Also create the next regular expression to use that
-  # is made up of the remaining file path elements.
+  # directory.  Also create the next regular expression to use that is
+  # made up of the remaining file path elements.  Make sure not to
+  # process any directories named `..'.
   my @results;
   my $new_regexp = join('/', @regexp_elements);
-  foreach my $new_dir (grep { -d "$current_dir/$_" } @matches) {
+  foreach my $new_dir (grep { $_ ne '..' and -d "$current_dir/$_" } @matches) {
     my $new_current = "$current_dir/$new_dir";
     $new_current =~ s:/{2,}:/:g;
     push(@results, perl_glob($new_regexp, $new_current));
@@ -2267,8 +2417,8 @@
   }
 }
 
-# Replace any %g with the group and any %G's with a capitalized version of
-# the group in the title string with the group name.
+# Replace any %g with the group and any %G's with a capitalized
+# version of the group in the title string with the group name.
 sub replace_group_name {
   my ($title, $group) = @_;
 
@@ -2340,8 +2490,8 @@
       next;
     }
 
-    # Calculate which group the file belongs in and create a hash listing
-    # the filenames for each group.
+    # Calculate which group the file belongs in and create a hash
+    # listing the filenames for each group.
     my %tmp_files_by_group;
     my %tmp_group_by_file;
     foreach my $filename (unique(@filenames)) {
@@ -2350,7 +2500,8 @@
       foreach my $regexp (@{$config_files->{$files_key}{find_files}}) {
         my @result = ($filename =~ $regexp);
         if (@result) {
-          # There there are no ()'s in the regexp, then change (1) to ().
+          # There there are no ()'s in the regexp, then change (1) to
+          # ().
           @result = () if (@result == 1 and $result[0] eq '1');
           # Remove any empty matches from @result.
           $group = join('_', grep {length($_)} @result);
@@ -2378,33 +2529,48 @@
 
     # Now for each file, create the Orca::SourceDataFile object that
     # manages that file and the GIFs that get generated from the file.
-    foreach my $filename (@filenames) {
-      # Create the object that contains this file.  Take care if the same
-      # file is being used in another files group.
+    # Delete from the list of filenames those files that have
+    # successfully created Orca::SourceDataFile objects.
+    for (my $i=0; $i<@filenames;) {
+      my $filename = $filenames[$i];
+      # Create the object that contains this file.  Take care if the
+      # same file is being used in another files group.
       unless (defined $new_found_files_ref->{$filename}) {
         if (defined $old_found_files_ref->{$filename}) {
           $new_found_files_ref->{$filename} = $old_found_files_ref->{$filename};
         }
         else {
           print "  $filename\n" if $opt_verbose;
-          my $data_file = 
+          my $data_file =
             Orca::SourceDataFile->new($filename,
-                                       $config_files->{$files_key}{interval},
-                                       $config_options->{late_interval},
-                                       $config_files->{$files_key}{reopen},
-                                       $config_files->{$files_key}{column_description},
-                                       $config_files->{$files_key}{date_source},
-                                       $config_files->{$files_key}{date_format},
-                                       $config_options->{warn_email},
-                                       $saved_source_file_state);
+                                      $config_files->{$files_key}{interval},
+                                      $config_options->{late_interval},
+                                      $config_files->{$files_key}{reopen},
+                                      $config_files->{$files_key}{column_description},
+                                      $config_files->{$files_key}{date_source},
+                                      $config_files->{$files_key}{date_format},
+                                      $config_options->{warn_email},
+                                      $saved_source_file_state);
           unless ($data_file) {
             warn "$0: warning: cannot process `$filename'.\n";
+            splice(@filenames, $i, 1);
             next;
           }
           $new_found_files_ref->{$filename} = $data_file;
           $found_new_files = 1;
         }
       }
+      ++$i;
+    }
+
+    # Register with each source data file the files keys that use it.
+    foreach my $filename (@filenames) {
+      $new_found_files_ref->{$filename}->add_files_keys($files_key);
+    }
+
+    # Go through each source data file and register the new plots to
+    # create.
+    foreach my $filename (@filenames) {
       my $group = $tmp_group_by_file{$filename};
       $new_found_files_ref->{$filename}->add_plots($config_options,
                                                    $config_files,
@@ -2446,14 +2612,15 @@
 
   print "Loading state from `$state_file'.\n" if $opt_verbose;
 
-  # Get the first line which contains the hash key name.  Check that the
-  # first field is _filename.
-  # key names match what is stored in this script.
+  # Get the first line which contains the hash key name.  Check that
+  # the first field is _filename.
   my $line = <STATE>;
+  defined($line) or return \%state;
   chomp($line);
   my @keys = split(' ', $line);
   unless ($keys[0] eq '_filename') {
     warn "$0: warning: ignoring state file `$state_file': incorrect first field.\n";
+    return \%state;
   }
 
   while (<STATE>) {
@@ -2542,12 +2709,12 @@
                                 'ff0000',	# Red
                                 'a020f0',	# Magenta
                                 'ffa500',	# Orange
-                                'a52a2a',	#
-                                '00ffff');	#
+                                'a52a2a',	# Brown
+                                '00ffff');	# Cyan
   }
 
-  # If data_dir is not set, then use base_dir.  Only die if both
-  # are not set.
+  # If data_dir is not set, then use base_dir.  Only die if both are
+  # not set.
   unless (defined $config_options->{data_dir}) {
     if (defined $config_options->{base_dir}) {
       $config_options->{data_dir} = $config_options->{base_dir};
@@ -2636,17 +2803,17 @@
       }
     }
 
-    # Optional files options will be set to '' here if they haven't been set
-    # by the user.
+    # Optional files options will be set to '' here if they haven't
+    # been set by the user.
     foreach my $option (@cc_optional_files) {
       unless (defined $config_files->{$files_key}{$option}) {
         $config_files->{$files_key}{$option} = '';
       }
     }
 
-    # Check that the date_source is either column_name followed by a column
-    # name or file_mtime for the file modification time.  If a column_name
-    # is used, then the date_format is required.
+    # Check that the date_source is either column_name followed by a
+    # column name or file_mtime for the file modification time.  If a
+    # column_name is used, then the date_format is required.
     my $date_source = $config_files->{$files_key}{date_source}[0];
     if ($date_source eq 'column_name') {
       unless (@{$config_files->{$files_key}{date_source}} == 2) {
@@ -2666,16 +2833,28 @@
     # Check that we have a valid regular expression for find_files and
     # get a unique list of them.  Also to see if the find_files match
     # contains any ()'s that will split the files into groups.  If so,
-    # then we will use subdirectories to create our structure.
+    # then we will use subdirectories to create our structure.  If a
+    # find begins with \./, then remove it from the path.  Be careful
+    # of a search on only \./.  Also remove any /\./'s in the path.
+    # Searches on both of these are unnecessary, since they involve
+    # searching on a current directory.  However, do not remove /./'s
+    # since this will match single character files and directories.
     my $sub_dir = 0;
     my %find_files;
-    foreach my $watch (@{$config_files->{$files_key}{find_files}}) {
+    my $number_finds = @{$config_files->{$files_key}{find_files}};
+    for (my $i=0; $i<$number_finds; ++$i) {
+      my $orig_find = $config_files->{$files_key}{find_files}[$i];
+      my $find = $orig_find;
+      $find =~ s:^\\./::;
+      $find =~ s:/\\./:/:g;
+      $find = $orig_find unless $find;
+      $config_files->{$files_key}{find_files}[$i] = $find;
       my $test_string = 'abcdefg';
       local $SIG{__WARN__} = sub { die $_[0] };
-      eval { $test_string =~ /$watch/ };
-      die "$0: error: illegal regular expression in `find_files $watch' for `files $files_key' in `$config_filename':\n$@\n" if $@;
-      $find_files{$watch}++;
-      $sub_dir = 1 if $watch =~ m:\(.+\):;
+      eval { $test_string =~ /$find/ };
+      die "$0: error: illegal regular expression in `find_files $orig_find' for `files $files_key' in `$config_filename':\n$@\n" if $@;
+      $find_files{$find}++;
+      $sub_dir = 1 if $find =~ m:\(.+\):;
     }
     $config_files->{$files_key}{find_files} = [sort keys %find_files];
     $config_files->{$files_key}{sub_dir}    = $sub_dir || $config_options->{sub_dir};
@@ -2696,12 +2875,12 @@
       }
     }
 
-    # Create an array for each plot that will have a list of GIFs that were
-    # generated from this plot.
+    # Create an array for each plot that will have a list of GIFs that
+    # were generated from this plot.
     $config_plots->[$i]{creates} = [];
 
-    # Optional options will be set to '' here if they haven't been set by the
-    # user.
+    # Optional options will be set to '' here if they haven't been set
+    # by the user.
     foreach my $option (@cc_optional_plots) {
       unless (defined $config_plots->[$i]{$option}) {
         $config_plots->[$i]{$option} = '';
@@ -2712,7 +2891,8 @@
     $config_plots->[$i]{plot_width}  = 500 unless $config_plots->[$i]{plot_width};
     $config_plots->[$i]{plot_height} = 125 unless $config_plots->[$i]{plot_height};
 
-    # Set the plot minimum and maximum values to U unless they are set.
+    # Set the plot minimum and maximum values to U unless they are
+    # set.
     unless (defined $config_plots->[$i]{data_min}) {
       $config_plots->[$i]{data_min} = 'U';
     }
@@ -2736,7 +2916,7 @@
         $config_plots->[$i]{data_type} = 'DERIVE';
       }
       else {
-        die "$0: error: `data_type $config_plots->[$i]{data_type}' for `plot' #$j in `$config_filename' must be gauge, counter, or absolute.\n";
+        die "$0: error: `data_type $config_plots->[$i]{data_type}' for `plot' #$j in `$config_filename' must be gauge, counter, derive, or absolute.\n";
       }
     }
     else {
@@ -2792,14 +2972,14 @@
       }
     }
 
-    # If the generic y_legend is not set, then set it equal to the first
-    # legend.
+    # If the generic y_legend is not set, then set it equal to the
+    # first legend.
     unless (defined $config_plots->[$i]{y_legend}) {
       $config_plots->[$i]{y_legend} = $config_plots->[$i]{legend}[0];
     }
 
-    # If the title is not set, then set it equal to all of the legends with
-    # the group name prepended.
+    # If the title is not set, then set it equal to all of the legends
+    # with the group name prepended.
     unless (defined $config_plots->[$i]{title}) {
       my $title = '%G ';
       for (my $k=0; $k<$number_datas; ++$k) {
@@ -2843,13 +3023,14 @@
   }
 }
 
-# These are state variables for reading the config file.  The $files_key
-# variable holds the name of the file parameter when a file configuration
-# is being defined.  If $files_key is '', then the a file configuration is
-# not being read.  $plot_index is a string that represents a number that
-# is used as an index into @plots.  If the string is negative, including
-# -0, then the plot configuration is not being defined, otherwise it holds
-# the index into the @plots array the is being defined.
+# These are state variables for reading the config file.  The
+# $files_key variable holds the name of the file parameter when a file
+# configuration is being defined.  If $files_key is '', then the a
+# file configuration is not being read.  $plot_index is a string that
+# represents a number that is used as an index into @plots.  If the
+# string is negative, including -0, then the plot configuration is not
+# being defined, otherwise it holds the index into the @plots array
+# the is being defined.
 my $pcl_files_key;
 my $pcl_plot_index;
 
@@ -2930,8 +3111,9 @@
   my @line  = split(' ', $line);
   my $key   = lc(shift(@line));
 
-  # Warn if there is no option and it requires an option.  Turn on options
-  # that do not require an option argument and do not supply one.
+  # Warn if there is no option and it requires an option.  Turn on
+  # options that do not require an option argument and do not supply
+  # one.
   if ($key ne '}') {
     if (grep { $key eq $_} @pcl_no_arg_elements) {
       push(@line, 1) unless @line;
@@ -2944,20 +3126,24 @@
     }
   }
 
-  # Prepend the base_dir to paths that are not prepended by /.
+  # Clean up paths.  Prepend the base_dir to paths that are not
+  # prepended by ^\\?\.{0,2}/, which matches /, ./, ../, and \./.
+  # Then, remove any //'s.
   my $base_dir = defined $config_options->{base_dir} ?
     $config_options->{base_dir} : '';
-  if ( $base_dir and grep {$key eq $_} @pcl_filepath_elements) {
+  if (grep {$key eq $_} @pcl_filepath_elements) {
     foreach my $path (@line) {
-      $path = "$base_dir/$path" unless $path =~ m:^/:;
-      $path =~ s:/{2,}:/:
+      if ($base_dir) {
+        $path = "$base_dir/$path" unless $path =~ m:^\\?\.{0,2}/:;
+      }
+      $path =~ s:/{2,}:/:g;
     }
   }
 
   my $value = "@line";
 
-  # Process the line differently if we're reading for a particular option.
-  # This one is for files.
+  # Process the line differently if we're reading for a particular
+  # option.  This one is for files.
   if ($pcl_files_key) {
     if ($key eq '}') {
       $pcl_files_key = '';
@@ -3068,9 +3254,9 @@
   my %files;
   my @plots;
 
-  # Load in all lines in the file and then process them.  If a line begins
-  # with whitespace, then append it to the previously read line and do
-  # not process it.
+  # Load in all lines in the file and then process them.  If a line
+  # begins with whitespace, then append it to the previously read line
+  # and do not process it.
   my $complete_line = '';
   my $line_number = 1;
   while (<CONFIG>) {
@@ -3078,7 +3264,8 @@
     # Skip lines that begin with #.
     next if /^#/;
 
-    # If the line begins with whitespace, then append it to the previous line.
+    # If the line begins with whitespace, then append it to the
+    # previous line.
     if (/^\s+/) {
       $complete_line .= " $_";
       next;
@@ -3144,8 +3331,8 @@
   * Can be run under cron or it can sleep itself waiting for file updates
     based on when the file was last updated.
 
-Orca is based the the RRD tool by Tobias Oetiker.  While it is similar to
-the other tools based on RRD, such as Cricket and MRTG, it is significantly
+Orca is based the RRD tool by Tobias Oetiker.  While it is similar to the
+other tools based on RRD, such as Cricket and MRTG, it is significantly
 different.  To see these other tools, examine
 
   http://ee-staff.ethz.ch/~oetiker/webtools/mrtg/mrtg.html
@@ -3158,7 +3345,7 @@
 
 A small static example of Orca is at
 
-  http://www.geocities.com/ResearchTriangle/Thinktank/4996/orca-example/
+  http://www.geocities.com/~bzking/orca-example/
 
 Please inform me of any other sites using Orca and I will include them
 here.
@@ -3195,8 +3382,8 @@
 The first step in using Orca is to set up a configuration file that
 instructs Orca on what to do.  The configuration file is based on a
 key/value pair structure.  The key name must start at the beginning of
-a line.  Lines that begin with whitespace are concatenated onto the the
-last key's value.  This is the same format as used by MRTG and Cricket.
+a line.  Lines that begin with whitespace are concatenated onto the last
+key's value.  This is the same format as used by MRTG and Cricket.
 
 There are three main groups of options in a Orca confg: general options,
 file specific options, and plot specific options.  General options may
@@ -3281,7 +3468,7 @@
 
 B<warn_email> takes a list of email addresses of people to email
 when something goes wrong with either Orca or the input data files.
-Currently email messages are sent out the the following circumstances:
+Currently email messages are sent out the following circumstances:
 
   1) When a file did exist and now is gone.
   2) When a file was being updated regularly and then no longer is updated.
@@ -3657,7 +3844,7 @@
 incrementing counters like the InOctets counter in a router. The
 B<COUNTER> data source assumes that the counter never decreases, except
 when a counter overflows.  The update function takes the overflow into
-account.  B<DERIVE> will store the the derivative of the line going from
+account.  B<DERIVE> will store the derivative of the line going from
 the last to the current value of the data source. This can be useful for
 counters which do raise and fall, for example, to measure the rate of
 people entering or leaving a room.  B<DERIVE> does not test for overflow.

Modified: trunk/orca/docs/ARCHITECTURE
==============================================================================
--- trunk/orca/docs/ARCHITECTURE	(original)
+++ trunk/orca/docs/ARCHITECTURE	Sat Jul 13 18:45:53 2002
@@ -1,10 +1,10 @@
+This incomplete file describes Orca's internal design.
+
 Orca::OpenFileHash
 Orca::HTMLFile
 Orca::DataFile
 Orca::SourceDataFile
 
-This file describes Orca's internal design.
-
 Orca makes use of several internal classes (objects).  They are:
 
 	Orca::OpenFileHash

Modified: trunk/orca/CHANGES
==============================================================================
--- trunk/orca/CHANGES	(original)
+++ trunk/orca/CHANGES	Sat Jul 13 18:45:54 2002
@@ -1,5 +1,217 @@
+Mon May 17 16:26:17 PDT 1999
+
+	Release version 0.21.
+
+Mon May 17 15:07:33 PDT 1999
+
+	Correct a bug when a source data file cannot be loaded it should
+	not used to look up a Orca::SourceDataFile object.
+
+	Reformat all the comments in orca.pl.
+
+Thu May 13 10:47:41 PDT 1999
+
+	Orca used to delete RRD files if they had an $ORCA_RRD_VERSION
+	number newer then the required version number.	Now use them.
+	Add code to remember the Orca RRD version number so that the
+	GIF creation code works properly with RRD files with a version
+	different than $ORCA_RRD_VERSION.
+
+	Thanks to a configure file and some data from from Eric Blaise
+	<Eric.Blaise at socgen.com>, Orca can now handle plots containing
+	columns of data that do not exist in all input source data files.
+
+	In add_plots, a linear search was used to convert column
+	description names appearing in data statements to an index into
+	the column_description array.  Now use a hash table look up.
+
+Wed May 12 09:31:43 PDT 1999
+
+	Orca now cleans up all file paths in the input configuration file.
+	If more than one / are found in a row, they are replaced by one /.
+	The base_dir is only prepended to paths if the path does not
+	match ^\\?\.{0,2}/, which will match on /, ./, ../, and \./.
+
+	The paths used to find input files are now passed through
+	the following regular expressions: s:^\\./:: and s:/\\./:/:g.
+	These remove unneccessary searches through the current directory.
+
+	Perl_glob will only return found files and no other type.
+	It will also not follow any directories named `..'.
+
+	Include RRDtool 0.99.29.1 with Orca.  This includes a Makefile
+	patch and does not include a new version of RRDs.pm or librrd.
+
+	In any Makefile.in's that run config.status, they used to run
+	a make from the top level directory.  Now they only run a make
+	from the directory that required the running of config.status.
+
+Tue May 11 16:24:09 PDT 1999
+
+	In places where deep copies of data structures are made and no
+	s///'s are performed on the text form of data, use dclone that
+	comes with Storable instead of using Data::Dumper and eval.
+
+	Do not prepend base_dir to any paths if they begin with either
+	`/' or `./'.
+
+	Require and include RRDtool 0.99.29 with Orca.
+
+	Orca now includes the four Perl packages it depends upon:
+	Digest::MD5 2.07, Math::Interpolate 1.02, RRDtool 0.99.29,
+	and Storable 0.6 at 3.
+
+Mon May 10 10:46:36 PDT 1999
+
+	Update references to Digest::MD5 version 2.07 and require
+	RRDtool 0.99.28.
+
+Sat May  8 19:29:14 PDT 1999
+
+	Upgrade the instructions to mention Math::Interpolate 1.02
+	instead of Math::Interpolator 1.01.
+
+Thu May  6 13:58:06 PDT 1999
+
+	Orca does not normally display the daily, weekly, monthly,
+	yearly, and everything plots for all the different measurements
+	if there is only one group.  However, it is nice to see all the
+	different measurement plots in one page for a single group, so if
+	now there is only one group, then an Everything group placed at
+	the top of the main index.html file for daily, weekly, monthly,
+	and yearly overviews.
+
+	Make a comment about using gd1.3 versus gd1.2 in INSTALL when
+	building RRDtool.  Because RRDtool comes with gd1.2 and generates
+	smaller GIFs, a comment is made that there is no reason to move
+	to gd1.3.  The bottom line is that gd1.2 is preferred.
+
+	Check if the state file is empty and do not complain if it is.
+
+	Add installation instructions that to install this version
+	of Orca over an older version, a make migrate command will
+	need to be run to renames all files and directories containing
+	percollator, percol, or perc to orcallator in any of the installed
+	Orca directories.
+
+	Update orcallator.cfg to look for filenames like
+	orcallator-1999-05-06 and percol-1999-05-06.
+
+Wed May  5 10:43:23 PDT 1999
+
+	Require RRDtool 0.99.27.
+
+Mon May  3 14:51:06 PDT 1999
+
+	Rename everything percollator, perc and percol to orcallator.
+
+Fri Apr 30 16:34:20 PDT 1999
+
+	Update to install Perl 5.005_03 instead of 5.005_02.
+
+Fri Apr 23 09:31:28 PDT 1999
+
+	Require RRDtool 0.99.25.
+
+Thu Apr 22 09:21:15 PDT 1999
+
+	Require RRDtool 0.99.24.
+
+Sat Apr 17 12:06:46 PDT 1999
+
+	Change all URLs from
+	    http://www.geocities.com/ResearchTriangle/Thinktank/4996/
+	to
+	    http://www.geocities.com/~bzking/
+
+Thu Apr  8 17:03:37 PDT 1999
+
+	Require RRDtool 0.99.23.
+
+Wed Mar 31 19:07:41 PST 1999
+
+	When perl_glob cannot open a directory, return an empty
+	array and warn instead of dying.  Fix from J.R. Tietsort
+	<jrtietsort at micron.com>.
+
+	Require RRDtool 0.99.22 which contains a memory leak bug fix.
+
+Sat Mar 27 10:07:09 PST 1999
+
+	Update references to Digest::MD5 version 2.06 and require
+	RRDtool 0.99.21.
+
+Thu Mar 25 15:30:00 PST 1999
+
+	Speed up count_proc() in percollator.se by 20% using a patch
+	supplied by Rich Pettit <rpettit at resolute.com>.
+
+Sat Mar  6 11:50:57 PST 1999
+
+	Update references to Digest::MD5 version 2.04.
+
+Thu Mar  4 16:42:03 PST 1999
+
+	Require RRDtool 0.99.19.
+
+Mon Mar  1 11:01:01 PST 1999
+
+	Require RRDtool 0.99.18.
+
+Tue Feb 23 09:19:37 PST 1999
+
+	Require RRDtool 0.99.15.
+
+	Die if a unrecognized command line option is given to Orca.
+
+	Do group name substitution on the Y legend in GIFs.
+
+	Add another consolidation function, DERIVE, to an error message.
+
+	Change the user, system and idle colors in the CPU usage plot
+	as requested by Alain Swanson <amswanson at micron.com>.
+
+	Change the printing format of usr% and sys% from %4.0f to %5.1f
+	in percollator.se to work around a printing problem reported by
+	Alain Swanson <amswanson at micron.com>.  In SE 3.1 this will now
+	display an extra non-zero digit of measured precision.
+
+	Always output the header information in percollator.se, even
+	if Orca cannot handle it yet, since the number of columns may
+	change if new hardware is added to the system.
+
+Mon Feb 22 10:23:21 PST 1999
+
+	Add GIF width and height tags to img src's using the returned
+	GIF size from RRDs::graph.
+
+	Add a space between the ending " for the img src="" and the
+	following alt="" in the generated HTML.
+
+	Require RRDtool 0.99.14.
+
+	Add x86 Ethernet device plotting to percollator.cfg.in.
+
+	Remove the LAST RRA from all Orca created RRAs since it is not
+	required to get the current value from an RRA.	The current
+	value is obtained by using the LAST consolidation function on
+	the plotted data.
+
+Sun Feb 21 11:03:39 PST 1999
+
+	Make use of RRDtool 0.99.12's legend formatting.
+
+Sat Feb 20 20:13:01 PST 1999
+
+	Require RRDtool 0.99.12.
+
 Fri Feb 19 11:55:50 PST 1999
 
+	Move some </a> tags to the end of the image they were referencing
+	to remove some Netscape glitches.
+
+	Minor spelling fix and addition to CHANGES file.
+
 	Version 0.20.
 
 	Have the Orca logo be a hyperlink to the Orca home page.
@@ -16,8 +228,12 @@
 	the interval.  This is useful for RRD which expects data to be
 	measured on the interval.
 
+	Fix a bug in percollator.se where it was inflating the httpops5
+	number since it was not calculating the actual time interval
+	and instead assuming a 5 second interval.
+
 	Add Squid log processing to percollator.se courtesy of Adrian
-	Cockroft of Sun Microsystems.
+	Cockcroft of Sun Microsystems.
 
 	Rename the configure --with options.  If you want to watch NCSA
 	style access logs, use --with-ncsa-log.  To watch NCSA style

Added: trunk/orca/NEWS
==============================================================================
--- trunk/orca/NEWS	(original)
+++ trunk/orca/NEWS	Sat Jul 13 18:45:54 2002
@@ -0,0 +1,45 @@
+New in version 0.21.
+ 1) Every file containing the words percollator, percol and perc has
+    been renamed to contain the word orcallator.  A new make target named
+    migrate will change all filenames in an installed Orca directory to
+    the new names.  This `make migrate' should only be run after killing
+    any running percollator.se's and Orca processes and before installing
+    this version of Orca.
+ 2) Orca now includes Digest::MD5 2.07, Math::Interpolate 1.02, RRDs
+    0.99029, and Storable 0.603 in packages/ to make installation easier.
+    The configure script now determines if you have the requisite version
+    of these packages installed in your Perl and will modify the Makefiles
+    to build the necessary modules.
+ 3) Orca now displays the daily, weekly, monthly, yearly plots of all
+    measurements even if there is only one group.  Orca used to not make
+    the web pages showing the different measurements all on one page if
+    there was only one group.
+ 4) Add GIF width and height tags to img src's using the returned GIF
+    size from RRDs::graph to speed with page rendering.
+ 5) Some minor HTML fixes to have the pages look cleaner for Netscape
+    browsers.
+ 6) Make use of RRDtool 0.99.12's legend formatting to clean up the GIF
+    legends and to store the minimum and maximum values of a data stream.
+ 7) Remove the LAST RRA from all Orca created RRAs since it is not
+    required to get the current value from an RRA.  This requires
+    rebuilding all RRDs.
+ 8) Add x86 Ethernet device (elxl*) plotting to orcallator.cfg.in.
+ 9) Do group name substitution on the Y legend in GIFs.
+10) Orca used to delete RRD files even if they are created with new
+    versions or Orca.  Now the RRD file is used if it is at least as
+    new as the version a particular version of Orca needs.
+11) Orca now dies if an unrecognized command line option is given.
+12) Speed up the count_proc() routine in orcallator.se by 20%.
+13) Perl_glob does not die if it cannot open a directory.  It will
+    also not follow directories named .. if they happen to match
+    a regular expression.  It also only returns files matching the
+    regular expressions.
+14) Change all references from
+    http://www.geocities.com/ResearchTriangle/Thinktank/4996/
+    to
+    http://www.geocities.com/~bzking/
+15) Speed up Orca by using Storable to do deep clones of objects
+    instead of using Data::Dumper and eval.
+16) Replace some linear search by a hash lookup to speed up Orca.
+17) Fix some bugs in orcallator.se.
+18) Clean up some error messages.

Modified: trunk/orca/README
==============================================================================
--- trunk/orca/README	(original)
+++ trunk/orca/README	Sat Jul 13 18:45:54 2002
@@ -1,4 +1,4 @@
-This package contains two main tools: Orca and percollator.se.
+This package contains two main tools: Orca and orcallator.se.
 
 Orca
 =====
@@ -32,7 +32,7 @@
 
 An example of the output generated by Orca is located at:
 
-http://www.geocities.com/ResearchTriangle/Thinktank/4996/orca-example/
+http://www.geocities.com/~bzking/orca-example/
 
 Orca is written completely in Perl.  To install, configure and use
 Orca read the INSTALL file.  Some sample configuration files for
@@ -47,29 +47,29 @@
 explain how the data files Orca uses are created, maintained, and
 used to create the GIFs that Orca creates.
 
-percollator.se
+orcallator.se
 ==============
 
-The other tool in this package is an updated version of percollator.se
+The other tool in this package is an updated version of orcallator.se
 written by Adrian Cockcroft.  Percollator.se is a tool written for Solaris
 SPARC and Solaris x86 that collects a large amount of system and web
 server statistics and prints them into a file for later processing
-and plotting.  For documentation on the original percollator.se tool,
+and plotting.  For documentation on the original orcallator.se tool,
 see the URL http://www.sunworld.com/swol-03-1996/swol-03-perf.html
 
-This version of percollator.se collects much more data than the original
+This version of orcallator.se collects much more data than the original
 on Solaris systems.  I have designed an Orca configuration file designed
-to read the output of this percollator.  Sample output from this set up
+to read the output of this orcallator.  Sample output from this set up
 is displayed at
 
-http://www.geocities.com/ResearchTriangle/Thinktank/4996/orca-example/
+http://www.geocities.com/~bzking/orca-example/
 
 AVAILABLE AT
 ============
 
 These tools are available for download from
 
-http://www.geocities.com/ResearchTriangle/Thinktank/4996/
+http://www.geocities.com/~bzking/
 
 MAILING LISTS
 =============

Added: trunk/orca/packages/Storable-0.6 at 3/t/dump.pl
==============================================================================
--- trunk/orca/packages/Storable-0.6 at 3/t/dump.pl	(original)
+++ trunk/orca/packages/Storable-0.6 at 3/t/dump.pl	Sat Jul 13 18:45:54 2002
@@ -0,0 +1,140 @@
+;# $Id: dump.pl,v 0.6 1998/06/04 16:08:27 ram Exp $
+;#
+;#  Copyright (c) 1995-1998, Raphael Manfredi
+;#  
+;#  You may redistribute only under the terms of the Artistic License,
+;#  as specified in the README file that comes with the distribution.
+;#
+;# $Log: dump.pl,v $
+;# Revision 0.6  1998/06/04  16:08:27  ram
+;# Baseline for first beta release.
+;#
+
+package dump;
+use Carp;
+
+%dump = (
+	'SCALAR'	=> 'dump_scalar',
+	'ARRAY'		=> 'dump_array',
+	'HASH'		=> 'dump_hash',
+	'REF'		=> 'dump_ref',
+);
+
+# Given an object, dump its transitive data closure
+sub main'dump {
+	my ($object) = @_;
+	croak "Not a reference!" unless ref($object);
+	local %dumped;
+	local %object;
+	local $count = 0;
+	local $dumped = '';
+	&recursive_dump($object, 1);
+	return $dumped;
+}
+
+# This is the root recursive dumping routine that may indirectly be
+# called by one of the routine it calls...
+# The link parameter is set to false when the reference passed to
+# the routine is an internal temporay variable, implying the object's
+# address is not to be dumped in the %dumped table since it's not a
+# user-visible object.
+sub recursive_dump {
+	my ($object, $link) = @_;
+
+	# Get something like SCALAR(0x...) or TYPE=SCALAR(0x...).
+	# Then extract the bless, ref and address parts of that string.
+
+	my $what = "$object";		# Stringify
+	my ($bless, $ref, $addr) = $what =~ /^(\w+)=(\w+)\((0x.*)\)$/;
+	($ref, $addr) = $what =~ /^(\w+)\((0x.*)\)$/ unless $bless;
+
+	# Special case for references to references. When stringified,
+	# they appear as being scalars. However, ref() correctly pinpoints
+	# them as being references indirections. And that's it.
+
+	$ref = 'REF' if ref($object) eq 'REF';
+
+	# Make sure the object has not been already dumped before.
+	# We don't want to duplicate data. Retrieval will know how to
+	# relink from the previously seen object.
+
+	if ($link && $dumped{$addr}++) {
+		my $num = $object{$addr};
+		$dumped .= "OBJECT #$num seen\n";
+		return;
+	}
+
+	my $objcount = $count++;
+	$object{$addr} = $objcount;
+
+	# Call the appropriate dumping routine based on the reference type.
+	# If the referenced was blessed, we bless it once the object is dumped.
+	# The retrieval code will perform the same on the last object retrieved.
+
+	croak "Unknown simple type '$ref'" unless defined $dump{$ref};
+
+	&{$dump{$ref}}($object);	# Dump object
+	&bless($bless) if $bless;	# Mark it as blessed, if necessary
+
+	$dumped .= "OBJECT $objcount\n";
+}
+
+# Indicate that current object is blessed
+sub bless {
+	my ($class) = @_;
+	$dumped .= "BLESS $class\n";
+}
+
+# Dump single scalar
+sub dump_scalar {
+	my ($sref) = @_;
+	my $scalar = $$sref;
+	unless (defined $scalar) {
+		$dumped .= "UNDEF\n";
+		return;
+	}
+	my $len = length($scalar);
+	$dumped .= "SCALAR len=$len $scalar\n";
+}
+
+# Dump array
+sub dump_array {
+	my ($aref) = @_;
+	my $items = 0 + @{$aref};
+	$dumped .= "ARRAY items=$items\n";
+	foreach $item (@{$aref}) {
+		unless (defined $item) {
+			$dumped .= 'ITEM_UNDEF' . "\n";
+			next;
+		}
+		$dumped .= 'ITEM ';
+		&recursive_dump(\$item, 1);
+	}
+}
+
+# Dump hash table
+sub dump_hash {
+	my ($href) = @_;
+	my $items = scalar(keys %{$href});
+	$dumped .= "HASH items=$items\n";
+	foreach $key (sort keys %{$href}) {
+		$dumped .= 'KEY ';
+		&recursive_dump(\$key, undef);
+		unless (defined $href->{$key}) {
+			$dumped .= 'VALUE_UNDEF' . "\n";
+			next;
+		}
+		$dumped .= 'VALUE ';
+		&recursive_dump(\$href->{$key}, 1);
+	}
+}
+
+# Dump reference to reference
+sub dump_ref {
+	my ($rref) = @_;
+	my $deref = $$rref;				# Follow reference to reference
+	$dumped .= 'REF ';
+	&recursive_dump($deref, 1);		# $dref is a reference
+}
+
+1;

Added: trunk/orca/packages/Storable-0.6 at 3/t/freeze.t
==============================================================================
--- trunk/orca/packages/Storable-0.6 at 3/t/freeze.t	(original)
+++ trunk/orca/packages/Storable-0.6 at 3/t/freeze.t	Sat Jul 13 18:45:54 2002
@@ -0,0 +1,111 @@
+#!./perl
+
+# $Id: freeze.t,v 0.6.1.1 1998/06/12 09:47:08 ram Exp $
+#
+#  Copyright (c) 1995-1998, Raphael Manfredi
+#  
+#  You may redistribute only under the terms of the Artistic License,
+#  as specified in the README file that comes with the distribution.
+#
+# $Log: freeze.t,v $
+# Revision 0.6.1.1  1998/06/12  09:47:08  ram
+# patch1: added test for the LVALUE bug workaround
+#
+# Revision 0.6  1998/06/04  16:08:31  ram
+# Baseline for first beta release.
+#
+
+require 't/dump.pl';
+
+use Storable qw(freeze nfreeze thaw);
+
+print "1..15\n";
+
+$a = 'toto';
+$b = \$a;
+$c = bless {}, CLASS;
+$c->{attribute} = $b;
+$d = {};
+$e = [];
+$d->{'a'} = $e;
+$e->[0] = $d;
+%a = ('key', 'value', 1, 0, $a, $b, 'cvar', \$c);
+ at a = ('first', undef, 3, -4, -3.14159, 456, 4.5, $d, \$d, \$e, $e,
+	$b, \$a, $a, $c, \$c, \%a);
+
+print "not " unless defined ($f1 = freeze(\@a));
+print "ok 1\n";
+
+$dumped = &dump(\@a);
+print "ok 2\n";
+
+$root = thaw($f1);
+print "not " unless defined $root;
+print "ok 3\n";
+
+$got = &dump($root);
+print "ok 4\n";
+
+print "not " unless $got eq $dumped; 
+print "ok 5\n";
+
+package FOO; @ISA = qw(Storable);
+
+sub make {
+	my $self = bless {};
+	$self->{key} = \%main::a;
+	return $self;
+};
+
+package main;
+
+$foo = FOO->make;
+print "not " unless $f2 = $foo->freeze;
+print "ok 6\n";
+
+print "not " unless $f3 = $foo->nfreeze;
+print "ok 7\n";
+
+$root3 = thaw($f3);
+print "not " unless defined $root3;
+print "ok 8\n";
+
+print "not " unless &dump($foo) eq &dump($root3);
+print "ok 9\n";
+
+$root = thaw($f2);
+print "not " unless &dump($foo) eq &dump($root);
+print "ok 10\n";
+
+print "not " unless &dump($root3) eq &dump($root);
+print "ok 11\n";
+
+$other = freeze($root);
+print "not " unless length($other) == length($f2);
+print "ok 12\n";
+
+$root2 = thaw($other);
+print "not " unless &dump($root2) eq &dump($root);
+print "ok 13\n";
+
+$VAR1 = [
+	'method',
+	1,
+	'prepare',
+	'SELECT table_name, table_owner, num_rows FROM iitables
+                  where table_owner != \'$ingres\' and table_owner != \'DBA\''
+];
+
+$x = nfreeze($VAR1);
+$VAR2 = thaw($x);
+print "not " unless $VAR2->[3] eq $VAR1->[3];
+print "ok 14\n";
+
+# Test the workaround for LVALUE bug in perl 5.004_04 -- from Gisle Aas
+sub foo { $_[0] = 1 }
+$foo = [];
+foo($foo->[1]);
+eval { freeze($foo) };
+print "not " if $@;
+print "ok 15\n";
+

Added: trunk/orca/packages/Storable-0.6 at 3/t/forgive.t
==============================================================================
--- trunk/orca/packages/Storable-0.6 at 3/t/forgive.t	(original)
+++ trunk/orca/packages/Storable-0.6 at 3/t/forgive.t	Sat Jul 13 18:45:54 2002
@@ -0,0 +1,52 @@
+#!./perl
+
+# $Id: forgive.t,v 0.6 1998/06/04 16:08:38 ram Exp $
+#
+#  Copyright (c) 1995-1998, Raphael Manfredi
+#  
+#  You may redistribute only under the terms of the Artistic License,
+#  as specified in the README file that comes with the distribution.
+#
+# Original Author: Ulrich Pfeifer
+# (C) Copyright 1997, Universitat Dortmund, all rights reserved.
+#
+# $Log: forgive.t,v $
+# Revision 0.6  1998/06/04  16:08:38  ram
+# Baseline for first beta release.
+#
+
+use Storable qw(store retrieve);
+
+print "1..8\n";
+
+my $test = 1;
+my $bad = ['foo', sub { 1 },  'bar'];
+my $result;
+
+eval {$result = store ($bad , 't/store')};
+print ((!defined $result)?"ok $test\n":"not ok $test\n"); $test++;
+print (($@ ne '')?"ok $test\n":"not ok $test\n"); $test++;
+
+$Storable::forgive_me=1;
+
+open(SAVEERR, ">&STDERR");
+open(STDERR, ">/dev/null") or 
+  ( print SAVEERR "Unable to redirect STDERR: $!\n" and exit(1) );
+
+eval {$result = store ($bad , 't/store')};
+
+open(STDERR, ">&SAVEERR");
+
+print ((defined $result)?"ok $test\n":"not ok $test\n"); $test++;
+print (($@ eq '')?"ok $test\n":"not ok $test\n"); $test++;
+
+my $ret = retrieve('t/store');
+print ((defined $ret)?"ok $test\n":"not ok $test\n"); $test++;
+print (($ret->[0] eq 'foo')?"ok $test\n":"not ok $test\n"); $test++;
+print (($ret->[2] eq 'bar')?"ok $test\n":"not ok $test\n"); $test++;
+print ((ref $ret->[1] eq 'SCALAR')?"ok $test\n":"not ok $test\n"); $test++;
+
+
+END {
+  unlink 't/store';
+}

Added: trunk/orca/packages/Storable-0.6 at 3/t/dclone.t
==============================================================================
--- trunk/orca/packages/Storable-0.6 at 3/t/dclone.t	(original)
+++ trunk/orca/packages/Storable-0.6 at 3/t/dclone.t	Sat Jul 13 18:45:54 2002
@@ -0,0 +1,57 @@
+#!./perl
+
+# $Id: dclone.t,v 0.6 1998/06/04 16:08:25 ram Exp $
+#
+#  Copyright (c) 1995-1998, Raphael Manfredi
+#  
+#  You may redistribute only under the terms of the Artistic License,
+#  as specified in the README file that comes with the distribution.
+#
+# $Log: dclone.t,v $
+# Revision 0.6  1998/06/04  16:08:25  ram
+# Baseline for first beta release.
+#
+
+require 't/dump.pl';
+
+use Storable qw(dclone);
+
+print "1..6\n";
+
+$a = 'toto';
+$b = \$a;
+$c = bless {}, CLASS;
+$c->{attribute} = 'attrval';
+%a = ('key', 'value', 1, 0, $a, $b, 'cvar', \$c);
+ at a = ('first', undef, 3, -4, -3.14159, 456, 4.5,
+	$b, \$a, $a, $c, \$c, \%a);
+
+print "not " unless defined ($aref = dclone(\@a));
+print "ok 1\n";
+
+$dumped = &dump(\@a);
+print "ok 2\n";
+
+$got = &dump($aref);
+print "ok 3\n";
+
+print "not " unless $got eq $dumped; 
+print "ok 4\n";
+
+package FOO; @ISA = qw(Storable);
+
+sub make {
+	my $self = bless {};
+	$self->{key} = \%main::a;
+	return $self;
+};
+
+package main;
+
+$foo = FOO->make;
+print "not " unless defined($r = $foo->dclone);
+print "ok 5\n";
+
+print "not " unless &dump($foo) eq &dump($r);
+print "ok 6\n";
+

Added: trunk/orca/packages/Storable-0.6 at 3/t/retrieve.t
==============================================================================
--- trunk/orca/packages/Storable-0.6 at 3/t/retrieve.t	(original)
+++ trunk/orca/packages/Storable-0.6 at 3/t/retrieve.t	Sat Jul 13 18:45:54 2002
@@ -0,0 +1,57 @@
+#!./perl
+
+# $Id: retrieve.t,v 0.6 1998/06/04 16:08:33 ram Exp $
+#
+#  Copyright (c) 1995-1998, Raphael Manfredi
+#  
+#  You may redistribute only under the terms of the Artistic License,
+#  as specified in the README file that comes with the distribution.
+#
+# $Log: retrieve.t,v $
+# Revision 0.6  1998/06/04  16:08:33  ram
+# Baseline for first beta release.
+#
+
+require 't/dump.pl';
+
+use Storable qw(store retrieve nstore);
+
+print "1..9\n";
+
+$a = 'toto';
+$b = \$a;
+$c = bless {}, CLASS;
+$c->{attribute} = 'attrval';
+%a = ('key', 'value', 1, 0, $a, $b, 'cvar', \$c);
+ at a = ('first', '', undef, 3, -4, -3.14159, 456, 4.5,
+	$b, \$a, $a, $c, \$c, \%a);
+
+print "not " unless defined store(\@a, 't/store');
+print "ok 1\n";
+print "not " unless defined nstore(\@a, 't/nstore');
+print "ok 2\n";
+
+$root = retrieve('t/store');
+print "not " unless defined $root;
+print "ok 3\n";
+
+$nroot = retrieve('t/nstore');
+print "not " unless defined $nroot;
+print "ok 4\n";
+
+$d1 = &dump($root);
+print "ok 5\n";
+$d2 = &dump($nroot);
+print "ok 6\n";
+
+print "not " unless $d1 eq $d2; 
+print "ok 7\n";
+
+# Make sure empty string is defined at retrieval time
+print "not " unless defined $root->[1];
+print "ok 8\n";
+print "not " if length $root->[1];
+print "ok 9\n";
+
+unlink 't/store', 't/nstore';
+

Added: trunk/orca/packages/Storable-0.6 at 3/t/tied.t
==============================================================================
--- trunk/orca/packages/Storable-0.6 at 3/t/tied.t	(original)
+++ trunk/orca/packages/Storable-0.6 at 3/t/tied.t	Sat Jul 13 18:45:54 2002
@@ -0,0 +1,177 @@
+#!./perl
+
+# $Id: tied.t,v 0.6 1998/06/04 16:08:40 ram Exp $
+#
+#  Copyright (c) 1995-1998, Raphael Manfredi
+#  
+#  You may redistribute only under the terms of the Artistic License,
+#  as specified in the README file that comes with the distribution.
+#
+# $Log: tied.t,v $
+# Revision 0.6  1998/06/04  16:08:40  ram
+# Baseline for first beta release.
+#
+
+require 't/dump.pl';
+
+use Storable qw(freeze thaw);
+
+print "1..15\n";
+
+($scalar_fetch, $array_fetch, $hash_fetch) = (0, 0, 0);
+
+package TIED_HASH;
+
+sub TIEHASH {
+	my $self = bless {}, shift;
+	return $self;
+}
+
+sub FETCH {
+	my $self = shift;
+	my ($key) = @_;
+	$main::hash_fetch++;
+	return $self->{$key};
+}
+
+sub STORE {
+	my $self = shift;
+	my ($key, $value) = @_;
+	$self->{$key} = $value;
+}
+
+sub FIRSTKEY {
+	my $self = shift;
+	scalar keys %{$self};
+	return each %{$self};
+}
+
+sub NEXTKEY {
+	my $self = shift;
+	return each %{$self};
+}
+
+package TIED_ARRAY;
+
+sub TIEARRAY {
+	my $self = bless [], shift;
+	return $self;
+}
+
+sub FETCH {
+	my $self = shift;
+	my ($idx) = @_;
+	$main::array_fetch++;
+	return $self->[$idx];
+}
+
+sub STORE {
+	my $self = shift;
+	my ($idx, $value) = @_;
+	$self->[$idx] = $value;
+}
+
+sub FETCHSIZE {
+	my $self = shift;
+	return @{$self};
+}
+
+package TIED_SCALAR;
+
+sub TIESCALAR {
+	my $scalar;
+	my $self = bless \$scalar, shift;
+	return $self;
+}
+
+sub FETCH {
+	my $self = shift;
+	$main::scalar_fetch++;
+	return $$self;
+}
+
+sub STORE {
+	my $self = shift;
+	my ($value) = @_;
+	$$self = $value;
+}
+
+package main;
+
+$a = 'toto';
+$b = \$a;
+
+$c = tie %hash, TIED_HASH;
+$d = tie @array, TIED_ARRAY;
+tie $scalar, TIED_SCALAR;
+
+#$scalar = 'foo';
+#$hash{'attribute'} = \$d;
+#$array[0] = $c;
+#$array[1] = \$scalar;
+
+### If I say
+###   $hash{'attribute'} = $d;
+### below, then dump() incorectly dumps the hash value as a string the second
+### time it is reached. I have not investigated enough to tell whether it's
+### a bug in my dump() routine or in the Perl tieing mechanism.
+$scalar = 'foo';
+$hash{'attribute'} = 'plain value';
+$array[0] = \$scalar;
+$array[1] = $c;
+$array[2] = \@array;
+
+ at tied = (\$scalar, \@array, \%hash);
+%a = ('key', 'value', 1, 0, $a, $b, 'cvar', \$a, 'scalarref', \$scalar);
+ at a = ('first', 3, -4, -3.14159, 456, 4.5, $d, \$d,
+	$b, \$a, $a, $c, \$c, \%a, \@array, \%hash, \@tied);
+
+print "not " unless defined($f = freeze(\@a));
+print "ok 1\n";
+
+$dumped = &dump(\@a);
+print "ok 2\n";
+
+$root = thaw($f);
+print "not " unless defined $root;
+print "ok 3\n";
+
+$got = &dump($root);
+print "ok 4\n";
+
+### Used to see the manifestation of the bug documented above.
+### print "original: $dumped";
+### print "--------\n";
+### print "got: $got";
+### print "--------\n";
+
+print "not " unless $got eq $dumped; 
+print "ok 5\n";
+
+$g = freeze($root);
+print "not " unless length($f) == length($g);
+print "ok 6\n";
+
+# Ensure the tied items in the retrieved image work
+ at old = ($scalar_fetch, $array_fetch, $hash_fetch);
+ at tied = ($tscalar, $tarray, $thash) = @{$root->[$#{$root}]};
+ at type = qw(SCALAR  ARRAY  HASH);
+
+print "not " unless tied $$tscalar;
+print "ok 7\n";
+print "not " unless tied @{$tarray};
+print "ok 8\n";
+print "not " unless tied %{$thash};
+print "ok 9\n";
+
+ at new = ($$tscalar, $tarray->[0], $thash->{'attribute'});
+ at new = ($scalar_fetch, $array_fetch, $hash_fetch);
+
+# Tests 10..15
+for ($i = 0; $i < @new; $i++) {
+	print "not " unless $new[$i] == $old[$i] + 1;
+	printf "ok %d\n", 10 + 2*$i;	# Tests 10,12,14
+	print "not " unless ref $tied[$i] eq $type[$i];
+	printf "ok %d\n", 11 + 2*$i;	# Tests 11,13,15
+}
+

Added: trunk/orca/packages/Storable-0.6 at 3/t/canonical.t
==============================================================================
--- trunk/orca/packages/Storable-0.6 at 3/t/canonical.t	(original)
+++ trunk/orca/packages/Storable-0.6 at 3/t/canonical.t	Sat Jul 13 18:45:54 2002
@@ -0,0 +1,128 @@
+#!./perl
+
+# $Id: canonical.t,v 0.6 1998/06/04 16:08:24 ram Exp $
+#
+#  Copyright (c) 1995-1998, Raphael Manfredi
+#  
+#  You may redistribute only under the terms of the Artistic License,
+#  as specified in the README file that comes with the distribution.
+#  
+# $Log: canonical.t,v $
+# Revision 0.6  1998/06/04  16:08:24  ram
+# Baseline for first beta release.
+#
+
+BEGIN { push @INC, "../blib" }
+
+use Storable qw(freeze thaw dclone);
+use vars qw($debugging $verbose);
+
+print "1..5\n";
+
+sub ok {
+    my($testno, $ok) = @_;
+    print "not " unless $ok;
+    print "ok $testno\n";
+}
+
+
+# Uncomment the folowing line to get a dump of the constructed data structure
+# (you may want to reduce the size of the hashes too)
+# $debugging = 1;
+
+$hashsize = 100;
+$maxhash2size = 100;
+$maxarraysize = 100;
+
+# Use MD5 if its available to make random string keys
+
+eval { require "MD5.pm" };
+$gotmd5 = !$@;
+
+# Use Data::Dumper if debugging and it is available to create an ASCII dump
+
+if ($debugging) {
+    eval { require "Data/Dumper.pm" };
+    $gotdd  = !$@;
+}
+
+ at fixed_strings = ("January", "February", "March", "April", "May", "June",
+		  "July", "August", "September", "October", "November", "December" );
+
+# Build some arbitrarily complex data structure starting with a top level hash
+# (deeper levels contain scalars, references to hashes or references to arrays);
+
+for (my $i = 0; $i < $hashsize; $i++) {
+	my($k) = int(rand(1_000_000));
+	$k = MD5->hexhash($k) if $gotmd5 and int(rand(2));
+	$a1{$k} = { key => "$k", value => $i };
+
+	# A third of the elements are references to further hashes
+
+	if (int(rand(1.5))) {
+		my($hash2) = {};
+		my($hash2size) = int(rand($maxhash2size));
+		while ($hash2size--) {
+			my($k2) = $k . $i . int(rand(100));
+			$hash2->{$k2} = $fixed_strings[rand(int(@fixed_strings))];
+		}
+		$a1{$k}->{value} = $hash2;
+	}
+
+	# A further third are references to arrays
+
+	elsif (int(rand(2))) {
+		my($arr_ref) = [];
+		my($arraysize) = int(rand($maxarraysize));
+		while ($arraysize--) {
+			push(@$arr_ref, $fixed_strings[rand(int(@fixed_strings))]);
+		}
+		$a1{$k}->{value} = $arr_ref;
+	}	
+}
+
+
+print STDERR Data::Dumper::Dumper(\%a1) if ($verbose and $gotdd);
+
+
+# Copy the hash, element by element in order of the keys
+
+foreach $k (sort keys %a1) {
+    $a2{$k} = { key => "$k", value => $a1{$k}->{value} };
+}
+
+# Deep clone the hash
+
+$a3 = dclone(\%a1);
+
+# In canonical mode the frozen representation of each of the hashes
+# should be identical
+
+$Storable::canonical = 1;
+
+$x1 = freeze(\%a1);
+$x2 = freeze(\%a2);
+$x3 = freeze($a3);
+
+ok 1, (length($x1) > $hashsize);	# sanity check
+ok 2, length($x1) == length($x2);	# idem
+ok 3, $x1 eq $x2;
+ok 4, $x1 eq $x3;
+
+# In normal mode it is exceedingly unlikely that the frozen
+# representaions of all the hashes will be the same (normally the hash
+# elements are frozen in the order they are stored internally,
+# i.e. pseudo-randomly).
+
+$Storable::canonical = 0;
+
+$x1 = freeze(\%a1);
+$x2 = freeze(\%a2);
+$x3 = freeze($a3);
+
+
+# Two out of three the same may be a coincidence, all three the same
+# is much, much more unlikely.  Still it could happen, so this test
+# may report a false negative.
+
+ok 5, ($x1 ne $x2) || ($x1 ne $x3);    

Added: trunk/orca/packages/Storable-0.6 at 3/t/store.t
==============================================================================
--- trunk/orca/packages/Storable-0.6 at 3/t/store.t	(original)
+++ trunk/orca/packages/Storable-0.6 at 3/t/store.t	Sat Jul 13 18:45:54 2002
@@ -0,0 +1,108 @@
+#!./perl
+
+# $Id: store.t,v 0.6 1998/06/04 16:08:35 ram Exp $
+#
+#  Copyright (c) 1995-1998, Raphael Manfredi
+#  
+#  You may redistribute only under the terms of the Artistic License,
+#  as specified in the README file that comes with the distribution.
+#
+# $Log: store.t,v $
+# Revision 0.6  1998/06/04  16:08:35  ram
+# Baseline for first beta release.
+#
+
+require 't/dump.pl';
+
+use Storable qw(store retrieve store_fd nstore_fd retrieve_fd);
+
+print "1..20\n";
+
+$a = 'toto';
+$b = \$a;
+$c = bless {}, CLASS;
+$c->{attribute} = 'attrval';
+%a = ('key', 'value', 1, 0, $a, $b, 'cvar', \$c);
+ at a = ('first', undef, 3, -4, -3.14159, 456, 4.5,
+	$b, \$a, $a, $c, \$c, \%a);
+
+print "not " unless defined store(\@a, 't/store');
+print "ok 1\n";
+
+$dumped = &dump(\@a);
+print "ok 2\n";
+
+$root = retrieve('t/store');
+print "not " unless defined $root;
+print "ok 3\n";
+
+$got = &dump($root);
+print "ok 4\n";
+
+print "not " unless $got eq $dumped; 
+print "ok 5\n";
+
+unlink 'store';
+
+package FOO; @ISA = qw(Storable);
+
+sub make {
+	my $self = bless {};
+	$self->{key} = \%main::a;
+	return $self;
+};
+
+package main;
+
+$foo = FOO->make;
+print "not " unless $foo->store('t/store');
+print "ok 6\n";
+
+print "not " unless open(OUT, '>>t/store');
+print "ok 7\n";
+binmode OUT;
+
+print "not " unless defined store_fd(\@a, ::OUT);
+print "ok 8\n";
+print "not " unless defined nstore_fd($foo, ::OUT);
+print "ok 9\n";
+print "not " unless defined nstore_fd(\%a, ::OUT);
+print "ok 10\n";
+
+print "not " unless close(OUT);
+print "ok 11\n";
+
+print "not " unless open(OUT, 't/store');
+binmode OUT;
+
+$r = retrieve_fd(::OUT);
+print "not " unless defined $r;
+print "ok 12\n";
+print "not " unless &dump($foo) eq &dump($r);
+print "ok 13\n";
+
+$r = retrieve_fd(::OUT);
+print "not " unless defined $r;
+print "ok 14\n";
+print "not " unless &dump(\@a) eq &dump($r);
+print "ok 15\n";
+
+$r = retrieve_fd(main::OUT);
+print "not " unless defined $r;
+print "ok 16\n";
+print "not " unless &dump($foo) eq &dump($r);
+print "ok 17\n";
+
+$r = retrieve_fd(::OUT);
+print "not " unless defined $r;
+print "ok 18\n";
+print "not " unless &dump(\%a) eq &dump($r);
+print "ok 19\n";
+
+eval { $r = retrieve_fd(::OUT); };
+print "not " unless $@;
+print "ok 20\n";
+
+close OUT;
+unlink 't/store';
+

Added: trunk/orca/packages/Storable-0.6 at 3/Storable.xs
==============================================================================
--- trunk/orca/packages/Storable-0.6 at 3/Storable.xs	(original)
+++ trunk/orca/packages/Storable-0.6 at 3/Storable.xs	Sat Jul 13 18:45:55 2002
@@ -0,0 +1,2515 @@
+/*
+ * Store and retrieve mechanism.
+ */
+
+/*
+ * $Id: Storable.xs,v 0.6.1.3 1998/07/03 11:36:09 ram Exp $
+ *
+ *  Copyright (c) 1995-1998, Raphael Manfredi
+ *  
+ *  You may redistribute only under the terms of the Artistic License,
+ *  as specified in the README file that comes with the distribution.
+ *
+ * $Log: Storable.xs,v $
+ * Revision 0.6.1.3  1998/07/03  11:36:09  ram
+ * patch3: fixed compatibility (wrt 0.5 at 9) for retrieval of blessed refs
+ * patch3: increased store() throughput significantly
+ *
+ * Revision 0.6.1.2  1998/06/22  09:00:04  ram
+ * patch2: adjust refcnt of tied objects after calling sv_magic()
+ *
+ * Revision 0.6.1.1  1998/06/12  09:46:48  ram
+ * patch1: added workaround for persistent LVALUE-ness in perl5.004
+ * patch1: now handles Perl immortal scalars explicitely
+ * patch1: retrieval of non-immortal undef cannot be shared
+ *
+ * Revision 0.6  1998/06/04  16:08:22  ram
+ * Baseline for first beta release.
+ *
+ */
+
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+/*#define DEBUGME /* Debug mode, turns assertions on as well */
+/*#define DASSERT /* Assertion mode */
+
+/*
+ * Pre PerlIO time when none of USE_PERLIO and PERLIO_IS_STDIO is defined
+ * Provide them with the necessary defines so they can build with pre-5.004.
+ */
+#ifndef USE_PERLIO
+#ifndef PERLIO_IS_STDIO
+#define PerlIO FILE
+#define PerlIO_getc(x) getc(x)
+#define PerlIO_putc(f,x) putc(x,f)
+#define PerlIO_read(x,y,z) fread(y,1,z,x)
+#define PerlIO_write(x,y,z) fwrite(y,1,z,x)
+#define PerlIO_stdoutf printf
+#endif	/* PERLIO_IS_STDIO */
+#endif	/* USE_PERLIO */
+
+/*
+ * Earlier versions of perl might be used, we can't assume they have the latest!
+ */
+#ifndef newRV_noinc
+#define newRV_noinc(sv)		((Sv = newRV(sv)), --SvREFCNT(SvRV(Sv)), Sv)
+#endif
+#ifndef HvSHAREKEYS_off
+#define HvSHAREKEYS_off(hv)	/* Ignore */
+#endif
+
+#ifdef DEBUGME
+#ifndef DASSERT
+#define DASSERT
+#endif
+#define TRACEME(x)	do { PerlIO_stdoutf x; PerlIO_stdoutf("\n"); } while (0)
+#else
+#define TRACEME(x)
+#endif
+
+#ifdef DASSERT
+#define ASSERT(x,y)	do { \
+	if (!x) { PerlIO_stdoutf y; PerlIO_stdoutf("\n"); }} while (0)
+#else
+#define ASSERT(x,y)
+#endif
+
+/*
+ * Type markers.
+ */
+
+#define C(x) ((char) (x))	/* For markers with dynamic retrieval handling */
+
+#define SX_OBJECT	C(0)	/* Already stored object */
+#define SX_LSCALAR	C(1)	/* Scalar (string) forthcoming (length, data) */
+#define SX_ARRAY	C(2)	/* Array forthcominng (size, item list) */
+#define SX_HASH		C(3)	/* Hash forthcoming (size, key/value pair list) */
+#define SX_REF		C(4)	/* Reference to object forthcoming */
+#define SX_UNDEF	C(5)	/* Undefined scalar */
+#define SX_INTEGER	C(6)	/* Integer forthcoming */
+#define SX_DOUBLE	C(7)	/* Double forthcoming */
+#define SX_BYTE		C(8)	/* (signed) byte forthcoming */
+#define SX_NETINT	C(9)	/* Integer in network order forthcoming */
+#define SX_SCALAR	C(10)	/* Scalar (small) forthcoming (length, data) */
+#define SX_TIED_ARRAY  C(11)  /* Tied array forthcoming */
+#define SX_TIED_HASH   C(12)  /* Tied hash forthcoming */
+#define SX_TIED_SCALAR C(13)  /* Tied scalar forthcoming */
+#define SX_SV_UNDEF	C(14)	/* Perl's immortal sv_undef */
+#define SX_SV_YES	C(15)	/* Perl's immortal sv_yes */
+#define SX_SV_NO	C(16)	/* Perl's immortal sv_no */
+#define SX_ERROR	C(17)	/* Error */
+
+/*
+ * Those are only used to retrieve "old" pre-0.6 binary images.
+ */
+#define SX_ITEM		'i'		/* An array item introducer */
+#define SX_IT_UNDEF	'I'		/* Undefined array item */
+#define SX_KEY		'k'		/* An hash key introducer */
+#define SX_VALUE	'v'		/* An hash value introducer */
+#define SX_VL_UNDEF	'V'		/* Undefined hash value */
+
+/*
+ * Notification markers.
+ */
+
+#define SX_BLESS	'b'		/* Object is blessed, class name length <255 */
+#define SX_LG_BLESS	'B'		/* Object is blessed, class name length >255 */
+#define SX_STORED	'X'		/* End of object */
+
+#define LG_BLESS	255		/* Large blessing classname length limit */
+#define LG_SCALAR	255		/* Large scalar length limit */
+
+/*
+ * The following structure is used for hash table key retrieval. Since, when
+ * retrieving objects, we'll be facing blessed hash references, it's best
+ * to pre-allocate that buffer once and resize it as the need arises, never
+ * freeing it (keys will be saved away someplace else anyway, so even large
+ * keys are not enough a motivation to reclaim that space).
+ *
+ * This structure is also used for memory store/retrieve operations which
+ * happen in a fixed place before being malloc'ed elsewhere if persistency
+ * is required. Hence the aptr pointer.
+ */
+struct extendable {
+	char *arena;		/* Will hold hash key strings, resized as needed */
+	STRLEN asiz;		/* Size of aforementionned buffer */
+	char *aptr;			/* Arena pointer, for in-place read/write ops */
+	char *aend;			/* First invalid address */
+};
+
+/*
+ * At store time:
+ * This hash table records the objects which have already been stored.
+ * Those are referred to as SX_OBJECT in the file, and their "tag" (i.e.
+ * an arbitrary sequence number) is used to identify them.
+ *
+ * At retrieve time:
+ * This array table records the objects which have already been retrieved,
+ * as seen by the tag determind by counting the objects themselves. The
+ * reference to that retrieved object is kept in the table, and is returned
+ * when an SX_OBJECT is found bearing that same tag.
+ */
+
+typedef unsigned long stag_t;	/* Used by pre-0.6 binary format */
+
+/*
+ * XXX multi-threading needs context for the following variables...
+ */
+static HV *hseen;			/* which objects have been seen, store time */
+static AV *aseen;			/* which objects have been seen, retrieve time */
+static I32 tagnum;			/* incremented at store time for each seen object */
+static int netorder = 0;	/* true if network order used */
+static int forgive_me = -1;	/* whether to be forgiving... */
+static int canonical;		/* whether to store hashes sorted by key */
+struct extendable keybuf;	/* for hash key retrieval */
+struct extendable membuf;	/* for memory store/retrieve operations */
+
+/*
+ * key buffer handling
+ */
+#define kbuf	keybuf.arena
+#define ksiz	keybuf.asiz
+#define KBUFINIT() do {					\
+	if (!kbuf) {						\
+		TRACEME(("** allocating kbuf of 128 bytes")); \
+		New(10003, kbuf, 128, char);	\
+		ksiz = 128;						\
+	}									\
+} while (0)
+#define KBUFCHK(x) do {			\
+	if (x >= ksiz) {			\
+		TRACEME(("** extending kbuf to %d bytes", x+1)); \
+		Renew(kbuf, x+1, char);	\
+		ksiz = x+1;				\
+	}							\
+} while (0)
+
+/*
+ * memory buffer handling
+ */
+#define mbase	membuf.arena
+#define msiz	membuf.asiz
+#define mptr	membuf.aptr
+#define mend	membuf.aend
+#define MGROW	(1 << 13)
+#define MMASK	(MGROW - 1)
+
+#define round_mgrow(x)	\
+	((unsigned long) (((unsigned long) (x) + MMASK) & ~MMASK))
+#define trunc_int(x)	\
+	((unsigned long) ((unsigned long) (x) & ~(sizeof(int)-1)))
+#define int_aligned(x)	\
+	((unsigned long) (x) == trunc_int(x))
+
+#define MBUF_INIT(x) do {				\
+	if (!mbase) {						\
+		TRACEME(("** allocating mbase of %d bytes", MGROW)); \
+		New(10003, mbase, MGROW, char);	\
+		msiz = MGROW;					\
+	}									\
+	mptr = mbase;						\
+	if (x)								\
+		mend = mbase + x;				\
+	else								\
+		mend = mbase + msiz;			\
+} while (0)
+
+#define MBUF_SIZE()	(mptr - mbase)
+
+/*
+ * Use SvPOKp(), because SvPOK() fails on tainted scalars.
+ * See store_scalar() for other usage of this workaround.
+ */
+#define MBUF_LOAD(v) do {				\
+	if (!SvPOKp(v))						\
+		croak("Not a scalar string");	\
+	mptr = mbase = SvPV(v, msiz);		\
+	mend = mbase + msiz;				\
+} while (0)
+
+#define MBUF_XTEND(x) do {			\
+	int nsz = (int) round_mgrow((x)+msiz);	\
+	int offset = mptr - mbase;		\
+	TRACEME(("** extending mbase to %d bytes", nsz));	\
+	Renew(mbase, nsz, char);		\
+	msiz = nsz;						\
+	mptr = mbase + offset;			\
+	mend = mbase + nsz;				\
+} while (0)
+
+#define MBUF_CHK(x) do {			\
+	if ((mptr + (x)) > mend)		\
+		MBUF_XTEND(x);				\
+} while (0)
+
+#define MBUF_GETC(x) do {			\
+	if (mptr < mend)				\
+		x = (int) (unsigned char) *mptr++;	\
+	else							\
+		return (SV *) 0;			\
+} while (0)
+
+#define MBUF_GETINT(x) do {				\
+	if ((mptr + sizeof(int)) <= mend) {	\
+		if (int_aligned(mptr))			\
+			x = *(int *) mptr;			\
+		else							\
+			memcpy(&x, mptr, sizeof(int));	\
+		mptr += sizeof(int);			\
+	} else								\
+		return (SV *) 0;				\
+} while (0)
+
+#define MBUF_READ(x,s) do {			\
+	if ((mptr + (s)) <= mend) {		\
+		memcpy(x, mptr, s);			\
+		mptr += s;					\
+	} else							\
+		return (SV *) 0;			\
+} while (0)
+
+#define MBUF_SAFEREAD(x,s,z) do {	\
+	if ((mptr + (s)) <= mend) {		\
+		memcpy(x, mptr, s);			\
+		mptr += s;					\
+	} else {						\
+		sv_free(z);					\
+		return (SV *) 0;			\
+	}								\
+} while (0)
+
+#define MBUF_PUTC(c) do {			\
+	if (mptr < mend)				\
+		*mptr++ = (char) c;			\
+	else {							\
+		MBUF_XTEND(1);				\
+		*mptr++ = (char) c;			\
+	}								\
+} while (0)
+
+#define MBUF_PUTINT(i) do {			\
+	MBUF_CHK(sizeof(int));			\
+	if (int_aligned(mptr))			\
+		*(int *) mptr = i;			\
+	else							\
+		memcpy(mptr, &i, sizeof(int));	\
+	mptr += sizeof(int);			\
+} while (0)
+
+#define MBUF_WRITE(x,s) do {		\
+	MBUF_CHK(s);					\
+	memcpy(mptr, x, s);				\
+	mptr += s;						\
+} while (0)
+
+
+#define mbuf	membuf.arena
+#define msiz	membuf.asiz
+
+#define svis_REF	0
+#define svis_SCALAR	1
+#define svis_ARRAY	2
+#define svis_HASH	3
+#define svis_TIED	4
+#define svis_OTHER	5
+
+/*
+ * Before 0.6, the magic string was "perl-store" (binary version number 0).
+ *
+ * Since 0.6 introduced many binary incompatibilities, the magic string has
+ * been changed to "pst0" to allow an old image to be properly retrieved by
+ * a newer Storable, but ensure a newer image cannot be retrieved with an
+ * older version.
+ */
+static char old_magicstr[] = "perl-store";	/* Magic number before 0.6 */
+static char magicstr[] = "pst0";			/* Used as a magic number */
+
+#define STORABLE_BINARY		1				/* Binary "version" number */
+
+/*
+ * Useful store shortcuts...
+ */
+#define PUTMARK(x) do {					\
+	if (!f)								\
+		MBUF_PUTC(x);					\
+	else if (PerlIO_putc(f, x) == EOF)	\
+		return -1;						\
+	} while (0)
+
+#ifdef HAS_HTONL
+#define WLEN(x)	do {				\
+	if (netorder) {					\
+		int y = (int) htonl(x);		\
+		if (!f)						\
+			MBUF_PUTINT(y);			\
+		else if (PerlIO_write(f, &y, sizeof(y)) != sizeof(y))	\
+			return -1;				\
+	} else {						\
+		if (!f)						\
+			MBUF_PUTINT(x);			\
+		else if (PerlIO_write(f, &x, sizeof(x)) != sizeof(x))	\
+			return -1;				\
+	}								\
+} while (0)
+#else
+#define WLEN(x)	do {				\
+	if (!f)							\
+		MBUF_PUTINT(x);				\
+	else if (PerlIO_write(f, &x, sizeof(x)) != sizeof(x))	\
+		return -1;					\
+	} while (0)
+#endif
+
+#define WRITE(x,y) do {						\
+	if (!f)									\
+		MBUF_WRITE(x,y);					\
+	else if (PerlIO_write(f, x, y) != y)	\
+		return -1;							\
+	} while (0)
+
+#define STORE_SCALAR(pv, len) do {		\
+	if (len < LG_SCALAR) {				\
+		unsigned char clen = (unsigned char) len;	\
+		PUTMARK(SX_SCALAR);				\
+		PUTMARK(clen);					\
+		if (len)						\
+			WRITE(pv, len);				\
+	} else {							\
+		PUTMARK(SX_LSCALAR);			\
+		WLEN(len);						\
+		WRITE(pv, len);					\
+	}									\
+} while (0)
+
+/*
+ * Store undef in arrays and hashes without recusrsing through store().
+ */
+#define STORE_UNDEF() do {				\
+	tagnum++;							\
+	PUTMARK(SX_UNDEF);					\
+	PUTMARK(SX_STORED);					\
+} while (0)
+
+/*
+ * Useful retrieve shortcuts...
+ */
+
+#define GETCHAR() \
+	(f ? PerlIO_getc(f) : (mptr >= mend ? EOF : (int) *mptr++))
+
+#define GETMARK(x) do {						\
+	if (!f)									\
+		MBUF_GETC(x);						\
+	else if ((x = PerlIO_getc(f)) == EOF)	\
+		return (SV *) 0;					\
+} while (0)
+
+#ifdef HAS_NTOHL
+#define RLEN(x)	do {					\
+	if (!f)								\
+		MBUF_GETINT(x);					\
+	else if (PerlIO_read(f, &x, sizeof(x)) != sizeof(x))	\
+		return (SV *) 0;				\
+	if (netorder)						\
+		x = (int) ntohl(x);				\
+} while (0)
+#else
+#define RLEN(x)	do {					\
+	if (!f)								\
+		MBUF_GETINT(x);					\
+	else if (PerlIO_read(f, &x, sizeof(x)) != sizeof(x))	\
+		return (SV *) 0;				\
+} while (0)
+#endif
+
+#define READ(x,y) do {					\
+	if (!f)								\
+		MBUF_READ(x, y);				\
+	else if (PerlIO_read(f, x, y) != y)	\
+		return (SV *) 0;				\
+} while (0)
+
+#define SAFEREAD(x,y,z) do { 				\
+	if (!f)									\
+		MBUF_SAFEREAD(x,y,z);				\
+	else if (PerlIO_read(f, x, y) != y)	 {	\
+		sv_free(z);							\
+		return (SV *) 0;					\
+	}										\
+} while (0)
+
+/*
+ * This macro is used at retrieve time, to remember where object 'y', bearing a
+ * given tag 'tagnum', has been retrieved. Next time we see an SX_OBJECT marker,
+ * we'll therefore know where it has been retrieved and will be able to
+ * share the same reference, as in the original stored memory image.
+ */
+#define SEEN(y) do {						\
+	if (!y)									\
+		return (SV *) 0;					\
+	if (av_store(aseen, tagnum++, SvREFCNT_inc(y)) == 0) \
+		return (SV *) 0;					\
+	TRACEME(("aseen(#%d) = 0x%lx (refcnt=%d)", tagnum-1, \
+		(unsigned long) y, SvREFCNT(y)-1)); \
+	} while (0)
+
+static int store();
+static SV *retrieve();
+
+/*
+ * store_ref
+ *
+ * Store a reference.
+ * Layout is SX_REF <object>.
+ */
+static int store_ref(f, sv)
+PerlIO *f;
+SV *sv;
+{
+	TRACEME(("store_ref (0x%lx)", (unsigned long) sv));
+
+	PUTMARK(SX_REF);
+	sv = SvRV(sv);
+	return store(f, sv);
+}
+
+/*
+ * store_scalar
+ *
+ * Store a scalar.
+ *
+ * Layout is SX_LSCALAR <length> <data>, SX_SCALAR <lenght> <data> or SX_UNDEF.
+ * The <data> section is omitted if <length> is 0.
+ *
+ * If integer or double, the layout is SX_INTEGER <data> or SX_DOUBLE <data>.
+ * Small integers (within [-127, +127]) are stored as SX_BYTE <byte>.
+ */
+static int store_scalar(f, sv)
+PerlIO *f;
+SV *sv;
+{
+	IV iv;
+	char *pv;
+	STRLEN len;
+	U32 flags = SvFLAGS(sv);			/* "cc -O" may put it in register */
+
+	TRACEME(("store_scalar (0x%lx)", (unsigned long) sv));
+
+	/*
+	 * For efficiency, break the SV encapsulation by peaking at the flags
+	 * directly without using the Perl macros to avoid dereferencing
+	 * sv->sv_flags each time we wish to check the flags.
+	 */
+
+	if (!(flags & SVf_OK)) {			/* !SvOK(sv) */
+		if (sv == &sv_undef) {
+			TRACEME(("immortal undef"));
+			PUTMARK(SX_SV_UNDEF);
+		} else {
+			TRACEME(("undef"));
+			PUTMARK(SX_UNDEF);
+		}
+		return 0;
+	}
+
+	/*
+	 * Always store the string representation of a scalar if it exists.
+	 * Gisle Aas provided me with this test case, better than a long speach:
+	 *
+	 *  perl -MDevel::Peek -le '$a="abc"; $a+0; Dump($a)'
+	 *  SV = PVNV(0x80c8520)
+	 *       REFCNT = 1
+	 *       FLAGS = (NOK,POK,pNOK,pPOK)
+	 *       IV = 0
+	 *       NV = 0
+	 *       PV = 0x80c83d0 "abc"\0
+	 *       CUR = 3
+	 *       LEN = 4
+	 *
+	 * Write SX_SCALAR, length, followed by the actual data.
+	 *
+	 * Otherwise, write an SX_BYTE, SX_INTEGER or an SX_DOUBLE as
+	 * appropriate, followed by the actual (binary) data. A double
+	 * is written as a string if network order, for portability.
+	 *
+	 * NOTE: instead of using SvNOK(sv), we test for SvNOKp(sv).
+	 * The reason is that when the scalar value is tainted, the SvNOK(sv)
+	 * value is false.
+	 *
+	 * The test for a read-only scalar with both POK and NOK set is meant
+	 * to quickly detect &sv_yes and &sv_no without having to pay the address
+	 * comparison for each scalar we store.
+	 */
+
+#define SV_MAYBE_IMMORTAL (SVf_READONLY|SVf_POK|SVf_NOK)
+
+	if ((flags & SV_MAYBE_IMMORTAL) == SV_MAYBE_IMMORTAL) {
+		if (sv == &sv_yes) {
+			TRACEME(("immortal yes"));
+			PUTMARK(SX_SV_YES);
+		} else if (sv == &sv_no) {
+			TRACEME(("immortal no"));
+			PUTMARK(SX_SV_NO);
+		} else {
+			pv = SvPV(sv, len);			/* We know it's SvPOK */
+			goto string;				/* Share code below */
+		}
+	} else if (flags & SVp_POK) {		/* SvPOKp(sv) => string */
+		pv = SvPV(sv, len);
+
+		/*
+		 * Will come here from below with pv and len set if double & netorder,
+		 * or from above if it was readonly, POK and NOK but neither &sv_yes
+		 * nor &sv_no.
+		 */
+	string:
+
+		STORE_SCALAR(pv, len);
+		TRACEME(("ok (scalar 0x%lx '%s', length = %d)",
+			(unsigned long) sv, SvPVX(sv), len));
+
+	} else if (flags & SVp_NOK) {		/* SvNOKp(sv) => double */
+		double nv = SvNV(sv);
+
+		/*
+		 * Watch for number being an integer in disguise.
+		 */
+		if (nv == (double) (iv = I_V(nv))) {
+			TRACEME(("double %lf is actually integer %ld", nv, iv));
+			goto integer;		/* Share code below */
+		}
+
+		if (netorder) {
+			TRACEME(("double %lf stored as string", nv));
+			pv = SvPV(sv, len);
+			goto string;		/* Share code below */
+		}
+
+		PUTMARK(SX_DOUBLE);
+		WRITE(&nv, sizeof(nv));
+
+		TRACEME(("ok (double 0x%lx, value = %lf)", (unsigned long) sv, nv));
+
+	} else if (flags & SVp_IOK) {		/* SvIOKp(sv) => integer */
+		iv = SvIV(sv);
+
+		/*
+		 * Will come here from above with iv set if double is an integer.
+		 */
+	integer:
+
+		/*
+		 * Optimize small integers into a single byte, otherwise store as
+		 * a real integer (converted into network order if they asked).
+		 */
+
+		if (iv >= -128 && iv <= 127) {
+			unsigned char siv = (unsigned char) (iv + 128);	/* [0,255] */
+			PUTMARK(SX_BYTE);
+			PUTMARK(siv);
+			TRACEME(("small integer stored as %d", siv));
+		} else if (netorder) {
+			int niv;
+#ifdef HAS_HTONL
+			niv = (int) htonl(iv);
+			TRACEME(("using network order"));
+#else
+			niv = (int) iv;
+			TRACEME(("as-is for network order"));
+#endif
+			PUTMARK(SX_NETINT);
+			WRITE(&niv, sizeof(niv));
+		} else {
+			PUTMARK(SX_INTEGER);
+			WRITE(&iv, sizeof(iv));
+		}
+
+		TRACEME(("ok (integer 0x%lx, value = %d)", (unsigned long) sv, iv));
+
+	} else
+		croak("Can't determine type of %s(0x%lx)", sv_reftype(sv, FALSE),
+			(unsigned long) sv);
+
+	return 0;		/* Ok, no recursion on scalars */
+}
+
+/*
+ * store_array
+ *
+ * Store an array.
+ *
+ * Layout is SX_ARRAY <size> followed by each item, in increading index order.
+ * Each item is stored as <object>.
+ */
+static int store_array(f, av)
+PerlIO *f;
+AV *av;
+{
+	SV **sav;
+	I32 len = av_len(av) + 1;
+	I32 i;
+	int ret;
+
+	TRACEME(("store_array (0x%lx)", (unsigned long) av));
+
+	/* 
+	 * Signal array by emitting SX_ARRAY, followed by the array length.
+	 */
+
+	PUTMARK(SX_ARRAY);
+	WLEN(len);
+	TRACEME(("size = %d", len));
+
+	/*
+	 * Now store each item recursively.
+	 */
+
+	for (i = 0; i < len; i++) {
+		sav = av_fetch(av, i, 0);
+		if (!sav) {
+			TRACEME(("(#%d) undef item", i));
+			STORE_UNDEF();
+			continue;
+		}
+		TRACEME(("(#%d) item", i));
+		if (ret = store(f, *sav))
+			return ret;
+	}
+
+	TRACEME(("ok (array)"));
+
+	return 0;
+}
+
+/*
+ * sortcmp
+ *
+ * Sort two SVs
+ * Borrowed from perl source file pp_ctl.c, where it is used by pp_sort.
+ */
+static int
+sortcmp(a, b)
+const void *a;
+const void *b;
+{
+	return sv_cmp(*(SV * const *) a, *(SV * const *) b);
+}
+
+
+/*
+ * store_hash
+ *
+ * Store an hash table.
+ *
+ * Layout is SX_HASH <size> followed by each key/value pair, in random order.
+ * Values are stored as <object>.
+ * Keys are stored as <length> <data>, the <data> section being omitted
+ * if length is 0.
+ */
+static int store_hash(f, hv)
+PerlIO *f;
+HV *hv;
+{
+	I32 len = HvKEYS(hv);
+	I32 i;
+	int ret = 0;
+	I32 riter;
+	HE *eiter;
+
+	TRACEME(("store_hash (0x%lx)", (unsigned long) hv));
+
+	/* 
+	 * Signal hash by emitting SX_HASH, followed by the table length.
+	 */
+
+	PUTMARK(SX_HASH);
+	WLEN(len);
+	TRACEME(("size = %d", len));
+
+	/*
+	 * Save possible iteration state via each() on that table.
+	 */
+
+	riter = HvRITER(hv);
+	eiter = HvEITER(hv);
+	hv_iterinit(hv);
+
+	/*
+	 * Now store each item recursively.
+	 *
+     * If canonical is defined to some true value then store each
+     * key/value pair in sorted order otherwise the order is random.
+	 *
+	 * Fetch the value from perl only once per store() operation, and only
+	 * when needed.
+	 */
+
+	if (
+		canonical == 1 ||
+		(canonical < 0 && (canonical =
+			SvTRUE(perl_get_sv("Storable::canonical", TRUE)) ? 1 : 0))
+	) {
+		/*
+		 * Storing in order, sorted by key.
+		 * Run through the hash, building up an array of keys in a
+		 * mortal array, sort the array and then run through the
+		 * array.  
+		 */
+
+		AV *av = newAV();
+
+		TRACEME(("using canonical order"));
+
+		for (i = 0; i < len; i++) {
+			HE *he = hv_iternext(hv);
+			SV *key = hv_iterkeysv(he);
+			av_push(av, key);
+		}
+			
+		qsort((char *) AvARRAY(av), len, sizeof(SV *), sortcmp);
+
+		for (i = 0; i < len; i++) {
+			char *keyval;
+			I32 keylen;
+			SV *key = av_shift(av);
+			HE *he  = hv_fetch_ent(hv, key, 0, 0);
+			SV *val = HeVAL(he);
+			if (val == 0)
+				return 1;		/* Internal error, not I/O error */
+			
+			/*
+			 * Store value first, if defined.
+			 */
+			
+			if (!SvOK(val)) {
+				TRACEME(("undef value"));
+				STORE_UNDEF();
+			} else {
+				TRACEME(("(#%d) value 0x%lx", i, (unsigned long) val));
+				if (ret = store(f, val))
+					goto out;
+			}
+
+			/*
+			 * Write key string.
+			 * Keys are written after values to make sure retrieval
+			 * can be optimal in terms of memory usage, where keys are
+			 * read into a fixed unique buffer called kbuf.
+			 * See retrieve_hash() for details.
+			 */
+			 
+			keyval = hv_iterkey(he, &keylen);
+			TRACEME(("(#%d) key '%s'", i, keyval));
+			WLEN(keylen);
+			if (keylen)
+				WRITE(keyval, keylen);
+		}
+
+		/* 
+		 * Free up the temporary array
+		 */
+
+		av_undef(av);
+		sv_free((SV *) av);
+
+	} else {
+
+		/*
+		 * Storing in "random" order (in the order the keys are stored
+		 * within the the hash).  This is the default and will be faster!
+		 */
+  
+		for (i = 0; i < len; i++) {
+			char *key;
+			I32 len;
+			SV *val = hv_iternextsv(hv, &key, &len);
+
+			if (val == 0)
+				return 1;		/* Internal error, not I/O error */
+
+			/*
+			 * Store value first, if defined.
+			 */
+
+			if (!SvOK(val)) {
+				TRACEME(("undef value"));
+				STORE_UNDEF();
+			} else {
+				TRACEME(("(#%d) value 0x%lx", i, (unsigned long) val));
+				if (ret = store(f, val))
+					goto out;
+			}
+
+			/*
+			 * Write key string.
+			 * Keys are written after values to make sure retrieval
+			 * can be optimal in terms of memory usage, where keys are
+			 * read into a fixed unique buffer called kbuf.
+			 * See retrieve_hash() for details.
+			 */
+
+			TRACEME(("(#%d) key '%s'", i, key));
+			WLEN(len);
+			if (len)
+				WRITE(key, len);
+		}
+    }
+
+	TRACEME(("ok (hash 0x%lx)", (unsigned long) hv));
+
+out:
+	HvRITER(hv) = riter;		/* Restore hash iterator state */
+	HvEITER(hv) = eiter;
+
+	return ret;
+}
+
+/*
+ * store_tied
+ *
+ * When storing a tied object (be it a tied scalar, array or hash), we lay out
+ * a special mark, followed by the underlying tied object. For instance, when
+ * dealing with a tied hash, we store SX_TIED_HASH <hash object>, where
+ * <hash object> stands for the serialization of the tied hash.
+ */
+static int store_tied(f, sv)
+PerlIO *f;
+SV *sv;
+{
+	MAGIC *mg;
+	int ret = 0;
+	int svt = SvTYPE(sv);
+	char mtype = 'P';
+
+	TRACEME(("store_tied (0x%lx)", (unsigned long) sv));
+
+	/*
+	 * We have a small run-time penalty here because we chose to factorise
+	 * all tieds objects into the same routine, and not have a store_tied_hash,
+	 * a store_tied_array, etc...
+	 *
+	 * Don't use a switch() statement, as most compilers don't optimize that
+	 * well for 2/3 values. An if() else if() cascade is just fine. We put
+	 * tied hashes first, as they are the most likely beasts.
+	 */
+
+	if (svt == SVt_PVHV) {
+		TRACEME(("tied hash"));
+		PUTMARK(SX_TIED_HASH);			/* Introduces tied hash */
+	} else if (svt == SVt_PVAV) {
+		TRACEME(("tied array"));
+		PUTMARK(SX_TIED_ARRAY);			/* Introduces tied array */
+	} else {
+		TRACEME(("tied scalar"));
+		PUTMARK(SX_TIED_SCALAR);		/* Introduces tied scalar */
+		mtype = 'q';
+	}
+
+	if (!(mg = mg_find(sv, mtype)))
+		croak("No magic '%c' found while storing tied %s", mtype,
+			(svt == SVt_PVHV) ? "hash" :
+				(svt == SVt_PVAV) ? "array" : "scalar");
+
+	/*
+	 * The mg->mg_obj found by mg_find() above actually points to the
+	 * underlying tied Perl object implementation. For instance, if the
+	 * original SV was that of a tied array, then mg->mg_obj is an AV.
+	 *
+	 * Note that we store the Perl object as-is. We don't call its FETCH
+	 * method along the way. At retrieval time, we won't call its STORE
+	 * method either, but the tieing magic will be re-installed. In itself,
+	 * that ensures that the tieing semantics are preserved since futher
+	 * accesses on the retrieved object will indeed call the magic methods...
+	 */
+
+	if (ret = store(f, mg->mg_obj))
+		return ret;
+
+	TRACEME(("ok (tied)"));
+
+	return 0;
+}
+
+/*
+ * store_other
+ *
+ * We don't know how to store the item we reached, so return an error condition.
+ * (it's probably a GLOB, some CODE reference, etc...)
+ *
+ * If they defined the `forgive_me' variable at the Perl level to some
+ * true value, then don't croak, just warn, and store a placeholder string
+ * instead.
+ */
+static int store_other(f, sv)
+PerlIO *f;
+SV *sv;
+{
+	STRLEN len;
+	static char buf[80];
+
+	TRACEME(("store_other"));
+
+	/*
+	 * Fetch the value from perl only once per store() operation.
+	 */
+
+	if (
+		forgive_me == 0 ||
+		(forgive_me < 0 && !(forgive_me =
+			SvTRUE(perl_get_sv("Storable::forgive_me", TRUE)) ? 1 : 0))
+	)
+		croak("Can't store %s items", sv_reftype(sv, FALSE));
+
+	warn("Can't store %s items", sv_reftype(sv, FALSE));
+
+	/*
+	 * Store placeholder string as a scalar instead...
+	 */
+
+	(void) sprintf(buf, "You lost %s(0x%lx)\0", sv_reftype(sv, FALSE),
+		(unsigned long) sv);
+
+	len = strlen(buf);
+	STORE_SCALAR(buf, len);
+	TRACEME(("ok (dummy \"%s\", length = %d)", buf, len));
+
+	return 0;
+}
+
+/*
+ * Dynamic dispatching table for SV store.
+ */
+static int (*sv_store[])() = {
+	store_ref,		/* svis_REF */
+	store_scalar,	/* svis_SCALAR */
+	store_array,	/* svis_ARRAY */
+	store_hash,		/* svis_HASH */
+	store_tied,		/* svis_TIED */
+	store_other,	/* svis_OTHER */
+};
+
+#define SV_STORE(x)	(*sv_store[x])
+
+/*
+ * sv_type
+ *
+ * WARNING: partially duplicates Perl's sv_reftype for speed.
+ *
+ * Returns the type of the SV, identified by an integer. That integer
+ * may then be used to index the dynamic routine dispatch table.
+ */
+static int sv_type(sv)
+SV *sv;
+{
+	switch (SvTYPE(sv)) {
+	case SVt_NULL:
+	case SVt_IV:
+	case SVt_NV:
+		/*
+		 * No need to check for ROK, that can't be set here since there
+		 * is no field capable of hodling the xrv_rv reference.
+		 */
+		return svis_SCALAR;
+	case SVt_PV:
+	case SVt_RV:
+	case SVt_PVIV:
+	case SVt_PVNV:
+		/*
+		 * Starting from SVt_PV, it is possible to have the ROK flag
+		 * set, the pointer to the other SV being either stored in
+		 * the xrv_rv (in the case of a pure SVt_RV), or as the
+		 * xpv_pv field of an SVt_PV and its heirs.
+		 *
+		 * However, those SV cannot be magical or they would be an
+		 * SVt_PVMG at least.
+		 */
+		return SvROK(sv) ? svis_REF : svis_SCALAR;
+	case SVt_PVMG:
+	case SVt_PVLV:		/* Workaround for perl5.004_04 "LVALUE" bug */
+	case SVt_PVBM:
+		if (SvRMAGICAL(sv) && (mg_find(sv, 'q')))
+			return svis_TIED;
+		return SvROK(sv) ? svis_REF : svis_SCALAR;
+	case SVt_PVAV:
+		if (SvRMAGICAL(sv) && (mg_find(sv, 'P')))
+			return svis_TIED;
+		return svis_ARRAY;
+	case SVt_PVHV:
+		if (SvRMAGICAL(sv) && (mg_find(sv, 'P')))
+			return svis_TIED;
+		return svis_HASH;
+	default:
+		break;
+	}
+
+	return svis_OTHER;
+}
+
+/*
+ * store
+ *
+ * Recursively store objects pointed to by the sv to the specified file.
+ *
+ * Layout is <content> SX_STORED or SX_OBJECT <tagnum> SX_STORED if we
+ * reach an already stored object (one for which storage has started--
+ * it may not be over if we have a self-referenced structure). This data set
+ * forms a stored <object>.
+ */
+static int store(f, sv)
+PerlIO *f;
+SV *sv;
+{
+	SV **svh;
+	int ret;
+	int type;
+	SV *tag;
+
+	TRACEME(("store (0x%lx)", (unsigned long) sv));
+
+	/*
+	 * If object has already been stored, do not duplicate data.
+	 * Simply emit the SX_OBJECT marker followed by its tag data.
+	 * The tag is always written in network order.
+	 */
+
+	svh = hv_fetch(hseen, (char *) &sv, sizeof(sv), FALSE);
+	if (svh) {
+		I32 tagval = htonl((I32) (*svh));
+		TRACEME(("object 0x%lx seen as #%d.", (unsigned long) sv, tagval));
+		PUTMARK(SX_OBJECT);
+		WRITE(&tagval, sizeof(I32));
+		return 0;
+	}
+
+	/*
+	 * Allocate a new tag and associate it with the address of the sv being
+	 * stored, before recursing...
+	 *
+	 * In order to avoid creating new SvIVs to hold the tagnum we just
+	 * cast the tagnum to a SV pointer and store that in the hash.  This
+	 * means that we must clean up the hash manually afterwards, but gives
+	 * us a 15% throughput increase.
+	 */
+
+	if (!hv_store(hseen, (char *) &sv, sizeof(sv), (SV*) (tagnum++), 0))
+		return -1;
+	TRACEME(("recorded 0x%lx as object #%d", (unsigned long) sv, tagnum));
+
+	/*
+	 * Call the proper routine to store this SV.
+	 * Abort immediately if we get a non-zero status back.
+	 */
+
+	type = sv_type(sv);
+	TRACEME(("storing 0x%lx #%d type=%d...", (unsigned long) sv, tagnum, type));
+	if (ret = SV_STORE(type)(f, sv))
+		return ret;
+
+	/*
+	 * If object is blessed, notify the blessing now.
+	 *
+	 * Since the storable mechanism is going to make usage of lots
+	 * of blessed objects (!), we're trying to optimize the cost
+	 * by having two separate blessing notifications:
+	 *    SX_BLESS <char-len> <class> for short classnames (<255 chars)
+	 *    SX_LG_BLESS <int-len> <class> for larger classnames.
+	 */
+
+	if (SvOBJECT(sv)) {
+		char *class = HvNAME(SvSTASH(sv));
+		I32 len = strlen(class);
+		unsigned char clen;
+		TRACEME(("blessing 0x%lx in %s", (unsigned long) sv, class));
+		if (len <= LG_BLESS) {
+			PUTMARK(SX_BLESS);
+			clen = (unsigned char) len;
+			PUTMARK(clen);
+		} else {
+			PUTMARK(SX_LG_BLESS);
+			WLEN(len);
+		}
+		WRITE(class, len);		/* Final \0 is omitted */
+	}
+
+	PUTMARK(SX_STORED);
+	TRACEME(("ok (store 0x%lx)", (unsigned long) sv));
+
+	return 0;	/* Done, with success */
+}
+
+/*
+ * magic_write
+ *
+ * Write magic number and system information into the file.
+ * Layout is <magic> <network> [<len> <byteorder> <sizeof int> <sizeof long>
+ * <sizeof ptr>] where <len> is the length of the byteorder hexa string.
+ * All size and lenghts are written as single characters here.
+ *
+ * Note that no byte ordering info is emitted when <network> is true, since
+ * integers will be emitted in network order in that case.
+ */
+static int magic_write(f, use_network_order)
+PerlIO *f;
+int use_network_order;
+{
+	char buf[256];	/* Enough room for 256 hexa digits */
+	unsigned char c;
+
+	TRACEME(("magic_write on fd=%d", fileno(f)));
+
+	if (f)
+		WRITE(magicstr, strlen(magicstr));	/* Don't write final \0 */
+
+	/*
+	 * Starting with 0.6, the "use_network_order" byte flag is also used to
+	 * indicate the version number of the binary image, encoded in the upper
+	 * bits. The bit 0 is always used to indicate network order.
+	 */
+
+	c = (unsigned char)
+		((use_network_order ? 0x1 : 0x0) | (STORABLE_BINARY << 1));
+	PUTMARK(c);
+
+	if (use_network_order)
+		return 0;						/* Don't bother with byte ordering */
+
+	sprintf(buf, "%lx", (unsigned long) BYTEORDER);
+	c = (unsigned char) strlen(buf);
+	PUTMARK(c);
+	WRITE(buf, (unsigned int) c);		/* Don't write final \0 */
+	PUTMARK((unsigned char) sizeof(int));
+	PUTMARK((unsigned char) sizeof(long));
+	PUTMARK((unsigned char) sizeof(char *));
+
+	TRACEME(("ok (magic_write byteorder = 0x%lx [%d], I%d L%d P%d)",
+		(unsigned long) BYTEORDER, (int) c,
+		sizeof(int), sizeof(long), sizeof(char *)));
+
+	return 0;
+}
+
+/*
+ * do_store
+ *
+ * Common code for pstore() and net_pstore().
+ */
+static int do_store(f, sv, use_network_order)
+PerlIO *f;
+SV *sv;
+int use_network_order;
+{
+	int status;
+
+	netorder = use_network_order;	/* Global, not suited for multi-thread */
+	forgive_me = -1;				/* Unknown, fetched from perl if needed */
+	canonical = -1;					/* Idem */
+	tagnum = 0;						/* Reset tag numbers */
+
+	if (-1 == magic_write(f, netorder))	/* Emit magic number and system info */
+		return 0;						/* Error */
+
+	/*
+	 * Ensure sv is actually a reference. From perl, we called something
+	 * like:
+	 *       pstore(FILE, \@array);
+	 * so we must get the scalar value behing that reference.
+	 */
+
+	if (!SvROK(sv))
+		croak("Not a reference");
+	sv = SvRV(sv);			/* So follow it to know what to store */
+
+	/*
+	 * The hash table used to keep track of each SV stored and their
+	 * associated tag numbers is special. It is "abused" because the
+	 * values stored are not real SV, just integers cast to (SV *),
+	 * which explains the freeing below.
+	 *
+	 * It is also one possible bottlneck to achieve good storing speed,
+	 * so the "shared keys" optimization is turned off (unlikely to be
+	 * of any use here), and the hash table is "pre-extended". Together,
+	 * those optimizations increase the throughput by 12%.
+	 */
+
+	hseen = newHV();			/* Table where seen objects are stored */
+	HvSHAREKEYS_off(hseen);
+
+	/*
+	 * The following does not work well with perl5.004_04, and causes
+	 * a core dump later on, in a completely unrelated spot, which
+	 * makes me think there is a memory corruption going on.
+	 *
+	 * Calling hv_ksplit(hseen, HBUCKETS) instead of manually hacking
+	 * it below does not make any difference. It seems to work fine
+	 * with perl5.004_68 but given the probable nature of the bug,
+	 * that does not prove anything.
+	 *
+	 * It's a shame because increasing the amount of buckets raises
+	 * store() throughput by 5%, but until I figure this out, I can't
+	 * allow for this to go into production.
+	 */
+#if 0
+#define HBUCKETS	4096			/* Buckets for %hseen */
+	HvMAX(hseen) = HBUCKETS - 1;	/* keys %hseen = $HBUCKETS; */
+#endif
+
+	/*
+	 * Recursively store object...
+	 */
+
+	status = store(f, sv);		/* Just do it! */
+
+	/*
+	 * Need to free the hseen table, but since we have stored fake
+	 * value pointers in it, we need to make them real first.
+	 */
+
+	{
+		HE * he;
+
+		hv_iterinit(hseen);
+		while (he = hv_iternext(hseen))
+			HeVAL(he) = &sv_undef;
+	}
+	hv_undef(hseen);		/* Free seen object table */
+	sv_free((SV *) hseen);	/* Free HV */
+
+	TRACEME(("do_store returns %d", status));
+
+	return status == 0;
+}
+
+/*
+ * mbuf2sv
+ *
+ * Build a new SV out of the content of the internal memory buffer.
+ */
+static SV *mbuf2sv()
+{
+	return newSVpv(mbase, MBUF_SIZE());
+}
+
+/*
+ * mstore
+ *
+ * Store the transitive data closure of given object to memory.
+ * Returns undef on error, a scalar value containing the data otherwise.
+ */
+SV *mstore(sv)
+SV *sv;
+{
+	TRACEME(("mstore"));
+	MBUF_INIT(0);
+	if (!do_store(0, sv, FALSE))		/* Not in network order */
+		return &sv_undef;
+
+	return mbuf2sv();
+}
+
+/*
+ * net_mstore
+ *
+ * Same as mstore(), but network order is used for integers and doubles are
+ * emitted as strings.
+ */
+SV *net_mstore(sv)
+SV *sv;
+{
+	TRACEME(("net_mstore"));
+	MBUF_INIT(0);
+	if (!do_store(0, sv, TRUE))	/* Use network order */
+		return &sv_undef;
+
+	return mbuf2sv();
+}
+
+/*
+ * pstore
+ *
+ * Store the transitive data closure of given object to disk.
+ * Returns 0 on error, a true value otherwise.
+ */
+int pstore(f, sv)
+PerlIO *f;
+SV *sv;
+{
+	TRACEME(("pstore"));
+	return do_store(f, sv, FALSE);	/* Not in network order */
+
+}
+
+/*
+ * net_pstore
+ *
+ * Same as pstore(), but network order is used for integers and doubles are
+ * emitted as strings.
+ */
+int net_pstore(f, sv)
+PerlIO *f;
+SV *sv;
+{
+	TRACEME(("net_pstore"));
+	return do_store(f, sv, TRUE);			/* Use network order */
+}
+
+/*
+ * retrieve_ref
+ *
+ * Retrieve reference to some other scalar.
+ * Layout is SX_REF <object>, with SX_REF already read.
+ */
+static SV *retrieve_ref(f)
+PerlIO *f;
+{
+	SV *rv;
+	SV *sv;
+
+	TRACEME(("retrieve_ref (#%d)", tagnum));
+
+	/*
+	 * We need to create the SV that holds the reference to the yet-to-retrieve
+	 * object now, so that we may record the address in the seen table.
+	 * Otherwise, if the object to retrieve references us, we won't be able
+	 * to resolve the SX_OBJECT we'll see at that point! Hence we cannot
+	 * do the retrieve first and use rv = newRV(sv) since it will be too late
+	 * for SEEN() recording.
+	 */
+
+	rv = NEWSV(10002, 0);
+	SEEN(rv);				/* Will return if rv is null */
+	sv = retrieve(f);		/* Retrieve <object> */
+	if (!sv)
+		return (SV *) 0;	/* Failed */
+
+	/*
+	 * WARNING: breaks RV encapsulation.
+	 *
+	 * Now for the tricky part. We have to upgrade our existing SV, so that
+	 * it is now an RV on sv... Again, we cheat by duplicating the code
+	 * held in newSVrv(), since we already got our SV from retrieve().
+	 *
+	 * We don't say:
+	 *
+	 *		SvRV(rv) = SvREFCNT_inc(sv);
+	 *
+	 * here because the reference count we got from retrieve() above is
+	 * already correct: if the object was retrieved from the file, then
+	 * its reference count is one. Otherwise, if it was retrieved via
+	 * an SX_OBJECT indication, a ref count increment was done.
+	 */
+
+	sv_upgrade(rv, SVt_RV);
+	SvRV(rv) = sv;				/* $rv = \$sv */
+	SvROK_on(rv);
+
+	TRACEME(("ok (retrieve_ref at 0x%lx)", (unsigned long) rv));
+
+	return rv;
+}
+
+/*
+ * retrieve_tied_array
+ *
+ * Retrieve tied array
+ * Layout is SX_TIED_ARRAY <object>, with SX_TIED_ARRAY already read.
+ */
+static SV *retrieve_tied_array(f)
+PerlIO *f;
+{
+	SV *tv;
+	SV *sv;
+
+	TRACEME(("retrieve_tied_array (#%d)", tagnum));
+
+	tv = NEWSV(10002, 0);
+	SEEN(tv);					/* Will return if tv is null */
+	sv = retrieve(f);			/* Retrieve <object> */
+	if (!sv)
+		return (SV *) 0;		/* Failed */
+
+	sv_upgrade(tv, SVt_PVAV);
+	AvREAL_off((AV *)tv);
+	sv_magic(tv, sv, 'P', Nullch, 0);
+	SvREFCNT_dec(sv);			/* Undo refcnt inc from sv_magic() */
+
+	TRACEME(("ok (retrieve_tied_array at 0x%lx)", (unsigned long) tv));
+
+	return tv;
+}
+
+/*
+ * retrieve_tied_hash
+ *
+ * Retrieve tied hash
+ * Layout is SX_TIED_HASH <object>, with SX_TIED_HASH already read.
+ */
+static SV *retrieve_tied_hash(f)
+PerlIO *f;
+{
+	SV *tv;
+	SV *sv;
+
+	TRACEME(("retrieve_tied_hash (#%d)", tagnum));
+
+	tv = NEWSV(10002, 0);
+	SEEN(tv);					/* Will return if rv is null */
+	sv = retrieve(f);			/* Retrieve <object> */
+	if (!sv)
+		return (SV *) 0;		/* Failed */
+
+	sv_upgrade(tv, SVt_PVHV);
+	sv_magic(tv, sv, 'P', Nullch, 0);
+	SvREFCNT_dec(sv);			/* Undo refcnt inc from sv_magic() */
+
+	TRACEME(("ok (retrieve_tied_hash at 0x%lx)", (unsigned long) tv));
+
+	return tv;
+}
+
+/*
+ * retrieve_tied_scalar
+ *
+ * Retrieve tied scalar
+ * Layout is SX_TIED_SCALAR <object>, with SX_TIED_SCALAR already read.
+ */
+static SV *retrieve_tied_scalar(f)
+PerlIO *f;
+{
+	SV *tv;
+	SV *sv;
+
+	TRACEME(("retrieve_tied_scalar (#%d)", tagnum));
+
+	tv = NEWSV(10002, 0);
+	SEEN(tv);					/* Will return if rv is null */
+	sv = retrieve(f);			/* Retrieve <object> */
+	if (!sv)
+		return (SV *) 0;		/* Failed */
+
+	sv_upgrade(tv, SVt_PVMG);
+	sv_magic(tv, sv, 'q', Nullch, 0);
+	SvREFCNT_dec(sv);			/* Undo refcnt inc from sv_magic() */
+
+	TRACEME(("ok (retrieve_tied_scalar at 0x%lx)", (unsigned long) tv));
+
+	return tv;
+}
+
+/*
+ * retrieve_lscalar
+ *
+ * Retrieve defined long (string) scalar.
+ *
+ * Layout is SX_LSCALAR <length> <data>, with SX_LSCALAR already read.
+ * The scalar is "long" in that <length> is larger than LG_SCALAR so it
+ * was not stored on a single byte.
+ */
+static SV *retrieve_lscalar(f)
+PerlIO *f;
+{
+	STRLEN len;
+	SV *sv;
+
+	RLEN(len);
+	TRACEME(("retrieve_lscalar (#%d), len = %d", tagnum, len));
+
+	/*
+	 * Allocate an empty scalar of the suitable length.
+	 */
+
+	sv = NEWSV(10002, len);
+	SEEN(sv);			/* Associate this new scalar with tag "tagnum" */
+
+	/*
+	 * WARNING: duplicates parts of sv_setpv and breaks SV data encapsulation.
+	 *
+	 * Now, for efficiency reasons, read data directly inside the SV buffer,
+	 * and perform the SV final settings directly by duplicating the final
+	 * work done by sv_setpv. Since we're going to allocate lots of scalars
+	 * this way, it's worth the hassle and risk.
+	 */
+
+	SAFEREAD(SvPVX(sv), len, sv);
+	SvCUR_set(sv, len);				/* Record C string length */
+	*SvEND(sv) = '\0';				/* Ensure it's null terminated anyway */
+	(void) SvPOK_only(sv);			/* Validate string pointer */
+	SvTAINT(sv);					/* External data cannot be trusted */
+
+	TRACEME(("large scalar len %d '%s'", len, SvPVX(sv)));
+	TRACEME(("ok (retrieve_lscalar at 0x%lx)", (unsigned long) sv));
+
+	return sv;
+}
+
+/*
+ * retrieve_scalar
+ *
+ * Retrieve defined short (string) scalar.
+ *
+ * Layout is SX_SCALAR <length> <data>, with SX_SCALAR already read.
+ * The scalar is "short" so <length> is single byte. If it is 0, there
+ * is no <data> section.
+ */
+static SV *retrieve_scalar(f)
+PerlIO *f;
+{
+	int len;
+	SV *sv;
+
+	GETMARK(len);
+	TRACEME(("retrieve_scalar (#%d), len = %d", tagnum, len));
+
+	/*
+	 * Allocate an empty scalar of the suitable length.
+	 */
+
+	sv = NEWSV(10002, len);
+	SEEN(sv);			/* Associate this new scalar with tag "tagnum" */
+
+	/*
+	 * WARNING: duplicates parts of sv_setpv and breaks SV data encapsulation.
+	 */
+
+	if (len == 0) {
+		/*
+		 * newSV did not upgrade to SVt_PV so the scalar is undefined.
+		 * To make it defined with an empty length, upgrade it now...
+		 */
+		sv_upgrade(sv, SVt_PV);
+		SvGROW(sv, 1);
+		*SvEND(sv) = '\0';			/* Ensure it's null terminated anyway */
+		TRACEME(("ok (retrieve_scalar empty at 0x%lx)", (unsigned long) sv));
+	} else {
+		/*
+		 * Now, for efficiency reasons, read data directly inside the SV buffer,
+		 * and perform the SV final settings directly by duplicating the final
+		 * work done by sv_setpv. Since we're going to allocate lots of scalars
+		 * this way, it's worth the hassle and risk.
+		 */
+		SAFEREAD(SvPVX(sv), len, sv);
+		SvCUR_set(sv, len);			/* Record C string length */
+		*SvEND(sv) = '\0';			/* Ensure it's null terminated anyway */
+		TRACEME(("small scalar len %d '%s'", len, SvPVX(sv)));
+	}
+
+	(void) SvPOK_only(sv);			/* Validate string pointer */
+	SvTAINT(sv);					/* External data cannot be trusted */
+
+	TRACEME(("ok (retrieve_scalar at 0x%lx)", (unsigned long) sv));
+	return sv;
+}
+
+/*
+ * retrieve_integer
+ *
+ * Retrieve defined integer.
+ * Layout is SX_INTEGER <data>, whith SX_INTEGER already read.
+ */
+static SV *retrieve_integer(f)
+PerlIO *f;
+{
+	SV *sv;
+	IV iv;
+
+	TRACEME(("retrieve_integer (#%d)", tagnum));
+
+	READ(&iv, sizeof(iv));
+	sv = newSViv(iv);
+	SEEN(sv);			/* Associate this new scalar with tag "tagnum" */
+
+	TRACEME(("integer %d", iv));
+	TRACEME(("ok (retrieve_integer at 0x%lx)", (unsigned long) sv));
+
+	return sv;
+}
+
+/*
+ * retrieve_netint
+ *
+ * Retrieve defined integer in network order.
+ * Layout is SX_NETINT <data>, whith SX_NETINT already read.
+ */
+static SV *retrieve_netint(f)
+PerlIO *f;
+{
+	SV *sv;
+	int iv;
+
+	TRACEME(("retrieve_netint (#%d)", tagnum));
+
+	READ(&iv, sizeof(iv));
+#ifdef HAS_NTOHL
+	sv = newSViv((int) ntohl(iv));
+	TRACEME(("network integer %d", (int) ntohl(iv)));
+#else
+	sv = newSViv(iv);
+	TRACEME(("network integer (as-is) %d", iv));
+#endif
+	SEEN(sv);			/* Associate this new scalar with tag "tagnum" */
+
+	TRACEME(("ok (retrieve_netint at 0x%lx)", (unsigned long) sv));
+
+	return sv;
+}
+
+/*
+ * retrieve_double
+ *
+ * Retrieve defined double.
+ * Layout is SX_DOUBLE <data>, whith SX_DOUBLE already read.
+ */
+static SV *retrieve_double(f)
+PerlIO *f;
+{
+	SV *sv;
+	double nv;
+
+	TRACEME(("retrieve_double (#%d)", tagnum));
+
+	READ(&nv, sizeof(nv));
+	sv = newSVnv(nv);
+	SEEN(sv);			/* Associate this new scalar with tag "tagnum" */
+
+	TRACEME(("double %lf", nv));
+	TRACEME(("ok (retrieve_double at 0x%lx)", (unsigned long) sv));
+
+	return sv;
+}
+
+/*
+ * retrieve_byte
+ *
+ * Retrieve defined byte (small integer within the [-128, +127] range).
+ * Layout is SX_BYTE <data>, whith SX_BYTE already read.
+ */
+static SV *retrieve_byte(f)
+PerlIO *f;
+{
+	SV *sv;
+	int siv;
+
+	TRACEME(("retrieve_byte (#%d)", tagnum));
+
+	GETMARK(siv);
+	TRACEME(("small integer read as %d", (unsigned char) siv));
+	sv = newSViv((unsigned char) siv - 128);
+	SEEN(sv);			/* Associate this new scalar with tag "tagnum" */
+
+	TRACEME(("byte %d", (unsigned char) siv - 128));
+	TRACEME(("ok (retrieve_byte at 0x%lx)", (unsigned long) sv));
+
+	return sv;
+}
+
+/*
+ * retrieve_undef
+ *
+ * Return the undefined value.
+ */
+static SV *retrieve_undef()
+{
+	SV* sv;
+
+	TRACEME(("retrieve_undef"));
+
+	sv = newSV(0);
+	SEEN(sv);
+
+	return sv;
+}
+
+/*
+ * retrieve_sv_undef
+ *
+ * Return the immortal undefined value.
+ */
+static SV *retrieve_sv_undef()
+{
+	SV *sv = &sv_undef;
+
+	TRACEME(("retrieve_sv_undef"));
+
+	SEEN(sv);
+	return sv;
+}
+
+/*
+ * retrieve_sv_yes
+ *
+ * Return the immortal yes value.
+ */
+static SV *retrieve_sv_yes()
+{
+	SV *sv = &sv_yes;
+
+	TRACEME(("retrieve_sv_yes"));
+
+	SEEN(sv);
+	return sv;
+}
+
+/*
+ * retrieve_sv_no
+ *
+ * Return the immortal no value.
+ */
+static SV *retrieve_sv_no()
+{
+	SV *sv = &sv_no;
+
+	TRACEME(("retrieve_sv_no"));
+
+	SEEN(sv);
+	return sv;
+}
+
+/*
+ * retrieve_other
+ *
+ * Return an error via croak, since it is not possible that we get here
+ * under normal conditions, when facing a file produced via pstore().
+ */
+static SV *retrieve_other()
+{
+	croak("Corrupted perl storable file");
+	return (SV *) 0;
+}
+
+/*
+ * retrieve_array
+ *
+ * Retrieve a whole array.
+ * Layout is SX_ARRAY <size> followed by each item, in increading index order.
+ * Each item is stored as <object>.
+ *
+ * When we come here, SX_ARRAY has been read already.
+ */
+static SV *retrieve_array(f)
+PerlIO *f;
+{
+	I32 len;
+	I32 i;
+	AV *av;
+	SV *sv;
+
+	TRACEME(("retrieve_array (#%d)", tagnum));
+
+	/*
+	 * Read length, and allocate array, then pre-extend it.
+	 */
+
+	RLEN(len);
+	TRACEME(("size = %d", len));
+	av = newAV();
+	SEEN(av);					/* Will return if array not allocated nicely */
+	if (len)
+		av_extend(av, len);
+	else
+		return (SV *) av;		/* No data follow if array is empty */
+
+	/*
+	 * Now get each item in turn...
+	 */
+
+	for (i = 0; i < len; i++) {
+		TRACEME(("(#%d) item", i));
+		sv = retrieve(f);				/* Retrieve item */
+		if (!sv)
+			return (SV *) 0;
+		if (av_store(av, i, sv) == 0)
+			return (SV *) 0;
+	}
+
+	TRACEME(("ok (retrieve_array at 0x%lx)", (unsigned long) av));
+
+	return (SV *) av;
+}
+
+/*
+ * retrieve_hash
+ *
+ * Retrieve a whole hash table.
+ * Layout is SX_HASH <size> followed by each key/value pair, in random order.
+ * Keys are stored as <length> <data>, the <data> section being omitted
+ * if length is 0.
+ * Values are stored as <object>.
+ *
+ * When we come here, SX_HASH has been read already.
+ */
+static SV *retrieve_hash(f)
+PerlIO *f;
+{
+	I32 len;
+	I32 size;
+	I32 i;
+	HV *hv;
+	SV *sv;
+	static SV *sv_h_undef = (SV *) 0;		/* hv_store() bug */
+
+	TRACEME(("retrieve_hash (#%d)", tagnum));
+
+	/*
+	 * Read length, allocate table.
+	 */
+
+	RLEN(len);
+	TRACEME(("size = %d", len));
+	hv = newHV();
+	SEEN(hv);			/* Will return if table not allocated properly */
+	if (len == 0)
+		return (SV *) hv;	/* No data follow if table empty */
+
+	/*
+	 * Now get each key/value pair in turn...
+	 */
+
+	for (i = 0; i < len; i++) {
+		/*
+		 * Get value first.
+		 */
+
+		TRACEME(("(#%d) value", i));
+		sv = retrieve(f);
+		if (!sv)
+			return (SV *) 0;
+
+		/*
+		 * Get key.
+		 * Since we're reading into kbuf, we must ensure we're not
+		 * recursing between the read and the hv_store() where it's used.
+		 * Hence the key comes after the value.
+		 */
+
+		RLEN(size);						/* Get key size */
+		KBUFCHK(size);					/* Grow hash key read pool if needed */
+		if (size)
+			READ(kbuf, size);
+		kbuf[size] = '\0';				/* Mark string end, just in case */
+		TRACEME(("(#%d) key '%s'", i, kbuf));
+
+		/*
+		 * Enter key/value pair into hash table.
+		 */
+
+		if (hv_store(hv, kbuf, (U32) size, sv, 0) == 0)
+			return (SV *) 0;
+	}
+
+	TRACEME(("ok (retrieve_hash at 0x%lx)", (unsigned long) hv));
+
+	return (SV *) hv;
+}
+
+/*
+ * old_retrieve_array
+ *
+ * Retrieve a whole array in pre-0.6 binary format.
+ *
+ * Layout is SX_ARRAY <size> followed by each item, in increading index order.
+ * Each item is stored as SX_ITEM <object> or SX_IT_UNDEF for "holes".
+ *
+ * When we come here, SX_ARRAY has been read already.
+ */
+static SV *old_retrieve_array(f)
+PerlIO *f;
+{
+	I32 len;
+	I32 i;
+	AV *av;
+	SV *sv;
+	int c;
+
+	TRACEME(("old_retrieve_array (#%d)", tagnum));
+
+	/*
+	 * Read length, and allocate array, then pre-extend it.
+	 */
+
+	RLEN(len);
+	TRACEME(("size = %d", len));
+	av = newAV();
+	SEEN(av);					/* Will return if array not allocated nicely */
+	if (len)
+		av_extend(av, len);
+	else
+		return (SV *) av;		/* No data follow if array is empty */
+
+	/*
+	 * Now get each item in turn...
+	 */
+
+	for (i = 0; i < len; i++) {
+		GETMARK(c);
+		if (c == SX_IT_UNDEF) {
+			TRACEME(("(#%d) undef item", i));
+			continue;			/* av_extend() already filled us with undef */
+		}
+		if (c != SX_ITEM)
+			(void) retrieve_other();	/* Will croak out */
+		TRACEME(("(#%d) item", i));
+		sv = retrieve(f);				/* Retrieve item */
+		if (!sv)
+			return (SV *) 0;
+		if (av_store(av, i, sv) == 0)
+			return (SV *) 0;
+	}
+
+	TRACEME(("ok (old_retrieve_array at 0x%lx)", (unsigned long) av));
+
+	return (SV *) av;
+}
+
+/*
+ * old_retrieve_hash
+ *
+ * Retrieve a whole hash table in pre-0.6 binary format.
+ *
+ * Layout is SX_HASH <size> followed by each key/value pair, in random order.
+ * Keys are stored as SX_KEY <length> <data>, the <data> section being omitted
+ * if length is 0.
+ * Values are stored as SX_VALUE <object> or SX_VL_UNDEF for "holes".
+ *
+ * When we come here, SX_HASH has been read already.
+ */
+static SV *old_retrieve_hash(f)
+PerlIO *f;
+{
+	I32 len;
+	I32 size;
+	I32 i;
+	HV *hv;
+	SV *sv;
+	int c;
+	static SV *sv_h_undef = (SV *) 0;		/* hv_store() bug */
+
+	TRACEME(("old_retrieve_hash (#%d)", tagnum));
+
+	/*
+	 * Read length, allocate table.
+	 */
+
+	RLEN(len);
+	TRACEME(("size = %d", len));
+	hv = newHV();
+	SEEN(hv);				/* Will return if table not allocated properly */
+	if (len == 0)
+		return (SV *) hv;	/* No data follow if table empty */
+
+	/*
+	 * Now get each key/value pair in turn...
+	 */
+
+	for (i = 0; i < len; i++) {
+		/*
+		 * Get value first.
+		 */
+
+		GETMARK(c);
+		if (c == SX_VL_UNDEF) {
+			TRACEME(("(#%d) undef value", i));
+			/*
+			 * Due to a bug in hv_store(), it's not possible to pass &sv_undef
+			 * to hv_store() as a value, otherwise the associated key will
+			 * not be creatable any more. -- RAM, 14/01/97
+			 */
+			if (!sv_h_undef)
+				sv_h_undef = newSVsv(&sv_undef);
+			sv = SvREFCNT_inc(sv_h_undef);
+		} else if (c == SX_VALUE) {
+			TRACEME(("(#%d) value", i));
+			sv = retrieve(f);
+			if (!sv)
+				return (SV *) 0;
+		} else
+			(void) retrieve_other();	/* Will croak out */
+
+		/*
+		 * Get key.
+		 * Since we're reading into kbuf, we must ensure we're not
+		 * recursing between the read and the hv_store() where it's used.
+		 * Hence the key comes after the value.
+		 */
+
+		GETMARK(c);
+		if (c != SX_KEY)
+			(void) retrieve_other();	/* Will croak out */
+		RLEN(size);						/* Get key size */
+		KBUFCHK(size);					/* Grow hash key read pool if needed */
+		if (size)
+			READ(kbuf, size);
+		kbuf[size] = '\0';				/* Mark string end, just in case */
+		TRACEME(("(#%d) key '%s'", i, kbuf));
+
+		/*
+		 * Enter key/value pair into hash table.
+		 */
+
+		if (hv_store(hv, kbuf, (U32) size, sv, 0) == 0)
+			return (SV *) 0;
+	}
+
+	TRACEME(("ok (retrieve_hash at 0x%lx)", (unsigned long) hv));
+
+	return (SV *) hv;
+}
+
+/*
+ * Dynamic dispatching tables for SV retrieval.
+ */
+
+static SV *(*sv_old_retrieve[])() = {
+	0,						/* SX_OBJECT -- entry unused dynamically */
+	retrieve_lscalar,		/* SX_LSCALAR */
+	old_retrieve_array,		/* SX_ARRAY -- for pre-0.6 binaries */
+	old_retrieve_hash,		/* SX_HASH -- for pre-0.6 binaries */
+	retrieve_ref,			/* SX_REF */
+	retrieve_undef,			/* SX_UNDEF */
+	retrieve_integer,		/* SX_INTEGER */
+	retrieve_double,		/* SX_DOUBLE */
+	retrieve_byte,			/* SX_BYTE */
+	retrieve_netint,		/* SX_NETINT */
+	retrieve_scalar,		/* SX_SCALAR */
+	retrieve_tied_array,	/* SX_ARRAY */
+	retrieve_tied_hash,		/* SX_HASH */
+	retrieve_tied_scalar,	/* SX_SCALAR */
+	retrieve_other,			/* SX_SV_UNDEF not supported */
+	retrieve_other,			/* SX_SV_YES not supported */
+	retrieve_other,			/* SX_SV_NO not supported */
+	retrieve_other,			/* SX_ERROR */
+};
+
+static SV *(*sv_retrieve[])() = {
+	0,						/* SX_OBJECT -- entry unused dynamically */
+	retrieve_lscalar,		/* SX_LSCALAR */
+	retrieve_array,			/* SX_ARRAY */
+	retrieve_hash,			/* SX_HASH */
+	retrieve_ref,			/* SX_REF */
+	retrieve_undef,			/* SX_UNDEF */
+	retrieve_integer,		/* SX_INTEGER */
+	retrieve_double,		/* SX_DOUBLE */
+	retrieve_byte,			/* SX_BYTE */
+	retrieve_netint,		/* SX_NETINT */
+	retrieve_scalar,		/* SX_SCALAR */
+	retrieve_tied_array,	/* SX_ARRAY */
+	retrieve_tied_hash,		/* SX_HASH */
+	retrieve_tied_scalar,	/* SX_SCALAR */
+	retrieve_sv_undef,		/* SX_SV_UNDEF */
+	retrieve_sv_yes,		/* SX_SV_YES */
+	retrieve_sv_no,			/* SX_SV_NO */
+	retrieve_other,			/* SX_ERROR */
+};
+
+static SV *(**sv_retrieve_vtbl)();	/* One of the above -- XXX for threads*/
+
+#define RETRIEVE(x)	(*sv_retrieve_vtbl[(x) >= SX_ERROR ? SX_ERROR : (x)])
+
+/*
+ * magic_check
+ *
+ * Make sure the stored data we're trying to retrieve has been produced
+ * on an ILP compatible system with the same byteorder. It croaks out in
+ * case an error is detected. [ILP = integer-long-pointer sizes]
+ * Returns null if error is detected, &sv_undef otherwise.
+ *
+ * Note that there's no byte ordering info emitted when network order was
+ * used at store time.
+ */
+static SV *magic_check(f)
+PerlIO *f;
+{
+	char buf[256];
+	char byteorder[256];
+	int c;
+	int use_network_order;
+	int version;
+
+	/*
+	 * The "magic number" is only for files, not when freezing in memory.
+	 */
+
+	if (f) {
+		STRLEN len = sizeof(magicstr) - 1;
+		STRLEN old_len;
+
+		READ(buf, len);					/* Not null-terminated */
+		buf[len] = '\0';				/* Is now */
+
+		if (0 == strcmp(buf, magicstr))
+			goto magic_ok;
+
+		/*
+		 * Try to read more bytes to check for the old magic number, which
+		 * was longer.
+		 */
+
+		old_len = sizeof(old_magicstr) - 1;
+		READ(&buf[len], old_len - len);
+		buf[old_len] = '\0';			/* Is now null-terminated */
+
+		if (strcmp(buf, old_magicstr))
+			croak("File is not a perl storable");
+	}
+
+magic_ok:
+	/*
+	 * Starting with 0.6, the "use_network_order" byte flag is also used to
+	 * indicate the version number of the binary, and therefore governs the
+	 * setting of sv_retrieve_vtbl. See magic_write().
+	 */
+
+	GETMARK(use_network_order);
+	version = use_network_order >> 1;
+	sv_retrieve_vtbl = version ? sv_retrieve : sv_old_retrieve;
+	TRACEME(("binary image version is %d", version));
+
+	if (netorder = (use_network_order & 0x1))
+		return &sv_undef;				/* No byte ordering info */
+
+	sprintf(byteorder, "%lx", (unsigned long) BYTEORDER);
+	GETMARK(c);
+	READ(buf, c);						/* Not null-terminated */
+	buf[c] = '\0';						/* Is now */
+
+	if (strcmp(buf, byteorder))
+		croak("Byte order is not compatible");
+	
+	GETMARK(c);		/* sizeof(int) */
+	if ((int) c != sizeof(int))
+		croak("Integer size is not compatible");
+
+	GETMARK(c);		/* sizeof(long) */
+	if ((int) c != sizeof(long))
+		croak("Long integer size is not compatible");
+
+	GETMARK(c);		/* sizeof(char *) */
+	if ((int) c != sizeof(char *))
+		croak("Pointer integer size is not compatible");
+
+	return &sv_undef;	/* OK */
+}
+
+/*
+ * retrieve
+ *
+ * Recursively retrieve objects from the specified file and return their
+ * root SV (which may be an AV or an HV for what we care).
+ * Returns null if there is a problem.
+ */
+static SV *retrieve(f)
+PerlIO *f;
+{
+	int type;
+	SV **svh;
+	SV *sv;
+
+	TRACEME(("retrieve"));
+
+	/*
+	 * Grab address tag which identifies the object if we are retrieving
+	 * an older format. Since the new binary format counts objects and no
+	 * longer explicitely tags them, we must keep track of the correspondance
+	 * ourselves.
+	 *
+	 * The following section will disappear one day when the old format is
+	 * no longer supported, hence the final "goto" in the "if" block.
+	 */
+
+	if (hseen) {							/* Retrieving old binary */
+		stag_t tag;
+		if (netorder) {
+			I32 nettag;
+			READ(&nettag, sizeof(I32));		/* Ordered sequence of I32 */
+			tag = (stag_t) nettag;
+		} else
+			READ(&tag, sizeof(stag_t));		/* Original address of the SV */
+
+		GETMARK(type);
+		if (type == SX_OBJECT) {
+			I32 tagn;
+			svh = hv_fetch(hseen, (char *) &tag, sizeof(tag), FALSE);
+			if (!svh)
+				croak("Old tag 0x%x should have been mapped already", tag);
+			tagn = SvIV(*svh);	/* Mapped tag number computed earlier below */
+
+			/*
+			 * The following code is common with the SX_OBJECT case below.
+			 */
+
+			svh = av_fetch(aseen, tagn, FALSE);
+			if (!svh)
+				croak("Object #%d should have been retrieved already", tagn);
+			sv = *svh;
+			TRACEME(("already retrieved at 0x%lx", (unsigned long) sv));
+			SvREFCNT_inc(sv);	/* One more reference to this same sv */
+			return sv;			/* The SV pointer where object was retrieved */
+		}
+
+		/*
+		 * Map new object, but don't increase tagnum. This will be done
+		 * by each of the retrieve_* functions when they call SEEN().
+		 *
+		 * The mapping associates the "tag" initially present with a unique
+		 * tag number. See test for SX_OBJECT above to see how this is perused.
+		 */
+
+		if (!hv_store(hseen, (char *) &tag, sizeof(tag), newSViv(tagnum), 0))
+			return (SV *) 0;
+
+		goto first_time;
+	}
+
+	/*
+	 * Regular post-0.6 binary format.
+	 */
+
+	GETMARK(type);
+
+	TRACEME(("retrieve type = %d", type));
+
+	/*
+	 * If the object type is SX_OBJECT, then we're dealing with an object we
+	 * should have already retrieved. Otherwise, we've got a new one....
+	 */
+
+	if (type == SX_OBJECT) {
+		I32 tag;
+		READ(&tag, sizeof(I32));
+		tag = ntohl(tag);
+		svh = av_fetch(aseen, tag, FALSE);
+		if (!svh)
+			croak("Object #%d should have been retrieved already", tag);
+		sv = *svh;
+		TRACEME(("already retrieved at 0x%lx", (unsigned long) sv));
+		SvREFCNT_inc(sv);	/* One more reference to this same sv */
+		return sv;			/* The SV pointer where object was retrieved */
+	}
+
+first_time:		/* Will disappear when support for old format is dropped */
+
+	/*
+	 * Okay, first time through for this one.
+	 */
+
+	sv = RETRIEVE(type)(f);
+	if (!sv)
+		return (SV *) 0;			/* Failed */
+
+	/*
+	 * Final notifications, ended by SX_STORED may now follow.
+	 * Currently, the only pertinent notification to apply on the
+	 * freshly retrieved object is either:
+	 *    SX_BLESS <char-len> <classname> for short classnames.
+	 *    SX_LG_BLESS <int-len> <classname> for larger one (rare!).
+	 * Class name is then read into the key buffer pool used by
+	 * hash table key retrieval.
+	 */
+
+	while ((type = GETCHAR()) != SX_STORED) {
+		I32 len;
+		HV *stash;
+		SV *ref;
+		switch (type) {
+		case SX_BLESS:
+			GETMARK(len);			/* Length coded on a single char */
+			break;
+		case SX_LG_BLESS:			/* Length coded on a regular integer */
+			RLEN(len);
+			break;
+		case EOF:
+		default:
+			return (SV *) 0;		/* Failed */
+		}
+		KBUFCHK(len);				/* Grow buffer as necessary */
+		if (len)
+			READ(kbuf, len);
+		kbuf[len] = '\0';			/* Mark string end */
+		TRACEME(("blessing 0x%lx in %s", (unsigned long) sv, kbuf));
+		stash = gv_stashpv(kbuf, TRUE);
+		ref = newRV_noinc(sv);		/* To please sv_bless() */
+		(void) sv_bless(ref, stash);
+		SvRV(ref) = 0;
+		SvREFCNT_dec(ref);			/* Reclaim temporary reference */
+	}
+
+	TRACEME(("ok (retrieved 0x%lx, refcnt=%d, %s)", (unsigned long) sv,
+		SvREFCNT(sv) - 1, sv_reftype(sv, FALSE)));
+
+	return sv;	/* Ok */
+}
+
+/*
+ * do_retrieve
+ *
+ * Retrieve data held in file and return the root object.
+ * Common routine for pretrieve and mretrieve.
+ */
+static SV *do_retrieve(f)
+PerlIO *f;
+{
+	SV *sv;
+
+	TRACEME(("do_retrieve"));
+	KBUFINIT();			 	/* Allocate hash key reading pool once */
+
+	/*
+	 * Magic number verifications.
+	 */
+
+	if (!magic_check(f))
+		croak("Magic number checking on perl storable failed");
+
+	/*
+	 * If retrieving an old binary version, the sv_retrieve_vtbl variable is
+	 * set to sv_old_retrieve. We'll need a hash table to keep track of
+	 * the correspondance between the tags and the tag number used by the
+	 * new retrieve routines.
+	 */
+
+	hseen = (sv_retrieve_vtbl == sv_old_retrieve) ? newHV() : 0;
+
+	aseen = newAV();		/* Table where retrieved objects are kept */
+	tagnum = 0;				/* Have to count objects too */
+	sv = retrieve(f);		/* Recursively retrieve object, get root SV */
+	av_undef(aseen);		/* Free retrieved object table */
+	sv_free((SV *) aseen);	/* Free AV */
+
+	if (hseen)
+		sv_free((SV *) hseen);	/* Free HV if created above */
+
+	if (!sv) {
+		TRACEME(("retrieve ERROR"));
+		return &sv_undef;	/* Something went wrong, return undef */
+	}
+
+	TRACEME(("retrieve got %s(0x%lx)",
+		sv_reftype(sv, FALSE), (unsigned long) sv));
+
+	/*
+	 * Build a reference to the SV returned by pretrieve even if it is
+	 * already one and not a scalar, for consistency reasons.
+	 *
+	 * Backward compatibility with Storable-0.5 at 9 (which we know we
+	 * are retrieving if hseen is non-null): don't create an extra RV
+	 * for objects since we special-cased it at store time.
+	 */
+
+	if (hseen) {
+		SV *rv;
+		if (sv_type(sv) == svis_REF && (rv = SvRV(sv)) && SvOBJECT(rv))
+			return sv;
+	}
+
+	return newRV_noinc(sv);
+}
+
+/*
+ * pretrieve
+ *
+ * Retrieve data held in file and return the root object, undef on error.
+ */
+SV *pretrieve(f)
+PerlIO *f;
+{
+	TRACEME(("pretrieve"));
+	return do_retrieve(f);
+}
+
+/*
+ * mretrieve
+ *
+ * Retrieve data held in scalar and return the root object, undef on error.
+ */
+SV *mretrieve(sv)
+SV *sv;
+{
+	struct extendable mcommon;			/* Temporary save area for global */
+	SV *rsv;							/* Retrieved SV pointer */
+
+	TRACEME(("mretrieve"));
+	StructCopy(&membuf, &mcommon, struct extendable);
+
+	MBUF_LOAD(sv);
+	rsv = do_retrieve(0);
+
+	StructCopy(&mcommon, &membuf, struct extendable);
+	return rsv;
+}
+
+/*
+ * dclone
+ *
+ * Deep clone: returns a fresh copy of the original referenced SV tree.
+ *
+ * This is achieved by storing the object in memory and restoring from
+ * there. Not that efficient, but it should be faster than doing it from
+ * pure perl anyway.
+ */
+SV *dclone(sv)
+SV *sv;
+{
+	int size;
+
+	TRACEME(("dclone"));
+
+	MBUF_INIT(0);
+	if (!do_store(0, sv, FALSE))		/* Not in network order! */
+		return &sv_undef;				/* Error during store */
+
+	size = MBUF_SIZE();
+	TRACEME(("dclone stored %d bytes", size));
+
+	MBUF_INIT(size);
+	return do_retrieve(0);
+}
+
+/*
+ * The Perl IO GV object distinguishes between input and output for sockets
+ * but not for plain files. To allow Storable to transparently work on
+ * plain files and sockets transparently, we have to ask xsubpp to fetch the
+ * right object for us. Hence the OutputStream and InputStream declarations.
+ *
+ * Before perl 5.004_05, those entries in the standard typemap are not
+ * defined in perl include files, so we do that here.
+ */
+
+#ifndef OutputStream
+#define OutputStream	PerlIO *
+#define InputStream		PerlIO *
+#endif	/* !OutputStream */
+
+MODULE = Storable	PACKAGE = Storable
+
+PROTOTYPES: ENABLE
+
+int
+pstore(f,obj)
+OutputStream	f
+SV *	obj
+
+int
+net_pstore(f,obj)
+OutputStream	f
+SV *	obj
+
+SV *
+mstore(obj)
+SV *	obj
+
+SV *
+net_mstore(obj)
+SV *	obj
+
+SV *
+pretrieve(f)
+InputStream	f
+
+SV *
+mretrieve(sv)
+SV *	sv
+
+SV *
+dclone(sv)
+SV *	sv
+

Added: trunk/orca/packages/Storable-0.6 at 3/Storable.pm
==============================================================================
--- trunk/orca/packages/Storable-0.6 at 3/Storable.pm	(original)
+++ trunk/orca/packages/Storable-0.6 at 3/Storable.pm	Sat Jul 13 18:45:55 2002
@@ -0,0 +1,429 @@
+;# $Id: Storable.pm,v 0.6.1.3 1998/07/03 11:32:52 ram Exp $
+;#
+;#  Copyright (c) 1995-1998, Raphael Manfredi
+;#  
+;#  You may redistribute only under the terms of the Artistic License,
+;#  as specified in the README file that comes with the distribution.
+;#
+;# $Log: Storable.pm,v $
+;# Revision 0.6.1.3  1998/07/03  11:32:52  ram
+;# patch3: recent optimizations increased store() throughput
+;# patch3: increased revision number
+;#
+;# Revision 0.6.1.2  1998/06/22  08:58:53  ram
+;# patch2: added Jeff Gresham to the list of contributors
+;# patch2: increased revision number
+;#
+;# Revision 0.6.1.1  1998/06/12  09:45:09  ram
+;# patch1: increased version number
+;#
+;# Revision 0.6  1998/06/04  16:08:20  ram
+;# Baseline for first beta release.
+;#
+
+require DynaLoader;
+require Exporter;
+package Storable; @ISA = qw(Exporter DynaLoader);
+
+ at EXPORT = qw(store retrieve);
+ at EXPORT_OK = qw(
+	nstore store_fd nstore_fd retrieve_fd
+	freeze nfreeze thaw
+	dclone
+);
+
+use AutoLoader;
+use Carp;
+use vars qw($forgive_me $VERSION);
+
+$VERSION = '0.603';
+*AUTOLOAD = \&AutoLoader::AUTOLOAD;		# Grrr...
+
+bootstrap Storable;
+1;
+__END__
+
+#
+# store
+#
+# Store target object hierarchy, identified by a reference to its root.
+# The stored object tree may later be retrieved to memory via retrieve.
+# Returns undef if an I/O error occurred, in which case the file is
+# removed.
+#
+sub store {
+	return _store(0, @_);
+}
+
+#
+# nstore
+#
+# Same as store, but in network order.
+#
+sub nstore {
+	return _store(1, @_);
+}
+
+# Internal store to file routine
+sub _store {
+	my $netorder = shift;
+	my $self = shift;
+	my ($file) = @_;
+	croak "Not a reference" unless ref($self);
+	croak "Too many arguments" unless @_ == 1;	# Watch out for @foo in arglist
+	local *FILE;
+	open(FILE, ">$file") || croak "Can't create $file: $!";
+	binmode FILE;				# Archaic systems...
+	my $ret;
+	# Call C routine nstore or pstore, depending on network order
+	eval { $ret = $netorder ? net_pstore(*FILE, $self) : pstore(*FILE, $self) };
+	close(FILE) or $ret = undef;
+	unlink($file) or warn "Can't unlink $file: $!\n" if $@ || !defined $ret;
+	croak $@ if $@ =~ s/\.?\n$/,/;
+	return $ret ? $ret : undef;
+}
+
+#
+# store_fd
+#
+# Same as store, but perform on an already opened file descriptor instead.
+# Returns undef if an I/O error occurred.
+#
+sub store_fd {
+	return _store_fd(0, @_);
+}
+
+#
+# nstore_fd
+#
+# Same as store_fd, but in network order.
+#
+sub nstore_fd {
+	my ($self, $file) = @_;
+	return _store_fd(1, @_);
+}
+
+# Internal store routine on opened file descriptor
+sub _store_fd {
+	my $netorder = shift;
+	my $self = shift;
+	my ($file) = @_;
+	croak "Not a reference" unless ref($self);
+	croak "Too many arguments" unless @_ == 1;	# Watch out for @foo in arglist
+	my $fd = fileno($file);
+	croak "Not a valid file descriptor" unless defined $fd;
+	my $ret;
+	# Call C routine nstore or pstore, depending on network order
+	eval { $ret = $netorder ? net_pstore($file, $self) : pstore($file, $self) };
+	croak $@ if $@ =~ s/\.?\n$/,/;
+	return $ret ? $ret : undef;
+}
+
+#
+# freeze
+#
+# Store oject and its hierarchy in memory and return a scalar
+# containing the result.
+#
+sub freeze {
+	_freeze(0, @_);
+}
+
+#
+# nfreeze
+#
+# Same as freeze but in network order.
+#
+sub nfreeze {
+	_freeze(1, @_);
+}
+
+# Internal freeze routine
+sub _freeze {
+	my $netorder = shift;
+	my $self = shift;
+	croak "Not a reference" unless ref($self);
+	croak "Too many arguments" unless @_ == 0;	# Watch out for @foo in arglist
+	my $ret;
+	# Call C routine mstore or net_mstore, depending on network order
+	eval { $ret = $netorder ? net_mstore($self) : mstore($self) };
+	croak $@ if $@ =~ s/\.?\n$/,/;
+	return $ret ? $ret : undef;
+}
+#
+# retrieve
+#
+# Retrieve object hierarchy from disk, returning a reference to the root
+# object of that tree.
+#
+sub retrieve {
+	my ($file) = @_;
+	local *FILE;
+	open(FILE, "$file") || croak "Can't open $file: $!";
+	binmode FILE;							# Archaic systems...
+	my $self;
+	eval { $self = pretrieve(*FILE) };		# Call C routine
+	close(FILE);
+	croak $@ if $@ =~ s/\.?\n$/,/;
+	return $self;
+}
+
+#
+# retrieve_fd
+#
+# Same as retrieve, but perform from an already opened file descriptor instead.
+#
+sub retrieve_fd {
+	my ($file) = @_;
+	my $fd = fileno($file);
+	croak "Not a valid file descriptor" unless defined $fd;
+	my $self;
+	eval { $self = pretrieve($file) };		# Call C routine
+	croak $@ if $@ =~ s/\.?\n$/,/;
+	return $self;
+}
+
+#
+# thaw
+#
+# Recreate objects in memory from an existing frozen image created
+# by freeze.  If the frozen image passed is undef, return undef.
+#
+sub thaw {
+	my ($frozen) = @_;
+	return undef unless defined $frozen;
+	my $self;
+	eval { $self = mretrieve($frozen) };	# Call C routine
+	croak $@ if $@ =~ s/\.?\n$/,/;
+	return $self;
+}
+
+=head1 NAME
+
+Storable - persistency for perl data structures
+
+=head1 SYNOPSIS
+
+ use Storable;
+ store \%table, 'file';
+ $hashref = retrieve('file');
+
+ use Storable qw(nstore store_fd nstore_fd freeze thaw dclone);
+
+ # Network order
+ nstore \%table, 'file';
+ $hashref = retrieve('file');	# There is NO nretrieve()
+
+ # Storing to and retrieving from an already opened file
+ store_fd \@array, \*STDOUT;
+ nstore_fd \%table, \*STDOUT;
+ $aryref = retrieve_fd(\*SOCKET);
+ $hashref = retrieve_fd(\*SOCKET);
+
+ # Serializing to memory
+ $serialized = freeze \%table;
+ %table_clone = %{ thaw($serialized) };
+
+ # Deep (recursive) cloning
+ $cloneref = dclone($ref);
+
+=head1 DESCRIPTION
+
+The Storable package brings persistency to your perl data structures
+containing SCALAR, ARRAY, HASH or REF objects, i.e. anything that can be
+convenientely stored to disk and retrieved at a later time.
+
+It can be used in the regular procedural way by calling C<store> with
+a reference to the object to be stored, along with the file name where
+the image should be written.
+The routine returns C<undef> for I/O problems or other internal error,
+a true value otherwise. Serious errors are propagated as a C<die> exception.
+
+To retrieve data stored to disk, use C<retrieve> with a file name,
+and the objects stored into that file are recreated into memory for you,
+a I<reference> to the root object being returned. In case an I/O error
+occurs while reading, C<undef> is returned instead. Other serious
+errors are propagated via C<die>.
+
+Since storage is performed recursively, you might want to stuff references
+to objects that share a lot of common data into a single array or hash
+table, and then store that object. That way, when you retrieve back the
+whole thing, the objects will continue to share what they originally shared.
+
+At the cost of a slight header overhead, you may store to an already
+opened file descriptor using the C<store_fd> routine, and retrieve
+from a file via C<retrieve_fd>. Those names aren't imported by default,
+so you will have to do that explicitely if you need those routines.
+The file descriptor you supply must be already opened, for read
+if you're going to retrieve and for write if you wish to store.
+
+	store_fd(\%table, *STDOUT) || die "can't store to stdout\n";
+	$hashref = retrieve_fd(*STDIN);
+
+You can also store data in network order to allow easy sharing across
+multiple platforms, or when storing on a socket known to be remotely
+connected. The routines to call have an initial C<n> prefix for I<network>,
+as in C<nstore> and C<nstore_fd>. At retrieval time, your data will be
+correctly restored so you don't have to know whether you're restoring
+from native or network ordered data.
+
+When using C<retrieve_fd>, objects are retrieved in sequence, one
+object (i.e. one recursive tree) per associated C<store_fd>.
+
+If you're more from the object-oriented camp, you can inherit from
+Storable and directly store your objects by invoking C<store> as
+a method. The fact that the root of the to-be-stored tree is a
+blessed reference (i.e. an object) is special-cased so that the
+retrieve does not provide a reference to that object but rather the
+blessed object reference itself. (Otherwise, you'd get a reference
+to that blessed object).
+
+=head1 MEMORY STORE
+
+The Storable engine can also store data into a Perl scalar instead, to
+later retrieve them. This is mainly used to freeze a complex structure in
+some safe compact memory place (where it can possibly be sent to another
+process via some IPC, since freezing the structure also serializes it in
+effect). Later on, and maybe somewhere else, you can thaw the Perl scalar
+out and recreate the original complex structure in memory.
+
+Surprisingly, the routines to be called are named C<freeze> and C<thaw>.
+If you wish to send out the frozen scalar to another machine, use
+C<nfreeze> instead to get a portable image.
+
+Note that freezing an object structure and immediately thawing it
+actually achieves a deep cloning of that structure. Storable provides
+you with a C<dclone> interface which does not create that intermediary
+scalar but instead freezes the structure in some internal memory space
+and then immediatly thaws it out.
+
+=head1 SPEED
+
+The heart of Storable is written in C for decent speed. Extra low-level
+optimization have been made when manipulating perl internals, to
+sacrifice encapsulation for the benefit of a greater speed.
+
+Storage is now slightly slower than retrieval since the former has to
+also store data in a hash table to keep track of which objects
+have been stored already, whilst the latter uses an array instead of
+a hash table.
+
+On my HP 9000/712 machine running HPUX 9.03 and with perl 5.004, I can
+store 0.85 Mbyte/s and I can retrieve at 0.90 Mbytes/s, approximatively
+(CPU + system time).
+This was measured with Benchmark and the I<Magic: The Gathering>
+database from Tom Christiansen (1.6 Mbytes on disk).
+
+=head1 CANONICAL REPRESENTATION
+
+Normally Storable stores elements of hashes in the order they are
+stored internally by Perl, i.e. pseudo-randomly.  If you set
+C<$Storable::canonical> to some C<TRUE> value, Storable will store
+hashes with the elements sorted by their key.  This allows you to
+compare data structures by comparing their frozen representations (or
+even the compressed frozen representations), which can be useful for
+creating lookup tables for complicated queries.
+
+Canonical order does not imply network order, those are two orthogonal
+settings.
+
+=head1 EXAMPLES
+
+Here are some code samples showing a possible usage of Storable:
+
+	use Storable qw(store retrieve freeze thaw dclone);
+
+	%color = ('Blue' => 0.1, 'Red' => 0.8, 'Black' => 0, 'White' => 1);
+
+	store(\%color, '/tmp/colors') or die "Can't store %a in /tmp/colors!\n";
+
+	$colref = retrieve('/tmp/colors');
+	die "Unable to retrieve from /tmp/colors!\n" unless defined $colref;
+	printf "Blue is still %lf\n", $colref->{'Blue'};
+
+	$colref2 = dclone(\%color);
+
+	$str = freeze(\%color);
+	printf "Serialization of %%color is %d bytes long.\n", length($str);
+	$colref3 = thaw($str);
+
+which prints (on my machine):
+
+	Blue is still 0.100000
+	Serialization of %color is 102 bytes long.
+
+=head1 WARNING
+
+If you're using references as keys within your hash tables, you're bound
+to disapointment when retrieving your data. Indeed, Perl stringifies
+references used as hash table keys. If you later wish to access the
+items via another reference stringification (i.e. using the same
+reference that was used for the key originally to record the value into
+the hash table), it will work because both references stringify to the
+same string.
+
+It won't work across a C<store> and C<retrieve> operations however, because
+the addresses in the retrieved objects, which are part of the stringified
+references, will probably differ from the original addresses. The
+topology of your structure is preserved, but not hidden semantics
+like those.
+
+On platforms where it matters, be sure to call C<binmode()> on the
+descriptors that you pass to Storable functions.
+
+Storing data canonically that contains large hashes can be
+significantly slower than storing the same data normally, as
+temprorary arrays to hold the keys for each hash have to be allocated,
+populated, sorted and freed.  Some tests have shown a halving of the
+speed of storing -- the exact penalty will depend on the complexity of
+your data.  There is no slowdown on retrieval.
+
+=head1 BUGS
+
+You can't store GLOB, CODE, FORMLINE, etc... If you can define
+semantics for those operations, feel free to enhance Storable so that
+it can deal with them.
+
+The store functions will C<croak> if they run into such references
+unless you set C<$Storable::forgive_me> to some C<TRUE> value. In that
+case, the fatal message is turned in a warning and some
+meaningless string is stored instead.
+
+Setting C<$Storable::canonical> may not yield frozen strings that
+compare equal due to possible stringification of numbers. When the
+string version of a scalar exists, it is the form stored, therefore
+if you happen to use your numbers as strings between two freezing
+operations on the same data structures, you will get different
+results.
+
+Due to the aforementionned optimizations, Storable is at the mercy
+of perl's internal redesign or structure changes. If that bothers
+you, you can try convincing Larry that what is used in Storable
+should be documented and consistently kept in future revisions.
+
+=head1 CREDITS
+
+Thank you to (in chronological order):
+
+	Jarkko Hietaniemi <jhi at iki.fi>
+	Ulrich Pfeifer <pfeifer at charly.informatik.uni-dortmund.de>
+	Benjamin A. Holzman <benjamin.a.holzman at bender.com>
+	Andrew Ford <A.Ford at ford-mason.co.uk>
+	Gisle Aas <gisle at aas.no>
+	Jeff Gresham <gresham_jeffrey at jpmorgan.com>
+
+for their bug reports, suggestions and contributions.
+
+Benjamin Holzman contributed the tied variable support, Andrew Ford
+contributed the canonical order for hashes, and Gisle Aas fixed
+a few misunderstandings of mine regarding the Perl internals,
+and optimized the emission of "tags" in the output streams by
+simply counting the objects instead of tagging them (leading to
+a binary incompatibility for the Storable image starting at version
+0.6--older images are of course still properly understood).
+
+=head1 AUTHOR
+
+Raphael Manfredi F<E<lt>Raphael_Manfredi at grenoble.hp.comE<gt>>
+
+=cut

Added: trunk/orca/packages/Storable-0.6 at 3/MANIFEST
==============================================================================
--- trunk/orca/packages/Storable-0.6 at 3/MANIFEST	(original)
+++ trunk/orca/packages/Storable-0.6 at 3/MANIFEST	Sat Jul 13 18:45:55 2002
@@ -0,0 +1,15 @@
+README                      Read this first
+MANIFEST                    This shipping list
+Makefile.PL                 Generic Makefile template
+Storable.pm                 The perl side of Storable
+Storable.xs                 The C side of Storable
+patchlevel.h                Records current patchlevel
+t/canonical.t               Test canonical hash table dumping
+t/dclone.t                  Test deep cloning
+t/dump.pl                   Small utility to dump data structures
+t/freeze.t                  Test memory store (freeze/thaw) operations
+t/retrieve.t                Test retrieve operation
+t/store.t                   Test store operation
+t/forgive.t                 Test if $Storable::forgive_me works
+t/tied.t                    Test serialization of tied SVs.
+ChangeLog                   Changes since baseline

Added: trunk/orca/packages/Storable-0.6 at 3/Makefile.PL
==============================================================================
--- trunk/orca/packages/Storable-0.6 at 3/Makefile.PL	(original)
+++ trunk/orca/packages/Storable-0.6 at 3/Makefile.PL	Sat Jul 13 18:45:56 2002
@@ -0,0 +1,23 @@
+# $Id: Makefile.PL,v 0.6 1998/06/04 16:08:18 ram Exp $
+#
+#  Copyright (c) 1995-1998, Raphael Manfredi
+#  
+#  You may redistribute only under the terms of the Artistic License,
+#  as specified in the README file that comes with the distribution.
+#
+# $Log: Makefile.PL,v $
+# Revision 0.6  1998/06/04  16:08:18  ram
+# Baseline for first beta release.
+#
+
+use ExtUtils::MakeMaker;
+use Config;
+
+WriteMakefile(
+    'NAME'			=> 'Storable',
+    'DISTNAME'		=> "Storable",
+    'VERSION_FROM'	=> 'Storable.pm',
+    'dist'			=> { SUFFIX => 'gz', COMPRESS => 'gzip -f' },
+    'clean'			=> {'FILES' => '*%'},
+);
+

Added: trunk/orca/packages/Storable-0.6 at 3/ChangeLog
==============================================================================
--- trunk/orca/packages/Storable-0.6 at 3/ChangeLog	(original)
+++ trunk/orca/packages/Storable-0.6 at 3/ChangeLog	Sat Jul 13 18:45:56 2002
@@ -0,0 +1,230 @@
+Fri Jul  3 13:38:16 METDST 1998   Raphael Manfredi <Raphael_Manfredi at grenoble.hp.com>
+
+. Description:
+
+	Updated benchmark figures due to recent optimizations done in
+	store(): tagnums are now stored as-is in the hash table, so
+	no surrounding SV is created. And the "shared keys" mode for
+	hash table was turned off.
+
+	Fixed backward compatibility (wrt 0.5 at 9) for retrieval of
+	blessed refs. That old version did something wrong, but the
+	bugfix prevented correct retrieval of the old format.
+
+Mon Jun 22 11:00:48 METDST 1998   Raphael Manfredi <Raphael_Manfredi at grenoble.hp.com>
+
+. Description:
+
+	Changed benchmark figures.
+
+	Adjust refcnt of tied objects after calling sv_magic() to avoid
+	memory leaks.  Contributed by Jeff Gresham.
+
+Fri Jun 12 11:50:04 METDST 1998   Raphael Manfredi <Raphael_Manfredi at grenoble.hp.com>
+
+. Description:
+
+	Added workaround for persistent LVALUE-ness in perl5.004. All
+	scalars tagged as being an lvalue are handled as if they were
+	not an lvalue at all.  Added test for that LVALUE bug workaround.
+
+	Now handles Perl immortal scalars explicitely, by storing &sv_yes
+	as such, explicitely.
+
+	Retrieval of non-immortal undef cannot be shared. Previous
+	version was over-optimizing by not creating a separate SV for
+	all undefined scalars seen.
+
+Thu Jun  4 17:21:51 METDST 1998   Raphael Manfredi <Raphael_Manfredi at grenoble.hp.com>
+
+. Description:
+
+	Baseline for Storable-0.6 at 0.
+
+	This version introduces a binary incompatibility in the generated
+	binary image, which is more compact than older ones by approximatively
+	15%, depending on the exact degree of sharing in your structures.
+
+	The good news is that your older images can still be retrieved with
+	this version, i.e. backward compatibility is preserved. This version
+	of Storable can only generate new binaries however.
+
+	Another good news is that the retrieval of data structure is
+	significantly quicker than before, because a Perl array is used
+	instead of a hash table to keep track of retrieved objects, and
+	also because the image being smaller, less I/O function calls are
+	made.
+
+Tue May 12 09:15:15 METDST 1998   Raphael Manfredi <Raphael_Manfredi at grenoble.hp.com>
+
+. Description:
+
+	Version number now got from Storable.pm directly.
+
+	Fixed overzealous sv_type() optimization, which would make
+	Storable fail when faced with an "upgraded" SV to the PVIV
+	or PVNV kind containing a reference.
+
+Thu Apr 30 15:11:30 METDST 1998   Raphael Manfredi <Raphael_Manfredi at grenoble.hp.com>
+
+. Description:
+
+	Extended the SYNOPSIS section to give quick overview of the
+	routines and their signature.
+
+	Optimized sv_type() to avoid flags checking when not needed, i.e.
+	when their type makes it impossible for them to be refs or tied.
+	This slightly increases throughput by a few percents when refs
+	and tied variables are marginal occurrences in your data.
+
+	Stubs for XS now use OutputStream and InputStream file types to
+	make it work when the given file is actually a socket. Perl
+	makes a distinction for sockets in its internal I/O structures
+	by having both a read and a write structure, whereas plain files
+	share the same one.
+
+Tue Jun  3 09:41:33 METDST 1997   Raphael Manfredi <Raphael_Manfredi at grenoble.hp.com>
+
+. Description:
+
+	Thanks to a contribution from Benjamin A. Holzman, Storable is now
+	able to correctly serialize tied SVs, i.e. tied arrays, hashes
+	and scalars.
+
+Thu Apr  9 18:07:51 METDST 1998   Raphael Manfredi <Raphael_Manfredi at grenoble.hp.com>
+
+. Description:
+
+	I said SvPOK() had changed to SvPOKp(), but that was a lie...
+
+Wed Apr  8 13:14:29 METDST 1998   Raphael Manfredi <Raphael_Manfredi at grenoble.hp.com>
+
+. Description:
+
+	Wrote sizeof(SV *) instead of sizeof(I32) when portable, which
+	in effect mangled the object tags and prevented portability
+	accross 32/64 bit architectures!
+
+Wed Mar 25 14:57:02 MET 1998   Raphael Manfredi <Raphael_Manfredi at grenoble.hp.com>
+
+. Description:
+
+	Added code example for store_fd() and retrieve_fd() in the
+	man page, to emphasize that file descriptors must be passed as
+	globs, not as plain strings.
+
+	Cannot use SV addresses as tag when using nstore() on LP64. This
+	was the cause of problems when creating a storable image on an
+	LP64 machine and retrieving it on an ILP32 system, which is
+	exactly what nstore() is meant for...
+
+	However, we continue to use SV addresses as tags for plain store(),
+	because benchamarking shows that it saves up to 8% of the store
+	time, and store() is meant to be fast at the expense of lack
+	of portability.
+
+	This means there will be approximately an 8% degradation of
+	performance for nstore(), but it's now working as expected.
+	That cost may vary on your machine of course, since it is
+	solely caused by the memory allocation overhead used to create
+	unique SV tags for each distinct stored SV.
+
+Tue Jan 20 09:21:53 MET 1998   Raphael Manfredi <Raphael_Manfredi at grenoble.hp.com>
+
+. Description:
+
+	Don't use any '_' in version number.
+
+Tue Jan 13 17:51:50 MET 1998   Raphael Manfredi <Raphael_Manfredi at grenoble.hp.com>
+
+. Description:
+
+	Updated version number.
+
+	added binmode() calls for systems where it matters.
+
+	Be sure to pass globs, not plain file strings, to C routines,
+	so that Storable can be used under the Perl debugger.
+
+Wed Nov  5 10:53:22 MET 1997   Raphael Manfredi <Raphael_Manfredi at grenoble.hp.com>
+
+. Description:
+
+	Fix memory leaks on seen hash table and returned SV refs.
+
+	Storable did not work properly when tainting enabled.
+
+	Fixed "Allocation too large" messages in freeze/thaw and added.
+	proper regression test in t/freeze.t.
+
+Tue Jun  3 09:41:33 METDST 1997   Raphael Manfredi <Raphael_Manfredi at grenoble.hp.com>
+
+. Description:
+
+	Updated version number
+
+	Added freeze/thaw interface and dclone.
+
+Fri May 16 10:45:47 METDST 1997   Raphael Manfredi <Raphael_Manfredi at grenoble.hp.com>
+
+. Description:
+
+	Forgot that AutoLoader does not export its own AUTOLOAD.
+	I could use
+
+		use AutoLoader 'AUTOLOAD';
+	
+	but that would not be backward compatible. So the export is
+	done by hand...
+
+Tue Mar 25 11:21:32 MET 1997   Raphael Manfredi <Raphael_Manfredi at grenoble.hp.com>
+
+. Description:
+
+	Empty scalar strings are now "defined" at retrieval time.
+
+	New test to ensure an empty string is defined when retrieved.
+
+Thu Feb 27 16:32:44 MET 1997   Raphael Manfredi <Raphael_Manfredi at grenoble.hp.com>
+
+. Description:
+
+	Updated version number
+
+	Declare VERSION as being used
+
+	Fixed a typo in the PerlIO_putc remapping.
+	PerlIO_read and perlIO_write inverted size/nb_items.
+	(only relevant for pre-perl5.004 versions)
+
+Thu Feb 27 15:58:31 MET 1997   Raphael Manfredi <Raphael_Manfredi at grenoble.hp.com>
+
+. Description:
+
+	Updated version number
+
+	Added VERSION identification
+
+	Allow build with perl5.003, which is ante perlIO time
+
+Mon Jan 13 17:53:18 MET 1997   Raphael Manfredi <Raphael_Manfredi at grenoble.hp.com>
+
+. Description:
+
+	Random code fixes.
+
+Wed Jan 22 15:19:56 MET 1997   Raphael Manfredi <Raphael_Manfredi at grenoble.hp.com>
+
+. Description:
+
+	Updated version number in Makefile.PL.
+
+	Added "thanks to" section to README.
+
+	Documented new forgive_me variable.
+
+	Made 64-bit clean.
+
+	Added forgive_me support to allow store() of data structures
+	containing non-storable items like CODE refs.
+

Added: trunk/orca/packages/Storable-0.6 at 3/patchlevel.h
==============================================================================
--- trunk/orca/packages/Storable-0.6 at 3/patchlevel.h	(original)
+++ trunk/orca/packages/Storable-0.6 at 3/patchlevel.h	Sat Jul 13 18:45:56 2002
@@ -0,0 +1 @@
+#define PATCHLEVEL 3

Added: trunk/orca/packages/Storable-0.6 at 3/README
==============================================================================
--- trunk/orca/packages/Storable-0.6 at 3/README	(original)
+++ trunk/orca/packages/Storable-0.6 at 3/README	Sat Jul 13 18:45:56 2002
@@ -0,0 +1,150 @@
+                         Storable 0.6
+               Copyright (c) 1995-1998, Raphael Manfredi
+
+------------------------------------------------------------------------
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the Artistic License, a copy of which can be
+    found with perl.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    Artistic License for more details.
+------------------------------------------------------------------------
+
+       *** This is beta software -- use at your own risks ***
+
+The Storable extension brings persistency to your data.
+
+You may recursively store to disk any data structure, no matter
+how complex and circular it is, provided it contains only SCALAR,
+ARRAY, HASH and references to those items, blessed or not.
+
+At a later stage, or in another program, you may retrieve data from
+the stored file and recreate the same hiearchy in memory. If you
+had blessed references, the retrieved references are blessed into
+the same package, so you must make sure you have access to the
+same perl class than the one used to create the relevant objects.
+
+For instance:
+
+	use Storable;
+
+	$scalar = 'scalar';
+	$hash{$scalar} = 'value';
+	$ref = \%hash;
+	@array = ('first', undef, $scalar, $ref, \$ref);
+
+	&show(\@array);
+
+	store(\@array, 'store');
+	$root = retrieve('store');
+
+	print '-' x 10, "\n";
+	&show($root) if ref($root) eq 'ARRAY';
+
+	sub show {
+		my ($aref) = @_;
+		foreach $i (@{$aref}) {
+			unless (defined $i) {
+				print "undef\n";
+				next;
+			}
+			print "$i";
+			print " ($$i)" if ref($i) eq 'SCALAR';
+			print "\n";
+		}
+	}
+
+
+when run on my machine produces:
+
+	first
+	undef
+	scalar
+	HASH(0x4001eec0)
+	SCALAR(0x4001ee60)
+	----------
+	first
+	undef
+	scalar
+	HASH(0x40021fd4)
+	SCALAR(0x40017008)
+
+You can see that items are retrieved in memory at some other place,
+but the topology of the retrieved data is the same as the original.
+
+I had first written Storable in Perl, but the results were disappointing,
+because it took almost 20 seconds to store 200K worth of data. By having
+the heart of Storable in C, I can store the same amount of data in about
+0.6 seconds. To retrieve the same data, it takes roughly 1.0 seconds,
+because you have to allocate objects in memory whereas storing merely
+traverses structures.
+
+More accurately, using Benchmark, I get (for a 236802 byte long stored
+file):
+
+	  Machine       Time to store       Time to retrieve
+	                 (cpu + sys)           (cpu + sys)
+	HP 9000/712         0.61 s                1.02 s
+	HP 9000/856         0.33 s                0.39 s
+
+To store/retrieve the "Magic: The Gathering" (MTG) database (1.9 Mb) in
+native format:
+
+	  Machine       Time to store       Time to retrieve
+	                 (cpu + sys)           (cpu + sys)
+	HP 9000/712         1.95 s                2.19 s
+
+That's roughly 1Mb/s for store and 0.86Mb/s for retrieve.
+
+NOTE: The above figures were valid for Storable-0.5 and earlier. No
+similar benchmarking have been made with Storable-0.6 and higher,
+which use a different binary image.
+
+Comparison of Storable-0.5 at 9 and Storable-0.6 at 3 on a version of
+Tom Christiansen's MTG database (1.8 Mb in native 0.5 format, 1.6 Mb
+only in 0.6 format) gives:
+
+    Version    Storable Image   "store"    "nstore"   "retrieve"
+                 Size in Mb     in Kb/s     in Kb/s     in Kb/s
+
+	 0.5 at 9          1.817         801         701         692
+	 0.6 at 3          1.526         880         851         870
+
+Kb/s rates refer to the size of the Storable image. Since the image
+is shorter with version 0.6, we must normalize the results to compare
+relative speed correctly, and therefore measure the overall time it
+takes to store/retrieve the same database. We get:
+
+    Version    Storable Image   "store"    "nstore"   "retrieve"
+                 Size in Mb     in secs     in secs     in secs
+
+	 0.5 at 9          1.817         2.32        2.65        2.69
+	 0.6 at 3          1.526         1.78        1.84        1.80
+
+Notice the important gain at retrieval time, due to the fact that we
+now use an array instead of a hash table to keep track of retrieved
+objects. I have no explaination for the relative speed-up of nstore
+operations other than the fact that less tests for "netorder" are made.
+
+To compile this extension, run:
+
+	perl Makefile.PL [PERL_SRC=...where you put perl sources...]
+	make
+	make install
+
+There is an embeded POD manual page in Storable.pm.
+
+Raphael Manfredi <Raphael_Manfredi at grenoble.hp.com>
+
+Thanks to:
+
+	Jarkko Hietaniemi <jhi at iki.fi>
+	Ulrich Pfeifer <pfeifer at charly.informatik.uni-dortmund.de>
+	Benjamin A. Holzman <benjamin.a.holzman at bender.com>
+	Andrew Ford <A.Ford at ford-mason.co.uk>
+	Gisle Aas <gisle at aas.no>
+	Jeff Gresham <gresham_jeffrey at jpmorgan.com>
+
+for their contributions.

Added: trunk/orca/packages/Makefile.in
==============================================================================
--- trunk/orca/packages/Makefile.in	(original)
+++ trunk/orca/packages/Makefile.in	Sat Jul 13 18:45:56 2002
@@ -0,0 +1,136 @@
+ at SET_MAKE@
+
+PERL			= @PERL@
+CFLAGS			= @CFLAGS@
+digest_md5_dir		= @DIGEST_MD5_DIR@
+math_interpolate_dir	= @MATH_INTERPOLATE_DIR@
+rrdtool_dir		= @RRDTOOL_DIR@
+storable_dir		= @STORABLE_DIR@
+
+MAKE_DIGEST_MD5		= @MAKE_DIGEST_MD5@
+MAKE_MATH_INTERPOLATE	= @MAKE_MATH_INTERPOLATE@
+MAKE_RRDTOOL		= @MAKE_RRDTOOL@
+MAKE_STORABLE		= @MAKE_STORABLE@
+MAKE_TARGETS		= $(MAKE_DIGEST_MD5) $(MAKE_MATH_INTERPOLATE) $(MAKE_RRDTOOL) $(MAKE_STORABLE)
+
+TEST_DIGEST_MD5		= @TEST_DIGEST_MD5@
+TEST_MATH_INTERPOLATE	= @TEST_MATH_INTERPOLATE@
+TEST_RRDTOOL		= @TEST_RRDTOOL@
+TEST_STORABLE		= @TEST_STORABLE@
+TEST_TARGETS		= $(TEST_DIGEST_MD5) $(TEST_MATH_INTERPOLATE) $(TEST_RRDTOOL) $(TEST_STORABLE)
+
+INSTALL_DIGEST_MD5	= @INSTALL_DIGEST_MD5@
+INSTALL_MATH_INTERPOLATE= @INSTALL_MATH_INTERPOLATE@
+INSTALL_RRDTOOL		= @INSTALL_RRDTOOL@
+INSTALL_STORABLE	= @INSTALL_STORABLE@
+INSTALL_TARGETS		= $(INSTALL_DIGEST_MD5) $(INSTALL_MATH_INTERPOLATE) $(INSTALL_RRDTOOL) $(INSTALL_STORABLE)
+
+CLEAN_DIGEST_MD5	= @CLEAN_DIGEST_MD5@
+CLEAN_MATH_INTERPOLATE	= @CLEAN_MATH_INTERPOLATE@
+CLEAN_RRDTOOL		= @CLEAN_RRDTOOL@
+CLEAN_STORABLE		= @CLEAN_STORABLE@
+CLEAN_TARGETS		= $(CLEAN_DIGEST_MD5) $(CLEAN_MATH_INTERPOLATE) $(CLEAN_RRDTOOL) $(CLEAN_STORABLE)
+
+DISTCLEAN_DIGEST_MD5	= @DISTCLEAN_DIGEST_MD5@
+DISTCLEAN_MATH_INTERPOLATE = @DISTCLEAN_MATH_INTERPOLATE@
+DISTCLEAN_RRDTOOL	= @DISTCLEAN_RRDTOOL@
+DISTCLEAN_STORABLE	= @DISTCLEAN_STORABLE@
+DISTCLEAN_TARGETS	= $(DISTCLEAN_DIGEST_MD5) $(DISTCLEAN_MATH_INTERPOLATE) $(DISTCLEAN_RRDTOOL) $(DISTCLEAN_STORABLE)
+
+all:	Makefile
+
+modules: Makefile $(MAKE_TARGETS)
+
+make_digest_md5: $(digest_md5_dir)/Makefile
+	(cd $(digest_md5_dir) && $(MAKE) OPTIMIZE="$(CFLAGS)")
+
+$(digest_md5_dir)/Makefile: $(digest_md5_dir)/Makefile.PL $(PERL)
+	(cd $(digest_md5_dir) && $(PERL) Makefile.PL)
+
+make_math_interpolate: $(math_interpolate_dir)/Makefile
+	(cd $(math_interpolate_dir) && $(MAKE) OPTIMIZE="$(CFLAGS)")
+
+$(math_interpolate_dir)/Makefile: $(math_interpolate_dir)/Makefile.PL $(PERL)
+	(cd $(math_interpolate_dir) && $(PERL) Makefile.PL)
+
+make_rrdtool: $(rrdtool_dir)/Makefile $(PERL)
+	(cd $(rrdtool_dir) && $(MAKE) CFLAGS="$(CFLAGS)")
+
+$(rrdtool_dir)/Makefile: $(rrdtool_dir)/Makefile.in
+	(cd .. && ./configure @CONFIGURE_COMMAND_LINE@)
+
+make_storable: $(storable_dir)/Makefile
+	(cd $(storable_dir) && $(MAKE) OPTIMIZE="$(CFLAGS)")
+
+$(storable_dir)/Makefile: $(storable_dir)/Makefile.PL $(PERL)
+	(cd $(storable_dir) && $(PERL) Makefile.PL)
+
+test:
+
+test_modules: $(TEST_TARGETS)
+
+test_digest_md5: $(digest_md5_dir)/Makefile
+	(cd $(digest_md5_dir) && $(MAKE) CFLAGS="$(CFLAGS)" test)
+
+test_math_interpolate: $(math_interpolate_dir)/Makefile
+	(cd $(math_interpolate_dir) && $(MAKE) test)
+
+test_rrdtool: make_rrdtool
+	(cd $(rrdtool_dir)/perl-shared && $(MAKE) CFLAGS="$(CFLAGS)" test)
+
+test_storable: make_storable
+	(cd $(storable_dir) && $(MAKE) CFLAGS="$(CFLAGS)" test)
+
+install:
+
+install_modules: $(INSTALL_TARGETS)
+
+install_digest_md5: make_digest_md5
+	(cd $(digest_md5_dir) && $(MAKE) install)
+
+install_math_interpolate: make_math_interpolate
+	(cd $(math_interpolate_dir) && $(MAKE) install)
+
+install_rrdtool: make_rrdtool
+	(cd $(rrdtool_dir)/perl-shared && $(MAKE) install)
+
+install_storable: make_storable
+	(cd $(storable_dir) && $(MAKE) install)
+
+clean: $(CLEAN_TARGETS)
+
+clean_digest_md5:
+	@if test -r $(digest_md5_dir)/Makefile; then 			\
+		echo '(cd $(digest_md5_dir); $(MAKE) clean';		\
+		(cd $(digest_md5_dir); $(MAKE) clean);			\
+	fi
+
+clean_math_interpolate:
+	@if test -r $(math_interpolate_dir)/Makefile; then 		\
+		echo '(cd $(math_interpolate_dir); $(MAKE) clean)';	\
+		(cd $(math_interpolate_dir); $(MAKE) clean);		\
+	fi
+
+clean_rrdtool:
+	(cd $(rrdtool_dir) && $(MAKE) clean)
+
+clean_storable:
+	@if test -r $(storable_dir)/Makefile; then 			\
+		echo '(cd $(storable_dir); $(MAKE) clean)';		\
+		(cd $(storable_dir); $(MAKE) clean);			\
+	fi
+
+distclean: $(DISTCLEAN_TARGETS)
+
+distclean_digest_md5:		clean_digest_md5
+
+distclean_math_interpolate:	clean_math_interpolate
+
+distclean_rrdtool:		clean_rrdtool
+	(cd $(rrdtool_dir) && $(MAKE) distclean)
+
+distclean_storable:		clean_storable
+
+Makefile: Makefile.in
+	(cd ..; ./config.status)
+	$(MAKE)

Added: trunk/orca/packages/Digest-MD5-2.07/rfc1321.txt
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/rfc1321.txt	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/rfc1321.txt	Sat Jul 13 18:45:56 2002
@@ -0,0 +1,1179 @@
+
+
+
+
+
+
+Network Working Group                                          R. Rivest
+Request for Comments: 1321           MIT Laboratory for Computer Science
+                                             and RSA Data Security, Inc.
+                                                              April 1992
+
+
+                     The MD5 Message-Digest Algorithm
+
+Status of this Memo
+
+   This memo provides information for the Internet community.  It does
+   not specify an Internet standard.  Distribution of this memo is
+   unlimited.
+
+Acknowlegements
+
+   We would like to thank Don Coppersmith, Burt Kaliski, Ralph Merkle,
+   David Chaum, and Noam Nisan for numerous helpful comments and
+   suggestions.
+
+Table of Contents
+
+   1. Executive Summary                                                1
+   2. Terminology and Notation                                         2
+   3. MD5 Algorithm Description                                        3
+   4. Summary                                                          6
+   5. Differences Between MD4 and MD5                                  6
+   References                                                          7
+   APPENDIX A - Reference Implementation                               7
+   Security Considerations                                            21
+   Author's Address                                                   21
+
+1. Executive Summary
+
+   This document describes the MD5 message-digest algorithm. The
+   algorithm takes as input a message of arbitrary length and produces
+   as output a 128-bit "fingerprint" or "message digest" of the input.
+   It is conjectured that it is computationally infeasible to produce
+   two messages having the same message digest, or to produce any
+   message having a given prespecified target message digest. The MD5
+   algorithm is intended for digital signature applications, where a
+   large file must be "compressed" in a secure manner before being
+   encrypted with a private (secret) key under a public-key cryptosystem
+   such as RSA.
+
+
+
+
+
+
+
+Rivest                                                          [Page 1]
+
+RFC 1321              MD5 Message-Digest Algorithm            April 1992
+
+
+   The MD5 algorithm is designed to be quite fast on 32-bit machines. In
+   addition, the MD5 algorithm does not require any large substitution
+   tables; the algorithm can be coded quite compactly.
+
+   The MD5 algorithm is an extension of the MD4 message-digest algorithm
+   1,2]. MD5 is slightly slower than MD4, but is more "conservative" in
+   design. MD5 was designed because it was felt that MD4 was perhaps
+   being adopted for use more quickly than justified by the existing
+   critical review; because MD4 was designed to be exceptionally fast,
+   it is "at the edge" in terms of risking successful cryptanalytic
+   attack. MD5 backs off a bit, giving up a little in speed for a much
+   greater likelihood of ultimate security. It incorporates some
+   suggestions made by various reviewers, and contains additional
+   optimizations. The MD5 algorithm is being placed in the public domain
+   for review and possible adoption as a standard.
+
+   For OSI-based applications, MD5's object identifier is
+
+   md5 OBJECT IDENTIFIER ::=
+     iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 5}
+
+   In the X.509 type AlgorithmIdentifier [3], the parameters for MD5
+   should have type NULL.
+
+2. Terminology and Notation
+
+   In this document a "word" is a 32-bit quantity and a "byte" is an
+   eight-bit quantity. A sequence of bits can be interpreted in a
+   natural manner as a sequence of bytes, where each consecutive group
+   of eight bits is interpreted as a byte with the high-order (most
+   significant) bit of each byte listed first. Similarly, a sequence of
+   bytes can be interpreted as a sequence of 32-bit words, where each
+   consecutive group of four bytes is interpreted as a word with the
+   low-order (least significant) byte given first.
+
+   Let x_i denote "x sub i". If the subscript is an expression, we
+   surround it in braces, as in x_{i+1}. Similarly, we use ^ for
+   superscripts (exponentiation), so that x^i denotes x to the i-th
+   power.
+
+   Let the symbol "+" denote addition of words (i.e., modulo-2^32
+   addition). Let X <<< s denote the 32-bit value obtained by circularly
+   shifting (rotating) X left by s bit positions. Let not(X) denote the
+   bit-wise complement of X, and let X v Y denote the bit-wise OR of X
+   and Y. Let X xor Y denote the bit-wise XOR of X and Y, and let XY
+   denote the bit-wise AND of X and Y.
+
+
+
+
+
+Rivest                                                          [Page 2]
+
+RFC 1321              MD5 Message-Digest Algorithm            April 1992
+
+
+3. MD5 Algorithm Description
+
+   We begin by supposing that we have a b-bit message as input, and that
+   we wish to find its message digest. Here b is an arbitrary
+   nonnegative integer; b may be zero, it need not be a multiple of
+   eight, and it may be arbitrarily large. We imagine the bits of the
+   message written down as follows:
+
+          m_0 m_1 ... m_{b-1}
+
+   The following five steps are performed to compute the message digest
+   of the message.
+
+3.1 Step 1. Append Padding Bits
+
+   The message is "padded" (extended) so that its length (in bits) is
+   congruent to 448, modulo 512. That is, the message is extended so
+   that it is just 64 bits shy of being a multiple of 512 bits long.
+   Padding is always performed, even if the length of the message is
+   already congruent to 448, modulo 512.
+
+   Padding is performed as follows: a single "1" bit is appended to the
+   message, and then "0" bits are appended so that the length in bits of
+   the padded message becomes congruent to 448, modulo 512. In all, at
+   least one bit and at most 512 bits are appended.
+
+3.2 Step 2. Append Length
+
+   A 64-bit representation of b (the length of the message before the
+   padding bits were added) is appended to the result of the previous
+   step. In the unlikely event that b is greater than 2^64, then only
+   the low-order 64 bits of b are used. (These bits are appended as two
+   32-bit words and appended low-order word first in accordance with the
+   previous conventions.)
+
+   At this point the resulting message (after padding with bits and with
+   b) has a length that is an exact multiple of 512 bits. Equivalently,
+   this message has a length that is an exact multiple of 16 (32-bit)
+   words. Let M[0 ... N-1] denote the words of the resulting message,
+   where N is a multiple of 16.
+
+3.3 Step 3. Initialize MD Buffer
+
+   A four-word buffer (A,B,C,D) is used to compute the message digest.
+   Here each of A, B, C, D is a 32-bit register. These registers are
+   initialized to the following values in hexadecimal, low-order bytes
+   first):
+
+
+
+
+Rivest                                                          [Page 3]
+
+RFC 1321              MD5 Message-Digest Algorithm            April 1992
+
+
+          word A: 01 23 45 67
+          word B: 89 ab cd ef
+          word C: fe dc ba 98
+          word D: 76 54 32 10
+
+3.4 Step 4. Process Message in 16-Word Blocks
+
+   We first define four auxiliary functions that each take as input
+   three 32-bit words and produce as output one 32-bit word.
+
+          F(X,Y,Z) = XY v not(X) Z
+          G(X,Y,Z) = XZ v Y not(Z)
+          H(X,Y,Z) = X xor Y xor Z
+          I(X,Y,Z) = Y xor (X v not(Z))
+
+   In each bit position F acts as a conditional: if X then Y else Z.
+   The function F could have been defined using + instead of v since XY
+   and not(X)Z will never have 1's in the same bit position.) It is
+   interesting to note that if the bits of X, Y, and Z are independent
+   and unbiased, the each bit of F(X,Y,Z) will be independent and
+   unbiased.
+
+   The functions G, H, and I are similar to the function F, in that they
+   act in "bitwise parallel" to produce their output from the bits of X,
+   Y, and Z, in such a manner that if the corresponding bits of X, Y,
+   and Z are independent and unbiased, then each bit of G(X,Y,Z),
+   H(X,Y,Z), and I(X,Y,Z) will be independent and unbiased. Note that
+   the function H is the bit-wise "xor" or "parity" function of its
+   inputs.
+
+   This step uses a 64-element table T[1 ... 64] constructed from the
+   sine function. Let T[i] denote the i-th element of the table, which
+   is equal to the integer part of 4294967296 times abs(sin(i)), where i
+   is in radians. The elements of the table are given in the appendix.
+
+   Do the following:
+
+   /* Process each 16-word block. */
+   For i = 0 to N/16-1 do
+
+     /* Copy block i into X. */
+     For j = 0 to 15 do
+       Set X[j] to M[i*16+j].
+     end /* of loop on j */
+
+     /* Save A as AA, B as BB, C as CC, and D as DD. */
+     AA = A
+     BB = B
+
+
+
+Rivest                                                          [Page 4]
+
+RFC 1321              MD5 Message-Digest Algorithm            April 1992
+
+
+     CC = C
+     DD = D
+
+     /* Round 1. */
+     /* Let [abcd k s i] denote the operation
+          a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+     /* Do the following 16 operations. */
+     [ABCD  0  7  1]  [DABC  1 12  2]  [CDAB  2 17  3]  [BCDA  3 22  4]
+     [ABCD  4  7  5]  [DABC  5 12  6]  [CDAB  6 17  7]  [BCDA  7 22  8]
+     [ABCD  8  7  9]  [DABC  9 12 10]  [CDAB 10 17 11]  [BCDA 11 22 12]
+     [ABCD 12  7 13]  [DABC 13 12 14]  [CDAB 14 17 15]  [BCDA 15 22 16]
+
+     /* Round 2. */
+     /* Let [abcd k s i] denote the operation
+          a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+     /* Do the following 16 operations. */
+     [ABCD  1  5 17]  [DABC  6  9 18]  [CDAB 11 14 19]  [BCDA  0 20 20]
+     [ABCD  5  5 21]  [DABC 10  9 22]  [CDAB 15 14 23]  [BCDA  4 20 24]
+     [ABCD  9  5 25]  [DABC 14  9 26]  [CDAB  3 14 27]  [BCDA  8 20 28]
+     [ABCD 13  5 29]  [DABC  2  9 30]  [CDAB  7 14 31]  [BCDA 12 20 32]
+
+     /* Round 3. */
+     /* Let [abcd k s t] denote the operation
+          a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+     /* Do the following 16 operations. */
+     [ABCD  5  4 33]  [DABC  8 11 34]  [CDAB 11 16 35]  [BCDA 14 23 36]
+     [ABCD  1  4 37]  [DABC  4 11 38]  [CDAB  7 16 39]  [BCDA 10 23 40]
+     [ABCD 13  4 41]  [DABC  0 11 42]  [CDAB  3 16 43]  [BCDA  6 23 44]
+     [ABCD  9  4 45]  [DABC 12 11 46]  [CDAB 15 16 47]  [BCDA  2 23 48]
+
+     /* Round 4. */
+     /* Let [abcd k s t] denote the operation
+          a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+     /* Do the following 16 operations. */
+     [ABCD  0  6 49]  [DABC  7 10 50]  [CDAB 14 15 51]  [BCDA  5 21 52]
+     [ABCD 12  6 53]  [DABC  3 10 54]  [CDAB 10 15 55]  [BCDA  1 21 56]
+     [ABCD  8  6 57]  [DABC 15 10 58]  [CDAB  6 15 59]  [BCDA 13 21 60]
+     [ABCD  4  6 61]  [DABC 11 10 62]  [CDAB  2 15 63]  [BCDA  9 21 64]
+
+     /* Then perform the following additions. (That is increment each
+        of the four registers by the value it had before this block
+        was started.) */
+     A = A + AA
+     B = B + BB
+     C = C + CC
+     D = D + DD
+
+   end /* of loop on i */
+
+
+
+Rivest                                                          [Page 5]
+
+RFC 1321              MD5 Message-Digest Algorithm            April 1992
+
+
+3.5 Step 5. Output
+
+   The message digest produced as output is A, B, C, D. That is, we
+   begin with the low-order byte of A, and end with the high-order byte
+   of D.
+
+   This completes the description of MD5. A reference implementation in
+   C is given in the appendix.
+
+4. Summary
+
+   The MD5 message-digest algorithm is simple to implement, and provides
+   a "fingerprint" or message digest of a message of arbitrary length.
+   It is conjectured that the difficulty of coming up with two messages
+   having the same message digest is on the order of 2^64 operations,
+   and that the difficulty of coming up with any message having a given
+   message digest is on the order of 2^128 operations. The MD5 algorithm
+   has been carefully scrutinized for weaknesses. It is, however, a
+   relatively new algorithm and further security analysis is of course
+   justified, as is the case with any new proposal of this sort.
+
+5. Differences Between MD4 and MD5
+
+     The following are the differences between MD4 and MD5:
+
+       1.   A fourth round has been added.
+
+       2.   Each step now has a unique additive constant.
+
+       3.   The function g in round 2 was changed from (XY v XZ v YZ) to
+       (XZ v Y not(Z)) to make g less symmetric.
+
+       4.   Each step now adds in the result of the previous step.  This
+       promotes a faster "avalanche effect".
+
+       5.   The order in which input words are accessed in rounds 2 and
+       3 is changed, to make these patterns less like each other.
+
+       6.   The shift amounts in each round have been approximately
+       optimized, to yield a faster "avalanche effect." The shifts in
+       different rounds are distinct.
+
+
+
+
+
+
+
+
+
+
+Rivest                                                          [Page 6]
+
+RFC 1321              MD5 Message-Digest Algorithm            April 1992
+
+
+References
+
+   [1] Rivest, R., "The MD4 Message Digest Algorithm", RFC 1320, MIT and
+       RSA Data Security, Inc., April 1992.
+
+   [2] Rivest, R., "The MD4 message digest algorithm", in A.J.  Menezes
+       and S.A. Vanstone, editors, Advances in Cryptology - CRYPTO '90
+       Proceedings, pages 303-311, Springer-Verlag, 1991.
+
+   [3] CCITT Recommendation X.509 (1988), "The Directory -
+       Authentication Framework."
+
+APPENDIX A - Reference Implementation
+
+   This appendix contains the following files taken from RSAREF: A
+   Cryptographic Toolkit for Privacy-Enhanced Mail:
+
+     global.h -- global header file
+
+     md5.h -- header file for MD5
+
+     md5c.c -- source code for MD5
+
+   For more information on RSAREF, send email to <rsaref at rsa.com>.
+
+   The appendix also includes the following file:
+
+     mddriver.c -- test driver for MD2, MD4 and MD5
+
+   The driver compiles for MD5 by default but can compile for MD2 or MD4
+   if the symbol MD is defined on the C compiler command line as 2 or 4.
+
+   The implementation is portable and should work on many different
+   plaforms. However, it is not difficult to optimize the implementation
+   on particular platforms, an exercise left to the reader. For example,
+   on "little-endian" platforms where the lowest-addressed byte in a 32-
+   bit word is the least significant and there are no alignment
+   restrictions, the call to Decode in MD5Transform can be replaced with
+   a typecast.
+
+A.1 global.h
+
+/* GLOBAL.H - RSAREF types and constants
+ */
+
+/* PROTOTYPES should be set to one if and only if the compiler supports
+  function argument prototyping.
+The following makes PROTOTYPES default to 0 if it has not already
+
+
+
+Rivest                                                          [Page 7]
+
+RFC 1321              MD5 Message-Digest Algorithm            April 1992
+
+
+  been defined with C compiler flags.
+ */
+#ifndef PROTOTYPES
+#define PROTOTYPES 0
+#endif
+
+/* POINTER defines a generic pointer type */
+typedef unsigned char *POINTER;
+
+/* UINT2 defines a two byte word */
+typedef unsigned short int UINT2;
+
+/* UINT4 defines a four byte word */
+typedef unsigned long int UINT4;
+
+/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
+If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
+  returns an empty list.
+ */
+#if PROTOTYPES
+#define PROTO_LIST(list) list
+#else
+#define PROTO_LIST(list) ()
+#endif
+
+A.2 md5.h
+
+/* MD5.H - header file for MD5C.C
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+
+
+
+Rivest                                                          [Page 8]
+
+RFC 1321              MD5 Message-Digest Algorithm            April 1992
+
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+/* MD5 context. */
+typedef struct {
+  UINT4 state[4];                                   /* state (ABCD) */
+  UINT4 count[2];        /* number of bits, modulo 2^64 (lsb first) */
+  unsigned char buffer[64];                         /* input buffer */
+} MD5_CTX;
+
+void MD5Init PROTO_LIST ((MD5_CTX *));
+void MD5Update PROTO_LIST
+  ((MD5_CTX *, unsigned char *, unsigned int));
+void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
+
+A.3 md5c.c
+
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+#include "global.h"
+#include "md5.h"
+
+/* Constants for MD5Transform routine.
+ */
+
+
+
+Rivest                                                          [Page 9]
+
+RFC 1321              MD5 Message-Digest Algorithm            April 1992
+
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64]));
+static void Encode PROTO_LIST
+  ((unsigned char *, UINT4 *, unsigned int));
+static void Decode PROTO_LIST
+  ((UINT4 *, unsigned char *, unsigned int));
+static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
+static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
+
+static unsigned char PADDING[64] = {
+  0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+
+
+
+Rivest                                                         [Page 10]
+
+RFC 1321              MD5 Message-Digest Algorithm            April 1992
+
+
+ (a) += (b); \
+  }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+  }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+  }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+  }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+void MD5Init (context)
+MD5_CTX *context;                                        /* context */
+{
+  context->count[0] = context->count[1] = 0;
+  /* Load magic initialization constants.
+*/
+  context->state[0] = 0x67452301;
+  context->state[1] = 0xefcdab89;
+  context->state[2] = 0x98badcfe;
+  context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+  operation, processing another message block, and updating the
+  context.
+ */
+void MD5Update (context, input, inputLen)
+MD5_CTX *context;                                        /* context */
+unsigned char *input;                                /* input block */
+unsigned int inputLen;                     /* length of input block */
+{
+  unsigned int i, index, partLen;
+
+  /* Compute number of bytes mod 64 */
+  index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+  /* Update number of bits */
+  if ((context->count[0] += ((UINT4)inputLen << 3))
+
+
+
+Rivest                                                         [Page 11]
+
+RFC 1321              MD5 Message-Digest Algorithm            April 1992
+
+
+   < ((UINT4)inputLen << 3))
+ context->count[1]++;
+  context->count[1] += ((UINT4)inputLen >> 29);
+
+  partLen = 64 - index;
+
+  /* Transform as many times as possible.
+*/
+  if (inputLen >= partLen) {
+ MD5_memcpy
+   ((POINTER)&context->buffer[index], (POINTER)input, partLen);
+ MD5Transform (context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+   MD5Transform (context->state, &input[i]);
+
+ index = 0;
+  }
+  else
+ i = 0;
+
+  /* Buffer remaining input */
+  MD5_memcpy
+ ((POINTER)&context->buffer[index], (POINTER)&input[i],
+  inputLen-i);
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+  the message digest and zeroizing the context.
+ */
+void MD5Final (digest, context)
+unsigned char digest[16];                         /* message digest */
+MD5_CTX *context;                                       /* context */
+{
+  unsigned char bits[8];
+  unsigned int index, padLen;
+
+  /* Save number of bits */
+  Encode (bits, context->count, 8);
+
+  /* Pad out to 56 mod 64.
+*/
+  index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+  padLen = (index < 56) ? (56 - index) : (120 - index);
+  MD5Update (context, PADDING, padLen);
+
+  /* Append length (before padding) */
+  MD5Update (context, bits, 8);
+
+
+
+Rivest                                                         [Page 12]
+
+RFC 1321              MD5 Message-Digest Algorithm            April 1992
+
+
+  /* Store state in digest */
+  Encode (digest, context->state, 16);
+
+  /* Zeroize sensitive information.
+*/
+  MD5_memset ((POINTER)context, 0, sizeof (*context));
+}
+
+/* MD5 basic transformation. Transforms state based on block.
+ */
+static void MD5Transform (state, block)
+UINT4 state[4];
+unsigned char block[64];
+{
+  UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+  Decode (x, block, 64);
+
+  /* Round 1 */
+  FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+  FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+  FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+  FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+  FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+  FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+  FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+  FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+  FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+  FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+  FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+  FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+  FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+  FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+  FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+  FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+  GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+  GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+  GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+  GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+  GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+  GG (d, a, b, c, x[10], S22,  0x2441453); /* 22 */
+  GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+  GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+  GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+  GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+  GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+
+
+
+Rivest                                                         [Page 13]
+
+RFC 1321              MD5 Message-Digest Algorithm            April 1992
+
+
+  GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+  GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+  GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+  GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+  GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+  /* Round 3 */
+  HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+  HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+  HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+  HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+  HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+  HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+  HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+  HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+  HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+  HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+  HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+  HH (b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
+  HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+  HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+  HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+  HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+  /* Round 4 */
+  II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+  II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+  II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+  II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+  II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+  II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+  II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+  II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+  II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+  II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+  II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+  II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+  II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+  II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+  II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+  II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+  state[0] += a;
+  state[1] += b;
+  state[2] += c;
+  state[3] += d;
+
+  /* Zeroize sensitive information.
+
+
+
+Rivest                                                         [Page 14]
+
+RFC 1321              MD5 Message-Digest Algorithm            April 1992
+
+
+*/
+  MD5_memset ((POINTER)x, 0, sizeof (x));
+}
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+  a multiple of 4.
+ */
+static void Encode (output, input, len)
+unsigned char *output;
+UINT4 *input;
+unsigned int len;
+{
+  unsigned int i, j;
+
+  for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+  }
+}
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+  a multiple of 4.
+ */
+static void Decode (output, input, len)
+UINT4 *output;
+unsigned char *input;
+unsigned int len;
+{
+  unsigned int i, j;
+
+  for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+   (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+/* Note: Replace "for loop" with standard memcpy if possible.
+ */
+
+static void MD5_memcpy (output, input, len)
+POINTER output;
+POINTER input;
+unsigned int len;
+{
+  unsigned int i;
+
+  for (i = 0; i < len; i++)
+
+
+
+Rivest                                                         [Page 15]
+
+RFC 1321              MD5 Message-Digest Algorithm            April 1992
+
+
+ output[i] = input[i];
+}
+
+/* Note: Replace "for loop" with standard memset if possible.
+ */
+static void MD5_memset (output, value, len)
+POINTER output;
+int value;
+unsigned int len;
+{
+  unsigned int i;
+
+  for (i = 0; i < len; i++)
+ ((char *)output)[i] = (char)value;
+}
+
+A.4 mddriver.c
+
+/* MDDRIVER.C - test driver for MD2, MD4 and MD5
+ */
+
+/* Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
+rights reserved.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+/* The following makes MD default to MD5 if it has not already been
+  defined with C compiler flags.
+ */
+#ifndef MD
+#define MD MD5
+#endif
+
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#include "global.h"
+#if MD == 2
+#include "md2.h"
+#endif
+#if MD == 4
+
+
+
+Rivest                                                         [Page 16]
+
+RFC 1321              MD5 Message-Digest Algorithm            April 1992
+
+
+#include "md4.h"
+#endif
+#if MD == 5
+#include "md5.h"
+#endif
+
+/* Length of test block, number of test blocks.
+ */
+#define TEST_BLOCK_LEN 1000
+#define TEST_BLOCK_COUNT 1000
+
+static void MDString PROTO_LIST ((char *));
+static void MDTimeTrial PROTO_LIST ((void));
+static void MDTestSuite PROTO_LIST ((void));
+static void MDFile PROTO_LIST ((char *));
+static void MDFilter PROTO_LIST ((void));
+static void MDPrint PROTO_LIST ((unsigned char [16]));
+
+#if MD == 2
+#define MD_CTX MD2_CTX
+#define MDInit MD2Init
+#define MDUpdate MD2Update
+#define MDFinal MD2Final
+#endif
+#if MD == 4
+#define MD_CTX MD4_CTX
+#define MDInit MD4Init
+#define MDUpdate MD4Update
+#define MDFinal MD4Final
+#endif
+#if MD == 5
+#define MD_CTX MD5_CTX
+#define MDInit MD5Init
+#define MDUpdate MD5Update
+#define MDFinal MD5Final
+#endif
+
+/* Main driver.
+
+Arguments (may be any combination):
+  -sstring - digests string
+  -t       - runs time trial
+  -x       - runs test script
+  filename - digests file
+  (none)   - digests standard input
+ */
+int main (argc, argv)
+int argc;
+
+
+
+Rivest                                                         [Page 17]
+
+RFC 1321              MD5 Message-Digest Algorithm            April 1992
+
+
+char *argv[];
+{
+  int i;
+
+  if (argc > 1)
+ for (i = 1; i < argc; i++)
+   if (argv[i][0] == '-' && argv[i][1] == 's')
+     MDString (argv[i] + 2);
+   else if (strcmp (argv[i], "-t") == 0)
+     MDTimeTrial ();
+   else if (strcmp (argv[i], "-x") == 0)
+     MDTestSuite ();
+   else
+     MDFile (argv[i]);
+  else
+ MDFilter ();
+
+  return (0);
+}
+
+/* Digests a string and prints the result.
+ */
+static void MDString (string)
+char *string;
+{
+  MD_CTX context;
+  unsigned char digest[16];
+  unsigned int len = strlen (string);
+
+  MDInit (&context);
+  MDUpdate (&context, string, len);
+  MDFinal (digest, &context);
+
+  printf ("MD%d (\"%s\") = ", MD, string);
+  MDPrint (digest);
+  printf ("\n");
+}
+
+/* Measures the time to digest TEST_BLOCK_COUNT TEST_BLOCK_LEN-byte
+  blocks.
+ */
+static void MDTimeTrial ()
+{
+  MD_CTX context;
+  time_t endTime, startTime;
+  unsigned char block[TEST_BLOCK_LEN], digest[16];
+  unsigned int i;
+
+
+
+
+Rivest                                                         [Page 18]
+
+RFC 1321              MD5 Message-Digest Algorithm            April 1992
+
+
+  printf
+ ("MD%d time trial. Digesting %d %d-byte blocks ...", MD,
+  TEST_BLOCK_LEN, TEST_BLOCK_COUNT);
+
+  /* Initialize block */
+  for (i = 0; i < TEST_BLOCK_LEN; i++)
+ block[i] = (unsigned char)(i & 0xff);
+
+  /* Start timer */
+  time (&startTime);
+
+  /* Digest blocks */
+  MDInit (&context);
+  for (i = 0; i < TEST_BLOCK_COUNT; i++)
+ MDUpdate (&context, block, TEST_BLOCK_LEN);
+  MDFinal (digest, &context);
+
+  /* Stop timer */
+  time (&endTime);
+
+  printf (" done\n");
+  printf ("Digest = ");
+  MDPrint (digest);
+  printf ("\nTime = %ld seconds\n", (long)(endTime-startTime));
+  printf
+ ("Speed = %ld bytes/second\n",
+  (long)TEST_BLOCK_LEN * (long)TEST_BLOCK_COUNT/(endTime-startTime));
+}
+
+/* Digests a reference suite of strings and prints the results.
+ */
+static void MDTestSuite ()
+{
+  printf ("MD%d test suite:\n", MD);
+
+  MDString ("");
+  MDString ("a");
+  MDString ("abc");
+  MDString ("message digest");
+  MDString ("abcdefghijklmnopqrstuvwxyz");
+  MDString
+ ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
+  MDString
+ ("1234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890");
+}
+
+/* Digests a file and prints the result.
+
+
+
+Rivest                                                         [Page 19]
+
+RFC 1321              MD5 Message-Digest Algorithm            April 1992
+
+
+ */
+static void MDFile (filename)
+char *filename;
+{
+  FILE *file;
+  MD_CTX context;
+  int len;
+  unsigned char buffer[1024], digest[16];
+
+  if ((file = fopen (filename, "rb")) == NULL)
+ printf ("%s can't be opened\n", filename);
+
+  else {
+ MDInit (&context);
+ while (len = fread (buffer, 1, 1024, file))
+   MDUpdate (&context, buffer, len);
+ MDFinal (digest, &context);
+
+ fclose (file);
+
+ printf ("MD%d (%s) = ", MD, filename);
+ MDPrint (digest);
+ printf ("\n");
+  }
+}
+
+/* Digests the standard input and prints the result.
+ */
+static void MDFilter ()
+{
+  MD_CTX context;
+  int len;
+  unsigned char buffer[16], digest[16];
+
+  MDInit (&context);
+  while (len = fread (buffer, 1, 16, stdin))
+ MDUpdate (&context, buffer, len);
+  MDFinal (digest, &context);
+
+  MDPrint (digest);
+  printf ("\n");
+}
+
+/* Prints a message digest in hexadecimal.
+ */
+static void MDPrint (digest)
+unsigned char digest[16];
+{
+
+
+
+Rivest                                                         [Page 20]
+
+RFC 1321              MD5 Message-Digest Algorithm            April 1992
+
+
+  unsigned int i;
+
+  for (i = 0; i < 16; i++)
+ printf ("%02x", digest[i]);
+}
+
+A.5 Test suite
+
+   The MD5 test suite (driver option "-x") should print the following
+   results:
+
+MD5 test suite:
+MD5 ("") = d41d8cd98f00b204e9800998ecf8427e
+MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661
+MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72
+MD5 ("message digest") = f96b697d7cb7938d525a2f31aaf161d0
+MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b
+MD5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") =
+d174ab98d277d9f5a5611c2c9f419d9f
+MD5 ("123456789012345678901234567890123456789012345678901234567890123456
+78901234567890") = 57edf4a22be3c955ac49da2e2107b67a
+
+Security Considerations
+
+   The level of security discussed in this memo is considered to be
+   sufficient for implementing very high security hybrid digital-
+   signature schemes based on MD5 and a public-key cryptosystem.
+
+Author's Address
+
+   Ronald L. Rivest
+   Massachusetts Institute of Technology
+   Laboratory for Computer Science
+   NE43-324
+   545 Technology Square
+   Cambridge, MA  02139-1986
+
+   Phone: (617) 253-5880
+   EMail: rivest at theory.lcs.mit.edu
+
+
+
+
+
+
+
+
+
+
+
+
+Rivest                                                         [Page 21]
+

Added: trunk/orca/packages/Digest-MD5-2.07/typemap
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/typemap	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/typemap	Sat Jul 13 18:45:56 2002
@@ -0,0 +1,5 @@
+MD5_CTX*	T_MD5_CTX
+
+INPUT
+T_MD5_CTX
+	$var = get_md5_ctx($arg)

Added: trunk/orca/packages/Digest-MD5-2.07/rfc2104.txt
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/rfc2104.txt	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/rfc2104.txt	Sat Jul 13 18:45:56 2002
@@ -0,0 +1,619 @@
+
+
+
+
+
+
+Network Working Group                                       H. Krawczyk
+Request for Comments: 2104                                          IBM
+Category: Informational                                      M. Bellare
+                                                                   UCSD
+                                                             R. Canetti
+                                                                    IBM
+                                                          February 1997
+
+
+             HMAC: Keyed-Hashing for Message Authentication
+
+Status of This Memo
+
+   This memo provides information for the Internet community.  This memo
+   does not specify an Internet standard of any kind.  Distribution of
+   this memo is unlimited.
+
+Abstract
+
+   This document describes HMAC, a mechanism for message authentication
+   using cryptographic hash functions. HMAC can be used with any
+   iterative cryptographic hash function, e.g., MD5, SHA-1, in
+   combination with a secret shared key.  The cryptographic strength of
+   HMAC depends on the properties of the underlying hash function.
+
+1. Introduction
+
+   Providing a way to check the integrity of information transmitted
+   over or stored in an unreliable medium is a prime necessity in the
+   world of open computing and communications. Mechanisms that provide
+   such integrity check based on a secret key are usually called
+   "message authentication codes" (MAC). Typically, message
+   authentication codes are used between two parties that share a secret
+   key in order to validate information transmitted between these
+   parties. In this document we present such a MAC mechanism based on
+   cryptographic hash functions. This mechanism, called HMAC, is based
+   on work by the authors [BCK1] where the construction is presented and
+   cryptographically analyzed. We refer to that work for the details on
+   the rationale and security analysis of HMAC, and its comparison to
+   other keyed-hash methods.
+
+
+
+
+
+
+
+
+
+
+
+Krawczyk, et. al.            Informational                      [Page 1]
+
+RFC 2104                          HMAC                     February 1997
+
+
+   HMAC can be used in combination with any iterated cryptographic hash
+   function. MD5 and SHA-1 are examples of such hash functions. HMAC
+   also uses a secret key for calculation and verification of the
+   message authentication values. The main goals behind this
+   construction are
+
+   * To use, without modifications, available hash functions.
+     In particular, hash functions that perform well in software,
+     and for which code is freely and widely available.
+
+   * To preserve the original performance of the hash function without
+     incurring a significant degradation.
+
+   * To use and handle keys in a simple way.
+
+   * To have a well understood cryptographic analysis of the strength of
+     the authentication mechanism based on reasonable assumptions on the
+     underlying hash function.
+
+   * To allow for easy replaceability of the underlying hash function in
+     case that faster or more secure hash functions are found or
+     required.
+
+   This document specifies HMAC using a generic cryptographic hash
+   function (denoted by H). Specific instantiations of HMAC need to
+   define a particular hash function. Current candidates for such hash
+   functions include SHA-1 [SHA], MD5 [MD5], RIPEMD-128/160 [RIPEMD].
+   These different realizations of HMAC will be denoted by HMAC-SHA1,
+   HMAC-MD5, HMAC-RIPEMD, etc.
+
+   Note: To the date of writing of this document MD5 and SHA-1 are the
+   most widely used cryptographic hash functions. MD5 has been recently
+   shown to be vulnerable to collision search attacks [Dobb].  This
+   attack and other currently known weaknesses of MD5 do not compromise
+   the use of MD5 within HMAC as specified in this document (see
+   [Dobb]); however, SHA-1 appears to be a cryptographically stronger
+   function. To this date, MD5 can be considered for use in HMAC for
+   applications where the superior performance of MD5 is critical.   In
+   any case, implementers and users need to be aware of possible
+   cryptanalytic developments regarding any of these cryptographic hash
+   functions, and the eventual need to replace the underlying hash
+   function. (See section 6 for more information on the security of
+   HMAC.)
+
+
+
+
+
+
+
+
+Krawczyk, et. al.            Informational                      [Page 2]
+
+RFC 2104                          HMAC                     February 1997
+
+
+2. Definition of HMAC
+
+   The definition of HMAC requires a cryptographic hash function, which
+   we denote by H, and a secret key K. We assume H to be a cryptographic
+   hash function where data is hashed by iterating a basic compression
+   function on blocks of data.   We denote by B the byte-length of such
+   blocks (B=64 for all the above mentioned examples of hash functions),
+   and by L the byte-length of hash outputs (L=16 for MD5, L=20 for
+   SHA-1).  The authentication key K can be of any length up to B, the
+   block length of the hash function.  Applications that use keys longer
+   than B bytes will first hash the key using H and then use the
+   resultant L byte string as the actual key to HMAC. In any case the
+   minimal recommended length for K is L bytes (as the hash output
+   length). See section 3 for more information on keys.
+
+   We define two fixed and different strings ipad and opad as follows
+   (the 'i' and 'o' are mnemonics for inner and outer):
+
+                   ipad = the byte 0x36 repeated B times
+                  opad = the byte 0x5C repeated B times.
+
+   To compute HMAC over the data `text' we perform
+
+                    H(K XOR opad, H(K XOR ipad, text))
+
+   Namely,
+
+    (1) append zeros to the end of K to create a B byte string
+        (e.g., if K is of length 20 bytes and B=64, then K will be
+         appended with 44 zero bytes 0x00)
+    (2) XOR (bitwise exclusive-OR) the B byte string computed in step
+        (1) with ipad
+    (3) append the stream of data 'text' to the B byte string resulting
+        from step (2)
+    (4) apply H to the stream generated in step (3)
+    (5) XOR (bitwise exclusive-OR) the B byte string computed in
+        step (1) with opad
+    (6) append the H result from step (4) to the B byte string
+        resulting from step (5)
+    (7) apply H to the stream generated in step (6) and output
+        the result
+
+   For illustration purposes, sample code based on MD5 is provided as an
+   appendix.
+
+
+
+
+
+
+
+Krawczyk, et. al.            Informational                      [Page 3]
+
+RFC 2104                          HMAC                     February 1997
+
+
+3. Keys
+
+   The key for HMAC can be of any length (keys longer than B bytes are
+   first hashed using H).  However, less than L bytes is strongly
+   discouraged as it would decrease the security strength of the
+   function.  Keys longer than L bytes are acceptable but the extra
+   length would not significantly increase the function strength. (A
+   longer key may be advisable if the randomness of the key is
+   considered weak.)
+
+   Keys need to be chosen at random (or using a cryptographically strong
+   pseudo-random generator seeded with a random seed), and periodically
+   refreshed.  (Current attacks do not indicate a specific recommended
+   frequency for key changes as these attacks are practically
+   infeasible.  However, periodic key refreshment is a fundamental
+   security practice that helps against potential weaknesses of the
+   function and keys, and limits the damage of an exposed key.)
+
+4. Implementation Note
+
+   HMAC is defined in such a way that the underlying hash function H can
+   be used with no modification to its code. In particular, it uses the
+   function H with the pre-defined initial value IV (a fixed value
+   specified by each iterative hash function to initialize its
+   compression function).  However, if desired, a performance
+   improvement can be achieved at the cost of (possibly) modifying the
+   code of H to support variable IVs.
+
+   The idea is that the intermediate results of the compression function
+   on the B-byte blocks (K XOR ipad) and (K XOR opad) can be precomputed
+   only once at the time of generation of the key K, or before its first
+   use. These intermediate results are stored and then used to
+   initialize the IV of H each time that a message needs to be
+   authenticated.  This method saves, for each authenticated message,
+   the application of the compression function of H on two B-byte blocks
+   (i.e., on (K XOR ipad) and (K XOR opad)). Such a savings may be
+   significant when authenticating short streams of data.  We stress
+   that the stored intermediate values need to be treated and protected
+   the same as secret keys.
+
+   Choosing to implement HMAC in the above way is a decision of the
+   local implementation and has no effect on inter-operability.
+
+
+
+
+
+
+
+
+
+Krawczyk, et. al.            Informational                      [Page 4]
+
+RFC 2104                          HMAC                     February 1997
+
+
+5. Truncated output
+
+   A well-known practice with message authentication codes is to
+   truncate the output of the MAC and output only part of the bits
+   (e.g., [MM, ANSI]).  Preneel and van Oorschot [PV] show some
+   analytical advantages of truncating the output of hash-based MAC
+   functions. The results in this area are not absolute as for the
+   overall security advantages of truncation. It has advantages (less
+   information on the hash result available to an attacker) and
+   disadvantages (less bits to predict for the attacker).  Applications
+   of HMAC can choose to truncate the output of HMAC by outputting the t
+   leftmost bits of the HMAC computation for some parameter t (namely,
+   the computation is carried in the normal way as defined in section 2
+   above but the end result is truncated to t bits). We recommend that
+   the output length t be not less than half the length of the hash
+   output (to match the birthday attack bound) and not less than 80 bits
+   (a suitable lower bound on the number of bits that need to be
+   predicted by an attacker).  We propose denoting a realization of HMAC
+   that uses a hash function H with t bits of output as HMAC-H-t. For
+   example, HMAC-SHA1-80 denotes HMAC computed using the SHA-1 function
+   and with the output truncated to 80 bits.  (If the parameter t is not
+   specified, e.g. HMAC-MD5, then it is assumed that all the bits of the
+   hash are output.)
+
+6. Security
+
+   The security of the message authentication mechanism presented here
+   depends on cryptographic properties of the hash function H: the
+   resistance to collision finding (limited to the case where the
+   initial value is secret and random, and where the output of the
+   function is not explicitly available to the attacker), and the
+   message authentication property of the compression function of H when
+   applied to single blocks (in HMAC these blocks are partially unknown
+   to an attacker as they contain the result of the inner H computation
+   and, in particular, cannot be fully chosen by the attacker).
+
+   These properties, and actually stronger ones, are commonly assumed
+   for hash functions of the kind used with HMAC. In particular, a hash
+   function for which the above properties do not hold would become
+   unsuitable for most (probably, all) cryptographic applications,
+   including alternative message authentication schemes based on such
+   functions.  (For a complete analysis and rationale of the HMAC
+   function the reader is referred to [BCK1].)
+
+
+
+
+
+
+
+
+Krawczyk, et. al.            Informational                      [Page 5]
+
+RFC 2104                          HMAC                     February 1997
+
+
+   Given the limited confidence gained so far as for the cryptographic
+   strength of candidate hash functions, it is important to observe the
+   following two properties of the HMAC construction and its secure use
+   for message authentication:
+
+   1. The construction is independent of the details of the particular
+   hash function H in use and then the latter can be replaced by any
+   other secure (iterative) cryptographic hash function.
+
+   2. Message authentication, as opposed to encryption, has a
+   "transient" effect. A published breaking of a message authentication
+   scheme would lead to the replacement of that scheme, but would have
+   no adversarial effect on information authenticated in the past.  This
+   is in sharp contrast with encryption, where information encrypted
+   today may suffer from exposure in the future if, and when, the
+   encryption algorithm is broken.
+
+   The strongest attack known against HMAC is based on the frequency of
+   collisions for the hash function H ("birthday attack") [PV,BCK2], and
+   is totally impractical for minimally reasonable hash functions.
+
+   As an example, if we consider a hash function like MD5 where the
+   output length equals L=16 bytes (128 bits) the attacker needs to
+   acquire the correct message authentication tags computed (with the
+   _same_ secret key K!) on about 2**64 known plaintexts.  This would
+   require the processing of at least 2**64 blocks under H, an
+   impossible task in any realistic scenario (for a block length of 64
+   bytes this would take 250,000 years in a continuous 1Gbps link, and
+   without changing the secret key K during all this time).  This attack
+   could become realistic only if serious flaws in the collision
+   behavior of the function H are discovered (e.g.  collisions found
+   after 2**30 messages). Such a discovery would determine the immediate
+   replacement of the function H (the effects of such failure would be
+   far more severe for the traditional uses of H in the context of
+   digital signatures, public key certificates, etc.).
+
+   Note: this attack needs to be strongly contrasted with regular
+   collision attacks on cryptographic hash functions where no secret key
+   is involved and where 2**64 off-line parallelizable (!) operations
+   suffice to find collisions.  The latter attack is approaching
+   feasibility [VW] while the birthday attack on HMAC is totally
+   impractical.  (In the above examples, if one uses a hash function
+   with, say, 160 bit of output then 2**64 should be replaced by 2**80.)
+
+
+
+
+
+
+
+
+Krawczyk, et. al.            Informational                      [Page 6]
+
+RFC 2104                          HMAC                     February 1997
+
+
+   A correct implementation of the above construction, the choice of
+   random (or cryptographically pseudorandom) keys, a secure key
+   exchange mechanism, frequent key refreshments, and good secrecy
+   protection of keys are all essential ingredients for the security of
+   the integrity verification mechanism provided by HMAC.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Krawczyk, et. al.            Informational                      [Page 7]
+
+RFC 2104                          HMAC                     February 1997
+
+
+Appendix -- Sample Code
+
+   For the sake of illustration we provide the following sample code for
+   the implementation of HMAC-MD5 as well as some corresponding test
+   vectors (the code is based on MD5 code as described in [MD5]).
+
+/*
+** Function: hmac_md5
+*/
+
+void
+hmac_md5(text, text_len, key, key_len, digest)
+unsigned char*  text;                /* pointer to data stream */
+int             text_len;            /* length of data stream */
+unsigned char*  key;                 /* pointer to authentication key */
+int             key_len;             /* length of authentication key */
+caddr_t         digest;              /* caller digest to be filled in */
+
+{
+        MD5_CTX context;
+        unsigned char k_ipad[65];    /* inner padding -
+                                      * key XORd with ipad
+                                      */
+        unsigned char k_opad[65];    /* outer padding -
+                                      * key XORd with opad
+                                      */
+        unsigned char tk[16];
+        int i;
+        /* if key is longer than 64 bytes reset it to key=MD5(key) */
+        if (key_len > 64) {
+
+                MD5_CTX      tctx;
+
+                MD5Init(&tctx);
+                MD5Update(&tctx, key, key_len);
+                MD5Final(tk, &tctx);
+
+                key = tk;
+                key_len = 16;
+        }
+
+        /*
+         * the HMAC_MD5 transform looks like:
+         *
+         * MD5(K XOR opad, MD5(K XOR ipad, text))
+         *
+         * where K is an n byte key
+         * ipad is the byte 0x36 repeated 64 times
+
+
+
+Krawczyk, et. al.            Informational                      [Page 8]
+
+RFC 2104                          HMAC                     February 1997
+
+
+         * opad is the byte 0x5c repeated 64 times
+         * and text is the data being protected
+         */
+
+        /* start out by storing key in pads */
+        bzero( k_ipad, sizeof k_ipad);
+        bzero( k_opad, sizeof k_opad);
+        bcopy( key, k_ipad, key_len);
+        bcopy( key, k_opad, key_len);
+
+        /* XOR key with ipad and opad values */
+        for (i=0; i<64; i++) {
+                k_ipad[i] ^= 0x36;
+                k_opad[i] ^= 0x5c;
+        }
+        /*
+         * perform inner MD5
+         */
+        MD5Init(&context);                   /* init context for 1st
+                                              * pass */
+        MD5Update(&context, k_ipad, 64)      /* start with inner pad */
+        MD5Update(&context, text, text_len); /* then text of datagram */
+        MD5Final(digest, &context);          /* finish up 1st pass */
+        /*
+         * perform outer MD5
+         */
+        MD5Init(&context);                   /* init context for 2nd
+                                              * pass */
+        MD5Update(&context, k_opad, 64);     /* start with outer pad */
+        MD5Update(&context, digest, 16);     /* then results of 1st
+                                              * hash */
+        MD5Final(digest, &context);          /* finish up 2nd pass */
+}
+
+Test Vectors (Trailing '\0' of a character string not included in test):
+
+  key =         0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
+  key_len =     16 bytes
+  data =        "Hi There"
+  data_len =    8  bytes
+  digest =      0x9294727a3638bb1c13f48ef8158bfc9d
+
+  key =         "Jefe"
+  data =        "what do ya want for nothing?"
+  data_len =    28 bytes
+  digest =      0x750c783e6ab0b503eaa86e310a5db738
+
+  key =         0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+
+
+
+Krawczyk, et. al.            Informational                      [Page 9]
+
+RFC 2104                          HMAC                     February 1997
+
+
+  key_len       16 bytes
+  data =        0xDDDDDDDDDDDDDDDDDDDD...
+                ..DDDDDDDDDDDDDDDDDDDD...
+                ..DDDDDDDDDDDDDDDDDDDD...
+                ..DDDDDDDDDDDDDDDDDDDD...
+                ..DDDDDDDDDDDDDDDDDDDD
+  data_len =    50 bytes
+  digest =      0x56be34521d144c88dbb8c733f0e8b3f6
+
+Acknowledgments
+
+   Pau-Chen Cheng, Jeff Kraemer, and Michael Oehler, have provided
+   useful comments on early drafts, and ran the first interoperability
+   tests of this specification. Jeff and Pau-Chen kindly provided the
+   sample code and test vectors that appear in the appendix.  Burt
+   Kaliski, Bart Preneel, Matt Robshaw, Adi Shamir, and Paul van
+   Oorschot have provided useful comments and suggestions during the
+   investigation of the HMAC construction.
+
+References
+
+   [ANSI]  ANSI X9.9, "American National Standard for Financial
+           Institution Message Authentication (Wholesale)," American
+           Bankers Association, 1981.   Revised 1986.
+
+   [Atk]   Atkinson, R., "IP Authentication Header", RFC 1826, August
+           1995.
+
+   [BCK1]  M. Bellare, R. Canetti, and H. Krawczyk,
+           "Keyed Hash Functions and Message Authentication",
+           Proceedings of Crypto'96, LNCS 1109, pp. 1-15.
+           (http://www.research.ibm.com/security/keyed-md5.html)
+
+   [BCK2]  M. Bellare, R. Canetti, and H. Krawczyk,
+           "Pseudorandom Functions Revisited: The Cascade Construction",
+           Proceedings of FOCS'96.
+
+   [Dobb]  H. Dobbertin, "The Status of MD5  After a Recent Attack",
+           RSA Labs' CryptoBytes, Vol. 2 No. 2, Summer 1996.
+           http://www.rsa.com/rsalabs/pubs/cryptobytes.html
+
+   [PV]    B. Preneel and P. van Oorschot, "Building fast MACs from hash
+           functions", Advances in Cryptology -- CRYPTO'95 Proceedings,
+           Lecture Notes in Computer Science, Springer-Verlag Vol.963,
+           1995, pp. 1-14.
+
+   [MD5]   Rivest, R., "The MD5 Message-Digest Algorithm",
+           RFC 1321, April 1992.
+
+
+
+Krawczyk, et. al.            Informational                     [Page 10]
+
+RFC 2104                          HMAC                     February 1997
+
+
+   [MM]    Meyer, S. and Matyas, S.M., Cryptography, New York Wiley,
+           1982.
+
+   [RIPEMD] H. Dobbertin, A. Bosselaers, and B. Preneel, "RIPEMD-160: A
+            strengthened version of RIPEMD", Fast Software Encryption,
+            LNCS Vol 1039, pp. 71-82.
+            ftp://ftp.esat.kuleuven.ac.be/pub/COSIC/bosselae/ripemd/.
+
+   [SHA]   NIST, FIPS PUB 180-1: Secure Hash Standard, April 1995.
+
+   [Tsu]   G. Tsudik, "Message authentication with one-way hash
+           functions", In Proceedings of Infocom'92, May 1992.
+           (Also in "Access Control and Policy Enforcement in
+            Internetworks", Ph.D. Dissertation, Computer Science
+            Department, University of Southern California, April 1991.)
+
+   [VW]    P. van Oorschot and M. Wiener, "Parallel Collision
+           Search with Applications to Hash Functions and Discrete
+           Logarithms", Proceedings of the 2nd ACM Conf. Computer and
+           Communications Security, Fairfax, VA, November 1994.
+
+Authors' Addresses
+
+   Hugo Krawczyk
+   IBM T.J. Watson Research Center
+   P.O.Box 704
+   Yorktown Heights, NY 10598
+
+   EMail: hugo at watson.ibm.com
+
+   Mihir Bellare
+   Dept of Computer Science and Engineering
+   Mail Code 0114
+   University of California at San Diego
+   9500 Gilman Drive
+   La Jolla, CA 92093
+
+   EMail: mihir at cs.ucsd.edu
+
+   Ran Canetti
+   IBM T.J. Watson Research Center
+   P.O.Box 704
+   Yorktown Heights, NY 10598
+
+   EMail: canetti at watson.ibm.com
+
+
+
+
+
+
+Krawczyk, et. al.            Informational                     [Page 11]
+

Added: trunk/orca/packages/Digest-MD5-2.07/MD5.pm
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/MD5.pm	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/MD5.pm	Sat Jul 13 18:45:56 2002
@@ -0,0 +1,250 @@
+package Digest::MD5;
+
+use strict;
+use vars qw($VERSION @ISA @EXPORT_OK);
+
+$VERSION = '2.07';  # $Date: 1999/04/03 18:07:49 $
+
+require Exporter;
+*import = \&Exporter::import;
+ at EXPORT_OK = qw(md5 md5_hex md5_base64);
+
+require DynaLoader;
+ at ISA=qw(DynaLoader);
+Digest::MD5->bootstrap($VERSION);
+
+*reset = \&new;
+
+1;
+__END__
+
+=head1 NAME
+
+Digest::MD5 - Perl interface to the MD5 Algorithm
+
+=head1 SYNOPSIS
+
+ # Functional style
+ use Digest::MD5  qw(md5 md5_hex md5_base64);
+
+ $digest = md5($data);
+ $digest = md5_hex($data);
+ $digest = md5_base64($data);
+    
+
+ # OO style
+ use Digest::MD5;
+
+ $ctx = Digest::MD5->new;
+
+ $ctx->add($data);
+ $ctx->addfile(*FILE);
+
+ $digest = $ctx->digest;
+ $digest = $ctx->hexdigest;
+ $digest = $ctx->b64digest;
+
+=head1 DESCRIPTION
+
+The C<Digest::MD5> module allows you to use the RSA Data Security
+Inc. MD5 Message Digest algorithm from within Perl programs.  The
+algorithm takes as input a message of arbitrary length and produces as
+output a 128-bit "fingerprint" or "message digest" of the input.
+
+The C<Digest::MD5> module provide a procedural interface for simple
+use, as well as an object oriented interface that can handle messages
+of arbitrary length and which can read files directly.
+
+A binary digest will be 16 bytes long.  A hex digest will be 32
+characters long.  A base64 digest will be 22 characters long.
+
+=head1 FUNCTIONS
+
+The following functions can be exported from the C<Digest::MD5>
+module.  No functions are exported by default.
+
+=over 4
+
+=item md5($data,...)
+
+This function will concatenate all arguments, calculate the MD5 digest
+of this "message", and return it in binary form.
+
+=item md5_hex($data,...)
+
+Same as md5(), but will return the digest in hexadecimal form.
+
+=item md5_base64($data,...)
+
+Same as md5(), but will return the digest as a base64 encoded string.
+
+=back
+
+=head1 METHODS
+
+The following methods are available:
+
+=over 4
+
+=item $md5 = Digest::MD5->new
+
+The constructor returns a new C<Digest::MD5> object which encapsulate
+the state of the MD5 message-digest algorithm.  You can add data to
+the object and finally ask for the digest.
+
+If called as a instance method (i.e. $md5->new) it will just reset the
+state the object to the state of a newly created object.  No new
+object is created in this case.
+
+=item $md5->reset
+
+This is just an alias for $md5->new.
+
+=item $md5->add($data,...)
+
+The $data provided as argument are appended to the message we
+calculate the digest for.  The return value is the $md5 object itself.
+
+=item $md5->addfile($io_handle)
+
+The $io_handle is read until EOF and the content is appended to the
+message we calculate the digest for.  The return value is the $md5
+object itself.
+
+=item $md5->digest
+
+Return the binary digest for the message.
+
+Note that the C<digest> operation is effectively a destructive,
+read-once operation. Once it has been performed, the C<Digest::MD5>
+object is automatically C<reset> and can be used to calculate another
+digest value.
+
+=item $md5->hexdigest
+
+Same as $md5->digest, but will return the digest in hexadecimal form.
+
+=item $md5->b64digest
+
+Same as $md5->digest, but will return the digest as a base64 encoded
+string.
+
+=back
+
+
+=head1 EXAMPLES
+
+The simplest way to use this library is to import the md5_hex()
+function (or one of its cousins):
+
+    use Digest::MD5 qw(md5_hex);
+    print "Digest is ", md5_hex("foobarbaz"), "\n";
+
+The above example would print out the message
+
+    Digest is 6df23dc03f9b54cc38a0fc1483df6e21
+
+provided that the implementation is working correctly.  The same
+checksum can also be calculated in OO style:
+
+    use Digest::MD5;
+    
+    $md5 = Digest::MD5->new;
+    $md5->add('foo', 'bar');
+    $md5->add('baz');
+    $digest = $md5->digest();
+    
+    print "Digest is ", unpack("H*", $digest), "\n";
+
+With OO style you can break the message arbitrary.  This means that we
+are no longer limited to have space for the whole message in memory.
+We can handle messages of any size.
+
+This is useful when calculating checksum for files:
+
+    use Digest::MD5;
+
+    my $file = shift || "/etc/passwd";
+    open(FILE, $file) or die "Can't open '$file': $!";
+    binmode(FILE);
+
+    $md5 = Digest::MD5->new;
+    while (<FILE>) {
+        $md5->add($_);
+    }
+    close(FILE);
+    print $md5->b64digest, " $file\n";
+
+Or we can use the builtin addfile method to read the file much faster:
+
+    use Digest::MD5;
+
+    my $file = shift || "/etc/passwd";
+    open(FILE, $file) or die "Can't open '$file': $!";
+    binmode(FILE);
+
+    print Digest::MD5->new->addfile(*FILE)->hexdigest, " $file\n";
+
+=head1 SEE ALSO
+
+L<Digest>,
+L<Digest::MD2>,
+L<Digest::SHA1>,
+L<Digest::HMAC>
+
+L<md5sum(1)>
+
+RFC 1321
+
+=head1 COPYRIGHT
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+ Copyright 1998-1999 Gisle Aas.
+ Copyright 1995-1996 Neil Winton.
+ Copyright 1991-1992 RSA Data Security, Inc.
+
+The MD5 algorithm is defined in RFC 1321. The basic C code
+implementing the algorithm is derived from that in the RFC and is
+covered by the following copyright:
+
+=over 4
+
+=item
+
+Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+
+=back
+
+This copyright does not prohibit distribution of any version of Perl
+containing this extension under the terms of the GNU or Artistic
+licenses.
+
+=head1 AUTHORS
+
+The original MD5 interface was written by Neil Winton
+(C<N.Winton at axion.bt.co.uk>).
+
+This release was made by Gisle Aas <gisle at aas.no>
+
+=cut

Added: trunk/orca/packages/Digest-MD5-2.07/MD2/typemap
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/MD2/typemap	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/MD2/typemap	Sat Jul 13 18:45:56 2002
@@ -0,0 +1,5 @@
+MD2_CTX*	T_MD2_CTX
+
+INPUT
+T_MD2_CTX
+	$var = get_md2_ctx($arg)

Added: trunk/orca/packages/Digest-MD5-2.07/MD2/t/md2.t
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/MD2/t/md2.t	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/MD2/t/md2.t	Sat Jul 13 18:45:56 2002
@@ -0,0 +1,34 @@
+print "1..7\n";
+use strict;
+
+use Digest::MD2 qw(md2 md2_hex);
+my $testno = 0;
+
+# From RFC 1319
+my $TESTS = <<'EOT';
+MD2 ("") = 8350e5a3e24c153df2275c9f80692773
+MD2 ("a") = 32ec01ec4a6dac72c0ab96fb34c0b5d1
+MD2 ("abc") = da853b0d3f88d99b30283a69e6ded6bb
+MD2 ("message digest") = ab4f496bfb2a530b219ff33031fe06b0
+MD2 ("abcdefghijklmnopqrstuvwxyz") = 4e8ddff3650292ab5a4108c3aa47940b
+MD2 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") = da33def2a42df13975352846c30338cd
+MD2 ("12345678901234567890123456789012345678901234567890123456789012345678901234567890") = d5976f79d83d3a0dc9806c3c66f3efd8
+EOT
+
+for (split(/^/, $TESTS)) {
+    die unless /^MD2\s*\(\"([^\"]*)\"\)\s*=\s*(.*)/;
+    my $message = $1;
+    my $hexdigest = $2;
+    my $bindigest = pack("H*", $hexdigest);
+
+    my $failed;
+    $failed++ unless md2($message) eq $bindigest;
+    $failed++ unless md2_hex($message) eq $hexdigest;
+
+    # Test OO interface
+    $failed++ unless Digest::MD2->new->add($message)->digest eq $bindigest;
+    $failed++ unless Digest::MD2->new->add($message)->hexdigest eq $hexdigest;
+
+    print "not " if $failed;
+    print "ok ", ++$testno, "\n";
+}

Added: trunk/orca/packages/Digest-MD5-2.07/MD2/rfc1319.txt
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/MD2/rfc1319.txt	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/MD2/rfc1319.txt	Sat Jul 13 18:45:56 2002
@@ -0,0 +1,955 @@
+
+
+
+
+
+
+Network Working Group                                         B. Kaliski
+Request for Comments: 1319                              RSA Laboratories
+Updates: RFC 1115                                             April 1992
+
+
+                     The MD2 Message-Digest Algorithm
+
+Status of this Memo
+
+   This memo provides information for the Internet community.  It does
+   not specify an Internet standard.  Distribution of this memo is
+   unlimited.
+
+Acknowlegements
+
+   The description of MD2 is based on material prepared by John Linn and
+   Ron Rivest.  Their permission to incorporate that material is greatly
+   appreciated.
+
+Table of Contents
+
+   1. Executive Summary                                                1
+   2. Terminology and Notation                                         2
+   3. MD2 Algorithm Description                                        2
+   4. Summary                                                          4
+   References                                                          5
+   APPENDIX A - Reference Implementation                               5
+   Security Considerations                                            17
+   Author's Address                                                   17
+
+1. Executive Summary
+
+   This document describes the MD2 message-digest algorithm. The
+   algorithm takes as input a message of arbitrary length and produces
+   as output a 128-bit "fingerprint" or "message digest" of the input.
+   It is conjectured that it is computationally infeasible to produce
+   two messages having the same message digest, or to produce any
+   message having a given prespecified target message digest. The MD2
+   algorithm is intended for digital signature applications, where a
+   large file must be "compressed" in a secure manner before being
+   signed with a private (secret) key under a public-key cryptosystem
+   such as RSA.
+
+   License to use MD2 is granted for non-commerical Internet Privacy-
+   Enhanced Mail [1-3].
+
+   This document is an update to the August 1989 RFC 1115 [3], which
+   also gives a reference implementation of MD2. The main differences
+
+
+
+Kaliski                                                         [Page 1]
+
+RFC 1319              MD2 Message-Digest Algorithm            April 1992
+
+
+   are that a textual description of MD2 is included, and that the
+   reference implementation of MD2 is more portable.
+
+   For OSI-based applications, MD2's object identifier is
+
+   md2 OBJECT IDENTIFIER ::=
+   iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 2}
+
+   In the X.509 type AlgorithmIdentifier [4], the parameters for MD2
+   should have type NULL.
+
+2. Terminology and Notation
+
+   In this document, a "byte" is an eight-bit quantity.
+
+   Let x_i denote "x sub i". If the subscript is an expression, we
+   surround it in braces, as in x_{i+1}. Similarly, we use ^ for
+   superscripts (exponentiation), so that x^i denotes x to the i-th
+   power.
+
+   Let X xor Y denote the bit-wise XOR of X and Y.
+
+3. MD2 Algorithm Description
+
+   We begin by supposing that we have a b-byte message as input, and
+   that we wish to find its message digest. Here b is an arbitrary
+   nonnegative integer; b may be zero, and it may be arbitrarily large.
+   We imagine the bytes of the message written down as follows:
+
+                   m_0 m_1 ... m_{b-1}
+
+   The following five steps are performed to compute the message digest
+   of the message.
+
+3.1 Step 1. Append Padding Bytes
+
+   The message is "padded" (extended) so that its length (in bytes) is
+   congruent to 0, modulo 16. That is, the message is extended so that
+   it is a multiple of 16 bytes long. Padding is always performed, even
+   if the length of the message is already congruent to 0, modulo 16.
+
+   Padding is performed as follows: "i" bytes of value "i" are appended
+   to the message so that the length in bytes of the padded message
+   becomes congruent to 0, modulo 16. At least one byte and at most 16
+   16 bytes are appended.
+
+   At this point the resulting message (after padding with bytes) has a
+   length that is an exact multiple of 16 bytes. Let M[0 ... N-1] denote
+
+
+
+Kaliski                                                         [Page 2]
+
+RFC 1319              MD2 Message-Digest Algorithm            April 1992
+
+
+   the bytes of the resulting message, where N is a multiple of 16.
+
+3.2 Step 2. Append Checksum
+
+   A 16-byte checksum of the message is appended to the result of the
+   previous step.
+
+   This step uses a 256-byte "random" permutation constructed from the
+   digits of pi. Let S[i] denote the i-th element of this table. The
+   table is given in the appendix.
+
+   Do the following:
+
+      /* Clear checksum. */
+      For i = 0 to 15 do:
+         Set C[i] to 0.
+      end /* of loop on i */
+
+      Set L to 0.
+
+      /* Process each 16-word block. */
+      For i = 0 to N/16-1 do
+
+         /* Checksum block i. */
+         For j = 0 to 15 do
+            Set c to M[i*16+j].
+            Set C[j] to S[c xor L].
+            Set L to C[j].
+          end /* of loop on j */
+       end /* of loop on i */
+
+   The 16-byte checksum C[0 ... 15] is appended to the message. Let M[0
+   with checksum), where N' = N + 16.
+
+3.3 Step 3. Initialize MD Buffer
+
+   A 48-byte buffer X is used to compute the message digest. The buffer
+   is initialized to zero.
+
+
+
+
+
+
+
+
+
+
+
+
+
+Kaliski                                                         [Page 3]
+
+RFC 1319              MD2 Message-Digest Algorithm            April 1992
+
+
+3.4 Step 4. Process Message in 16-Byte Blocks
+
+   This step uses the same 256-byte permutation S as step 2 does.
+
+   Do the following:
+
+      /* Process each 16-word block. */
+      For i = 0 to N'/16-1 do
+
+         /* Copy block i into X. */
+         For j = 0 to 15 do
+            Set X[16+j] to M[i*16+j].
+            Set X[32+j] to (X[16+j] xor X[j]).
+          end /* of loop on j */
+
+         Set t to 0.
+
+         /* Do 18 rounds. */
+         For j = 0 to 17 do
+
+            /* Round j. */
+            For k = 0 to 47 do
+               Set t and X[k] to (X[k] xor S[t]).
+            end /* of loop on k */
+
+            Set t to (t+j) modulo 256.
+         end /* of loop on j */
+
+      end /* of loop on i */
+
+3.5 Step 5. Output
+
+   The message digest produced as output is X[0 ... 15]. That is, we
+   begin with X[0], and end with X[15].
+
+   This completes the description of MD2. A reference implementation in
+   C is given in the appendix.
+
+4. Summary
+
+   The MD2 message-digest algorithm is simple to implement, and provides
+   a "fingerprint" or message digest of a message of arbitrary length.
+   It is conjectured that the difficulty of coming up with two messages
+   having the same message digest is on the order of 2^64 operations,
+   and that the difficulty of coming up with any message having a given
+   message digest is on the order of 2^128 operations. The MD2 algorithm
+   has been carefully scrutinized for weaknesses. It is, however, a
+   relatively new algorithm and further security analysis is of course
+
+
+
+Kaliski                                                         [Page 4]
+
+RFC 1319              MD2 Message-Digest Algorithm            April 1992
+
+
+   justified, as is the case with any new proposal of this sort.
+
+References
+
+   [1] Linn, J., "Privacy Enhancement for Internet Electronic Mail: Part
+       I -- Message Encipherment and Authentication Procedures", RFC
+       1113, DEC,  IAB Privacy Task Force, August 1989.
+
+   [2] Kent, S., and J. Linn, "Privacy Enhancement for Internet
+       Electronic Mail: Part II -- Certificate-Based Key Management",
+       RFC 1114, BBNCC, DEC, IAB Privacy Task Force, August 1989.
+
+   [3] Linn, J., "Privacy Enhancement for Internet Electronic Mail: Part
+       III -- Algorithms, Modes, and Identifiers", RFC 1115 DEC, IAB
+       Privacy Task Force, August 1989.
+
+   [4] CCITT Recommendation X.509 (1988), "The Directory -
+       Authentication Framework".
+
+APPENDIX A - Reference Implementation
+
+   This appendix contains the following files taken from RSAREF: A
+   Cryptographic Toolkit for Privacy-Enhanced Mail:
+
+     global.h -- global header file
+
+     md2.h -- header file for MD2
+
+     md2c.c -- source code for MD2
+
+For more information on RSAREF, send email to <rsaref at rsa.com>.
+
+The appendix also includes the following file:
+
+     mddriver.c -- test driver for MD2, MD4 and MD5
+
+The driver compiles for MD5 by default but can compile for MD2 or MD4 if
+the symbol MD is defined on the C compiler command line as 2 or 4.
+
+A.1 global.h
+
+/* GLOBAL.H - RSAREF types and constants
+ */
+
+/* PROTOTYPES should be set to one if and only if the compiler supports
+     function argument prototyping.
+   The following makes PROTOTYPES default to 0 if it has not already
+     been defined with C compiler flags.
+
+
+
+Kaliski                                                         [Page 5]
+
+RFC 1319              MD2 Message-Digest Algorithm            April 1992
+
+
+ */
+#ifndef PROTOTYPES
+#define PROTOTYPES 0
+#endif
+
+/* POINTER defines a generic pointer type */
+typedef unsigned char *POINTER;
+
+/* UINT2 defines a two byte word */
+typedef unsigned short int UINT2;
+
+/* UINT4 defines a four byte word */
+typedef unsigned long int UINT4;
+
+/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
+   If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
+     returns an empty list.
+ */
+#if PROTOTYPES
+#define PROTO_LIST(list) list
+#else
+#define PROTO_LIST(list) ()
+#endif
+
+A.2 md2.h
+
+/* MD2.H - header file for MD2C.C
+ */
+
+/* Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
+   rights reserved.
+
+   License to copy and use this software is granted for
+   non-commercial Internet Privacy-Enhanced Mail provided that it is
+   identified as the "RSA Data Security, Inc. MD2 Message Digest
+   Algorithm" in all material mentioning or referencing this software
+   or this function.
+
+   RSA Data Security, Inc. makes no representations concerning either
+   the merchantability of this software or the suitability of this
+   software for any particular purpose. It is provided "as is"
+   without express or implied warranty of any kind.
+
+   These notices must be retained in any copies of any part of this
+   documentation and/or software.
+ */
+
+
+
+
+
+Kaliski                                                         [Page 6]
+
+RFC 1319              MD2 Message-Digest Algorithm            April 1992
+
+
+typedef struct {
+  unsigned char state[16];                                 /* state */
+  unsigned char checksum[16];                           /* checksum */
+  unsigned int count;                 /* number of bytes, modulo 16 */
+  unsigned char buffer[16];                         /* input buffer */
+} MD2_CTX;
+
+void MD2Init PROTO_LIST ((MD2_CTX *));
+void MD2Update PROTO_LIST
+  ((MD2_CTX *, unsigned char *, unsigned int));
+void MD2Final PROTO_LIST ((unsigned char [16], MD2_CTX *));
+
+A.3 md2c.c
+
+/* MD2C.C - RSA Data Security, Inc., MD2 message-digest algorithm
+ */
+
+/* Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
+   rights reserved.
+
+   License to copy and use this software is granted for
+   non-commercial Internet Privacy-Enhanced Mail provided that it is
+   identified as the "RSA Data Security, Inc. MD2 Message Digest
+   Algorithm" in all material mentioning or referencing this software
+   or this function.
+
+   RSA Data Security, Inc. makes no representations concerning either
+   the merchantability of this software or the suitability of this
+   software for any particular purpose. It is provided "as is"
+   without express or implied warranty of any kind.
+
+   These notices must be retained in any copies of any part of this
+   documentation and/or software.
+ */
+
+#include "global.h"
+#include "md2.h"
+
+static void MD2Transform PROTO_LIST
+  ((unsigned char [16], unsigned char [16], unsigned char [16]));
+static void MD2_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
+static void MD2_memset PROTO_LIST ((POINTER, int, unsigned int));
+
+/* Permutation of 0..255 constructed from the digits of pi. It gives a
+   "random" nonlinear byte substitution operation.
+ */
+static unsigned char PI_SUBST[256] = {
+  41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
+
+
+
+Kaliski                                                         [Page 7]
+
+RFC 1319              MD2 Message-Digest Algorithm            April 1992
+
+
+  19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
+  76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
+  138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
+  245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
+  148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
+  39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
+  181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
+  150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
+  112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
+  96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
+  85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
+  234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
+  129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
+  8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
+  203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
+  166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
+  31, 26, 219, 153, 141, 51, 159, 17, 131, 20
+};
+
+static unsigned char *PADDING[] = {
+  (unsigned char *)"",
+  (unsigned char *)"\001",
+  (unsigned char *)"\002\002",
+  (unsigned char *)"\003\003\003",
+  (unsigned char *)"\004\004\004\004",
+  (unsigned char *)"\005\005\005\005\005",
+  (unsigned char *)"\006\006\006\006\006\006",
+  (unsigned char *)"\007\007\007\007\007\007\007",
+  (unsigned char *)"\010\010\010\010\010\010\010\010",
+  (unsigned char *)"\011\011\011\011\011\011\011\011\011",
+  (unsigned char *)"\012\012\012\012\012\012\012\012\012\012",
+  (unsigned char *)"\013\013\013\013\013\013\013\013\013\013\013",
+  (unsigned char *)"\014\014\014\014\014\014\014\014\014\014\014\014",
+  (unsigned char *)
+    "\015\015\015\015\015\015\015\015\015\015\015\015\015",
+  (unsigned char *)
+    "\016\016\016\016\016\016\016\016\016\016\016\016\016\016",
+  (unsigned char *)
+    "\017\017\017\017\017\017\017\017\017\017\017\017\017\017\017",
+  (unsigned char *)
+    "\020\020\020\020\020\020\020\020\020\020\020\020\020\020\020\020"
+};
+
+/* MD2 initialization. Begins an MD2 operation, writing a new context.
+ */
+void MD2Init (context)
+MD2_CTX *context;                                        /* context */
+{
+
+
+
+Kaliski                                                         [Page 8]
+
+RFC 1319              MD2 Message-Digest Algorithm            April 1992
+
+
+  context->count = 0;
+  MD2_memset ((POINTER)context->state, 0, sizeof (context->state));
+  MD2_memset
+    ((POINTER)context->checksum, 0, sizeof (context->checksum));
+}
+
+/* MD2 block update operation. Continues an MD2 message-digest
+     operation, processing another message block, and updating the
+     context.
+ */
+void MD2Update (context, input, inputLen)
+MD2_CTX *context;                                        /* context */
+unsigned char *input;                                /* input block */
+unsigned int inputLen;                     /* length of input block */
+{
+  unsigned int i, index, partLen;
+
+  /* Update number of bytes mod 16 */
+  index = context->count;
+  context->count = (index + inputLen) & 0xf;
+
+  partLen = 16 - index;
+
+  /* Transform as many times as possible.
+    */
+  if (inputLen >= partLen) {
+    MD2_memcpy
+      ((POINTER)&context->buffer[index], (POINTER)input, partLen);
+    MD2Transform (context->state, context->checksum, context->buffer);
+
+    for (i = partLen; i + 15 < inputLen; i += 16)
+      MD2Transform (context->state, context->checksum, &input[i]);
+
+    index = 0;
+  }
+  else
+    i = 0;
+
+  /* Buffer remaining input */
+  MD2_memcpy
+    ((POINTER)&context->buffer[index], (POINTER)&input[i],
+     inputLen-i);
+}
+
+/* MD2 finalization. Ends an MD2 message-digest operation, writing the
+     message digest and zeroizing the context.
+ */
+void MD2Final (digest, context)
+
+
+
+Kaliski                                                         [Page 9]
+
+RFC 1319              MD2 Message-Digest Algorithm            April 1992
+
+
+unsigned char digest[16];                         /* message digest */
+MD2_CTX *context;                                        /* context */
+{
+  unsigned int index, padLen;
+
+  /* Pad out to multiple of 16.
+   */
+  index = context->count;
+  padLen = 16 - index;
+  MD2Update (context, PADDING[padLen], padLen);
+
+  /* Extend with checksum */
+  MD2Update (context, context->checksum, 16);
+
+  /* Store state in digest */
+  MD2_memcpy ((POINTER)digest, (POINTER)context->state, 16);
+
+  /* Zeroize sensitive information.
+   */
+  MD2_memset ((POINTER)context, 0, sizeof (*context));
+}
+
+/* MD2 basic transformation. Transforms state and updates checksum
+     based on block.
+ */
+static void MD2Transform (state, checksum, block)
+unsigned char state[16];
+unsigned char checksum[16];
+unsigned char block[16];
+{
+  unsigned int i, j, t;
+  unsigned char x[48];
+
+  /* Form encryption block from state, block, state ^ block.
+   */
+  MD2_memcpy ((POINTER)x, (POINTER)state, 16);
+  MD2_memcpy ((POINTER)x+16, (POINTER)block, 16);
+  for (i = 0; i < 16; i++)
+    x[i+32] = state[i] ^ block[i];
+
+  /* Encrypt block (18 rounds).
+   */
+  t = 0;
+  for (i = 0; i < 18; i++) {
+    for (j = 0; j < 48; j++)
+      t = x[j] ^= PI_SUBST[t];
+    t = (t + i) & 0xff;
+  }
+
+
+
+Kaliski                                                        [Page 10]
+
+RFC 1319              MD2 Message-Digest Algorithm            April 1992
+
+
+  /* Save new state */
+  MD2_memcpy ((POINTER)state, (POINTER)x, 16);
+
+  /* Update checksum.
+   */
+  t = checksum[15];
+  for (i = 0; i < 16; i++)
+    t = checksum[i] ^= PI_SUBST[block[i] ^ t];
+
+  /* Zeroize sensitive information.
+   */
+  MD2_memset ((POINTER)x, 0, sizeof (x));
+}
+
+/* Note: Replace "for loop" with standard memcpy if possible.
+ */
+static void MD2_memcpy (output, input, len)
+POINTER output;
+POINTER input;
+unsigned int len;
+{
+  unsigned int i;
+
+  for (i = 0; i < len; i++)
+    output[i] = input[i];
+}
+
+/* Note: Replace "for loop" with standard memset if possible.
+ */
+static void MD2_memset (output, value, len)
+POINTER output;
+int value;
+unsigned int len;
+{
+  unsigned int i;
+
+  for (i = 0; i < len; i++)
+    ((char *)output)[i] = (char)value;
+}
+
+A.4 mddriver.c
+
+/* MDDRIVER.C - test driver for MD2, MD4 and MD5
+ */
+
+/* Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
+   rights reserved.
+
+
+
+
+Kaliski                                                        [Page 11]
+
+RFC 1319              MD2 Message-Digest Algorithm            April 1992
+
+
+   RSA Data Security, Inc. makes no representations concerning either
+   the merchantability of this software or the suitability of this
+   software for any particular purpose. It is provided "as is"
+   without express or implied warranty of any kind.
+
+   These notices must be retained in any copies of any part of this
+   documentation and/or software.
+ */
+
+/* The following makes MD default to MD5 if it has not already been
+     defined with C compiler flags.
+ */
+#ifndef MD
+#define MD MD5
+#endif
+
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#include "global.h"
+#if MD == 2
+#include "md2.h"
+#endif
+#if MD == 4
+#include "md4.h"
+#endif
+#if MD == 5
+#include "md5.h"
+#endif
+
+/* Length of test block, number of test blocks.
+ */
+#define TEST_BLOCK_LEN 1000
+#define TEST_BLOCK_COUNT 1000
+
+static void MDString PROTO_LIST ((char *));
+static void MDTimeTrial PROTO_LIST ((void));
+static void MDTestSuite PROTO_LIST ((void));
+static void MDFile PROTO_LIST ((char *));
+static void MDFilter PROTO_LIST ((void));
+static void MDPrint PROTO_LIST ((unsigned char [16]));
+
+#if MD == 2
+#define MD_CTX MD2_CTX
+#define MDInit MD2Init
+#define MDUpdate MD2Update
+#define MDFinal MD2Final
+#endif
+
+
+
+Kaliski                                                        [Page 12]
+
+RFC 1319              MD2 Message-Digest Algorithm            April 1992
+
+
+#if MD == 4
+#define MD_CTX MD4_CTX
+#define MDInit MD4Init
+#define MDUpdate MD4Update
+#define MDFinal MD4Final
+#endif
+#if MD == 5
+#define MD_CTX MD5_CTX
+#define MDInit MD5Init
+#define MDUpdate MD5Update
+#define MDFinal MD5Final
+#endif
+
+/* Main driver.
+
+   Arguments (may be any combination):
+     -sstring - digests string
+     -t       - runs time trial
+     -x       - runs test script
+     filename - digests file
+     (none)   - digests standard input
+ */
+int main (argc, argv)
+int argc;
+char *argv[];
+{
+  int i;
+
+  if (argc > 1)
+    for (i = 1; i < argc; i++)
+      if (argv[i][0] == '-' && argv[i][1] == 's')
+        MDString (argv[i] + 2);
+      else if (strcmp (argv[i], "-t") == 0)
+        MDTimeTrial ();
+      else if (strcmp (argv[i], "-x") == 0)
+        MDTestSuite ();
+      else
+        MDFile (argv[i]);
+  else
+    MDFilter ();
+
+  return (0);
+}
+
+/* Digests a string and prints the result.
+ */
+static void MDString (string)
+char *string;
+
+
+
+Kaliski                                                        [Page 13]
+
+RFC 1319              MD2 Message-Digest Algorithm            April 1992
+
+
+{
+  MD_CTX context;
+  unsigned char digest[16];
+  unsigned int len = strlen (string);
+
+  MDInit (&context);
+  MDUpdate (&context, string, len);
+  MDFinal (digest, &context);
+
+  printf ("MD%d (\"%s\") = ", MD, string);
+  MDPrint (digest);
+  printf ("\n");
+}
+
+/* Measures the time to digest TEST_BLOCK_COUNT TEST_BLOCK_LEN-byte
+     blocks.
+ */
+static void MDTimeTrial ()
+{
+  MD_CTX context;
+  time_t endTime, startTime;
+  unsigned char block[TEST_BLOCK_LEN], digest[16];
+  unsigned int i;
+
+  printf
+    ("MD%d time trial. Digesting %d %d-byte blocks ...", MD,
+     TEST_BLOCK_LEN, TEST_BLOCK_COUNT);
+
+  /* Initialize block */
+  for (i = 0; i < TEST_BLOCK_LEN; i++)
+    block[i] = (unsigned char)(i & 0xff);
+
+  /* Start timer */
+  time (&startTime);
+
+  /* Digest blocks */
+  MDInit (&context);
+  for (i = 0; i < TEST_BLOCK_COUNT; i++)
+    MDUpdate (&context, block, TEST_BLOCK_LEN);
+  MDFinal (digest, &context);
+
+  /* Stop timer */
+  time (&endTime);
+
+  printf (" done\n");
+  printf ("Digest = ");
+  MDPrint (digest);
+  printf ("\nTime = %ld seconds\n", (long)(endTime-startTime));
+
+
+
+Kaliski                                                        [Page 14]
+
+RFC 1319              MD2 Message-Digest Algorithm            April 1992
+
+
+  printf
+    ("Speed = %ld bytes/second\n",
+     (long)TEST_BLOCK_LEN * (long)TEST_BLOCK_COUNT/(endTime-startTime));
+}
+/* Digests a reference suite of strings and prints the results.
+ */
+static void MDTestSuite ()
+{
+  printf ("MD%d test suite:\n", MD);
+
+  MDString ("");
+  MDString ("a");
+  MDString ("abc");
+  MDString ("message digest");
+  MDString ("abcdefghijklmnopqrstuvwxyz");
+  MDString
+    ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
+  MDString
+    ("1234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890");
+}
+
+/* Digests a file and prints the result.
+ */
+static void MDFile (filename)
+char *filename;
+{
+  FILE *file;
+  MD_CTX context;
+  int len;
+  unsigned char buffer[1024], digest[16];
+
+  if ((file = fopen (filename, "rb")) == NULL)
+    printf ("%s can't be opened\n", filename);
+
+  else {
+    MDInit (&context);
+    while (len = fread (buffer, 1, 1024, file))
+      MDUpdate (&context, buffer, len);
+    MDFinal (digest, &context);
+
+    fclose (file);
+
+    printf ("MD%d (%s) = ", MD, filename);
+    MDPrint (digest);
+    printf ("\n");
+  }
+}
+
+
+
+Kaliski                                                        [Page 15]
+
+RFC 1319              MD2 Message-Digest Algorithm            April 1992
+
+
+/* Digests the standard input and prints the result.
+ */
+static void MDFilter ()
+{
+  MD_CTX context;
+  int len;
+  unsigned char buffer[16], digest[16];
+
+  MDInit (&context);
+  while (len = fread (buffer, 1, 16, stdin))
+    MDUpdate (&context, buffer, len);
+  MDFinal (digest, &context);
+
+  MDPrint (digest);
+  printf ("\n");
+}
+
+/* Prints a message digest in hexadecimal.
+ */
+static void MDPrint (digest)
+unsigned char digest[16];
+{
+  unsigned int i;
+
+  for (i = 0; i < 16; i++)
+    printf ("%02x", digest[i]);
+}
+
+A.5 Test suite
+
+   The MD2 test suite (driver option "-x") should print the following
+   results:
+
+MD2 test suite:
+MD2 ("") = 8350e5a3e24c153df2275c9f80692773
+MD2 ("a") = 32ec01ec4a6dac72c0ab96fb34c0b5d1
+MD2 ("abc") = da853b0d3f88d99b30283a69e6ded6bb
+MD2 ("message digest") = ab4f496bfb2a530b219ff33031fe06b0
+MD2 ("abcdefghijklmnopqrstuvwxyz") = 4e8ddff3650292ab5a4108c3aa47940b
+MD2 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") =
+da33def2a42df13975352846c30338cd
+MD2 ("123456789012345678901234567890123456789012345678901234567890123456
+78901234567890") = d5976f79d83d3a0dc9806c3c66f3efd8
+
+
+
+
+
+
+
+
+Kaliski                                                        [Page 16]
+
+RFC 1319              MD2 Message-Digest Algorithm            April 1992
+
+
+Security Considerations
+
+   The level of security discussed in this memo is considered to be
+   sufficient for implementing very high security hybrid digital
+   signature schemes based on MD2 and a public-key cryptosystem.
+
+Author's Address
+
+   Burton S. Kaliski Jr.
+   RSA Laboratories (a division of RSA Data Security, Inc.)
+   10 Twin Dolphin Drive
+   Redwood City, CA  94065
+
+   Phone: (415) 595-8782
+   FAX: (415) 595-4126
+   EMail: burt at rsa.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Kaliski                                                        [Page 17]
+

Added: trunk/orca/packages/Digest-MD5-2.07/MD2/Makefile.PL
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/MD2/Makefile.PL	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/MD2/Makefile.PL	Sat Jul 13 18:45:57 2002
@@ -0,0 +1,8 @@
+require 5.004;
+use ExtUtils::MakeMaker;
+
+WriteMakefile(
+    'NAME'	   => 'Digest::MD2',
+    'VERSION_FROM' => 'MD2.pm',
+    'dist'         => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', },
+);

Added: trunk/orca/packages/Digest-MD5-2.07/MD2/MD2.xs
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/MD2/MD2.xs	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/MD2/MD2.xs	Sat Jul 13 18:45:57 2002
@@ -0,0 +1,366 @@
+/* $Id: MD2.xs,v 1.8 1999/03/05 21:13:03 gisle Exp $ */
+
+/* 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the same terms as Perl itself.
+ * 
+ *  Copyright 1998 Gisle Aas.
+ *  Copyright 1990-1992 RSA Data Security, Inc.
+ *
+ * This code is derived from the reference implementation in RFC 1231
+ * which comes with this message:
+ *
+ * Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
+ * rights reserved.
+ *
+ * License to copy and use this software is granted for
+ * non-commercial Internet Privacy-Enhanced Mail provided that it is
+ * identified as the "RSA Data Security, Inc. MD2 Message Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software for any particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+#ifdef __cplusplus
+}
+#endif
+
+typedef struct {
+  unsigned char state[16];                                 /* state */
+  unsigned char checksum[16];                           /* checksum */
+  unsigned int count;                 /* number of bytes, modulo 16 */
+  unsigned char buffer[16];                         /* input buffer */
+} MD2_CTX;
+
+
+/* Permutation of 0..255 constructed from the digits of pi. It gives a
+   "random" nonlinear byte substitution operation.
+ */
+static U8 PI_SUBST[256] = {
+  41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
+  19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
+  76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
+  138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
+  245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
+  148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
+  39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
+  181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
+  150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
+  112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
+  96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
+  85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
+  234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
+  129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
+  8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
+  203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
+  166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
+  31, 26, 219, 153, 141, 51, 159, 17, 131, 20
+};
+
+static U8 *PADDING[] = {
+  (U8 *)"",
+  (U8 *)"\001",
+  (U8 *)"\002\002",
+  (U8 *)"\003\003\003",
+  (U8 *)"\004\004\004\004",
+  (U8 *)"\005\005\005\005\005",
+  (U8 *)"\006\006\006\006\006\006",
+  (U8 *)"\007\007\007\007\007\007\007",
+  (U8 *)"\010\010\010\010\010\010\010\010",
+  (U8 *)"\011\011\011\011\011\011\011\011\011",
+  (U8 *)"\012\012\012\012\012\012\012\012\012\012",
+  (U8 *)"\013\013\013\013\013\013\013\013\013\013\013",
+  (U8 *)"\014\014\014\014\014\014\014\014\014\014\014\014",
+  (U8 *)"\015\015\015\015\015\015\015\015\015\015\015\015\015",
+  (U8 *)"\016\016\016\016\016\016\016\016\016\016\016\016\016\016",
+  (U8 *)"\017\017\017\017\017\017\017\017\017\017\017\017\017\017\017",
+  (U8 *)"\020\020\020\020\020\020\020\020\020\020\020\020\020\020\020\020"
+};
+
+
+static void
+MD2Init(MD2_CTX* context)
+{
+    Zero(context, 1, MD2_CTX);
+    context->count = 0;
+}
+
+
+static void
+MD2Transform (U8* state, U8* checksum, U8* block)
+{
+    unsigned int i, j, t;
+    U8 x[48];
+
+    /* Form encryption block from state, block, state ^ block.
+     */
+    Copy(state, x, 16, char);
+    Copy(block, x+16, 16, char);
+
+    for (i = 0; i < 16; i++)
+	x[i+32] = state[i] ^ block[i];
+
+    /* Encrypt block (18 rounds).
+     */
+    t = 0;
+    for (i = 0; i < 18; i++) {
+	for (j = 0; j < 48; j++)
+	    t = x[j] ^= PI_SUBST[t];
+	t = (t + i) & 0xff;
+    }
+
+    Copy(x, state, 16, char);     /* Save new state */
+
+    /* Update checksum.
+     */
+    t = checksum[15];
+    for (i = 0; i < 16; i++)
+	t = checksum[i] ^= PI_SUBST[block[i] ^ t];
+
+    Zero(x, 1, x);     /* Zeroize sensitive information. */
+}
+
+
+static void
+MD2Update (MD2_CTX* context, U8 *input, STRLEN inputLen)
+{
+    unsigned int i, index, partLen;
+
+    /* Update number of bytes mod 16 */
+    index = context->count;
+    context->count = (index + inputLen) & 0xf;
+
+    partLen = 16 - index;
+
+    /* Transform as many times as possible.
+     */
+    if (inputLen >= partLen) {
+	Copy(input, context->buffer+index, partLen, char);
+	MD2Transform (context->state, context->checksum, context->buffer);
+
+	for (i = partLen; i + 15 < inputLen; i += 16)
+	    MD2Transform (context->state, context->checksum, &input[i]);
+
+	index = 0;
+    }
+    else
+	i = 0;
+
+    /* Buffer remaining input */
+    Copy(input+i, context->buffer + index, inputLen-i, char);
+}
+
+
+static void
+MD2Final (U8* digest, MD2_CTX *context)
+{
+    unsigned int index, padLen;
+
+    /* Pad out to multiple of 16 */
+    index = context->count;
+    padLen = 16 - index;
+    MD2Update (context, PADDING[padLen], padLen);
+
+    /* Extend with checksum */
+    MD2Update (context, context->checksum, 16);
+
+    Copy(context->state, digest, 16, char);      /* Store state in digest */
+    Zero(context, 1, MD2_CTX);          /* Zeroize sensitive information. */
+}
+
+/*----------------------------------------------------------------*/
+
+static MD2_CTX* get_md2_ctx(SV* sv)
+{
+    if (sv_derived_from(sv, "Digest::MD2"))
+	return (MD2_CTX*)SvIV(SvRV(sv));
+    croak("Not a reference to a Digest::MD2 object");
+    return (MD2_CTX*)0; /* some compilers insist on a return value */
+}
+
+
+static char* hex_16(const unsigned char* from, char* to)
+{
+    static char *hexdigits = "0123456789abcdef";
+    const unsigned char *end = from + 16;
+    char *d = to;
+
+    while (from < end) {
+	*d++ = hexdigits[(*from >> 4)];
+	*d++ = hexdigits[(*from & 0x0F)];
+	from++;
+    }
+    *d = '\0';
+    return to;
+}
+
+static char* base64_16(const unsigned char* from, char* to)
+{
+    static char* base64 =
+	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+    const unsigned char *end = from + 16;
+    unsigned char c1, c2, c3;
+    char *d = to;
+
+    while (1) {
+	c1 = *from++;
+	*d++ = base64[c1>>2];
+	if (from == end) {
+	    *d++ = base64[(c1 & 0x3) << 4];
+	    break;
+	}
+	c2 = *from++;
+	c3 = *from++;
+	*d++ = base64[((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4)];
+	*d++ = base64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
+	*d++ = base64[c3 & 0x3F];
+    }
+    *d = '\0';
+    return to;
+}
+
+/* Formats */
+#define F_BIN 0
+#define F_HEX 1
+#define F_B64 2
+
+static SV* make_mortal_sv(const unsigned char *src, int type)
+{
+    STRLEN len;
+    char result[33];
+    char *ret;
+    
+    switch (type) {
+    case F_BIN:
+	ret = (char*)src;
+	len = 16;
+	break;
+    case F_HEX:
+	ret = hex_16(src, result);
+	len = 32;
+	break;
+    case F_B64:
+	ret = base64_16(src, result);
+	len = 22;
+	break;
+    default:
+	croak("Bad convertion type (%d)", type);
+	break;
+    }
+    return sv_2mortal(newSVpv(ret,len));
+}
+
+
+/********************************************************************/
+
+typedef PerlIO* InputStream;
+
+MODULE = Digest::MD2		PACKAGE = Digest::MD2
+
+PROTOTYPES: DISABLE
+
+void
+new(xclass)
+	SV* xclass
+    PREINIT:
+	MD2_CTX* context;
+    PPCODE:
+	if (!SvROK(xclass)) {
+	    STRLEN my_na;
+	    char *sclass = SvPV(xclass, my_na);
+	    New(55, context, 1, MD2_CTX);
+	    ST(0) = sv_newmortal();
+	    sv_setref_pv(ST(0), sclass, (void*)context);
+	    SvREADONLY_on(SvRV(ST(0)));
+	} else {
+	    context = get_md2_ctx(xclass);
+	}
+        MD2Init(context);
+	XSRETURN(1);
+
+void
+DESTROY(context)
+	MD2_CTX* context
+    CODE:
+        Safefree(context);
+
+void
+add(self, ...)
+	SV* self
+    PREINIT:
+	MD2_CTX* context = get_md2_ctx(self);
+	int i;
+	unsigned char *data;
+	STRLEN len;
+    PPCODE:
+	for (i = 1; i < items; i++) {
+	    data = (unsigned char *)(SvPV(ST(i), len));
+	    MD2Update(context, data, len);
+	}
+	XSRETURN(1);  /* self */
+
+void
+addfile(self, fh)
+	SV* self
+	InputStream fh
+    PREINIT:
+	MD2_CTX* context = get_md2_ctx(self);
+	unsigned char buffer[4096];
+	int  n;
+    CODE:
+	/* Process blocks until EOF */
+        while ( (n = PerlIO_read(fh, buffer, sizeof(buffer)))) {
+	    MD2Update(context, buffer, n);
+	}
+	XSRETURN(1);  /* self */
+
+void
+digest(context)
+	MD2_CTX* context
+    ALIAS:
+	Digest::MD2::digest    = F_BIN
+	Digest::MD2::hexdigest = F_HEX
+	Digest::MD2::b64digest = F_B64
+    PREINIT:
+	unsigned char digeststr[16];
+    PPCODE:
+        MD2Final(digeststr, context);
+	MD2Init(context);  /* In case it is reused */
+        ST(0) = make_mortal_sv(digeststr, ix);
+        XSRETURN(1);
+
+void
+md2(...)
+    ALIAS:
+	Digest::MD2::md2        = F_BIN
+	Digest::MD2::md2_hex    = F_HEX
+	Digest::MD2::md2_base64 = F_B64
+    PREINIT:
+	MD2_CTX ctx;
+	int i;
+	unsigned char *data;
+        STRLEN len;
+	unsigned char digeststr[16];
+    PPCODE:
+	MD2Init(&ctx);
+	for (i = 0; i < items; i++) {
+	    data = (unsigned char *)(SvPV(ST(i), len));
+	    MD2Update(&ctx, data, len);
+	}
+	MD2Final(digeststr, &ctx);
+        ST(0) = make_mortal_sv(digeststr, ix);
+        XSRETURN(1);

Added: trunk/orca/packages/Digest-MD5-2.07/MD2/MD2.pm
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/MD2/MD2.pm	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/MD2/MD2.pm	Sat Jul 13 18:45:57 2002
@@ -0,0 +1,73 @@
+package Digest::MD2;
+
+use strict;
+use vars qw($VERSION @ISA @EXPORT_OK);
+
+$VERSION = '1.00';  # $Date: 1998/11/04 21:53:42 $
+
+require Exporter;
+*import = \&Exporter::import;
+ at EXPORT_OK = qw(md2 md2_hex md2_base64);
+
+require DynaLoader;
+ at ISA=qw(DynaLoader);
+Digest::MD2->bootstrap($VERSION);
+
+*reset = \&new;
+
+1;
+__END__
+
+=head1 NAME
+
+Digest::MD2 - Perl interface to the MD2 Algorithm
+
+=head1 SYNOPSIS
+
+ # Functional style
+ use Digest::MD2  qw(md2 md2_hex md2_base64);
+
+ $digest = md2($data);
+ $digest = md2_hex($data);
+ $digest = md2_base64($data);
+    
+
+ # OO style
+ use Digest::MD2;
+
+ $ctx = Digest::MD2->new;
+
+ $ctx->add($data);
+ $ctx->addfile(*FILE);
+
+ $digest = $ctx->digest;
+ $digest = $ctx->hexdigest;
+ $digest = $ctx->b64digest;
+
+=head1 DESCRIPTION
+
+The C<Digest::MD2> module allows you to use the RSA Data Security
+Inc. MD2 Message Digest algorithm from within Perl programs.  The
+algorithm takes as input a message of arbitrary length and produces as
+output a 128-bit "fingerprint" or "message digest" of the input.
+
+The C<Digest::MD2> programming interface is identical to the interface
+of C<Digest::MD5>.
+
+=head1 SEE ALSO
+
+L<Digest::MD5>
+
+=head1 COPYRIGHT
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+ Copyright 1998 Gisle Aas.
+ Copyright 1990-1992 RSA Data Security, Inc.
+
+=head1 AUTHOR
+
+Gisle Aas <gisle at aas.no>
+
+=cut

Added: trunk/orca/packages/Digest-MD5-2.07/t/digest.t
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/t/digest.t	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/t/digest.t	Sat Jul 13 18:45:57 2002
@@ -0,0 +1,12 @@
+print "1..3\n";
+
+use Digest;
+
+print "not " unless Digest->MD5->add("abc")->hexdigest eq "900150983cd24fb0d6963f7d28e17f72";
+print "ok 1\n";
+
+print "not " unless Digest->MD5->add("abc")->hexdigest eq "900150983cd24fb0d6963f7d28e17f72";
+print "ok 2\n";
+
+print "not " unless Digest->new("HMAC-MD5" => "Jefe")->add("what do ya want for nothing?")->hexdigest eq "750c783e6ab0b503eaa86e310a5db738";
+print "ok 3\n";

Added: trunk/orca/packages/Digest-MD5-2.07/t/rfc2202.t
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/t/rfc2202.t	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/t/rfc2202.t	Sat Jul 13 18:45:57 2002
@@ -0,0 +1,603 @@
+print "1..14\n";
+
+$test_case = 0;
+$algorithm = "";
+
+while (<DATA>) {
+   next if /^\s+$/;            # blank lines
+   next if /^Cheng & Glenn/;   # page header
+   next if /^RFC 2202/;        # page header
+   chomp;
+   if (/^2\. Test Cases for/ .. /4\. Security Considerations/) {
+	if (/^\d+\. Test Cases for (\S+)/) {
+	    if (defined $key) { save($key, $val); undef($key) }
+	    $algorithm = $1;
+        } elsif (/^(\w+(?:-\w+)*)\s+=\s+(.*)/) {
+            save($key, $val) if defined $key;
+	    $key = $1;
+	    $val = $2;
+	    $test_case = $val if $key eq "test_case";
+        } elsif (/^\s+(.*)/) {
+	    $val .= " $1";
+        } elsif (/^4\. /) {
+	    # ignore
+        } else {
+	    print ">>> $_\n";
+        }
+   }
+}
+close(DATA);
+save($key, $val) if $key;
+
+sub save
+{
+    my($key,$val) = @_;
+    if ($val =~ /^0x(..) repeated (\d+) times$/) {
+	$val = chr(hex($1)) x $2;
+    } elsif ($val =~ s/^0x//) {
+	$val = pack("H*", $val);
+    } elsif ($val =~ s/^\"// && $val =~ s/\"$//) {
+	# we already did it
+    }
+    $case{$algorithm}[$test_case-1]{$key} = $val;
+}
+
+#use Data::Dumper; print Dumper(\%case);
+
+
+$testno = 0;
+
+use Digest::HMAC_MD5 qw(hmac_md5);
+print "\n# HMAC-MD5 tests\n";
+foreach (@{$case{"HMAC-MD5"}}) {
+    $testno++;
+
+    # This is a temporary workaround necessitated by a DEC
+    # compiler bug which breaks the 'x' operator.  See
+    #
+    #  http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/1998-12/msg01720.html
+    #
+    if ($^O eq 'dec_osf' and $] < 5.00503) {
+      require Config;
+      my $temp=\%Config::Config;  # suppress a silly warning
+      if ($testno =~ /^(?:3|4|6|7)$/ and ! $Config::Config{gccversion}) {
+        print "ok $testno # skipping test on this platform\n";
+        next;
+      }
+    }
+
+    #use Data::Dumper; print Dumper($_);
+    warn unless length($_->{key}) == $_->{key_len};
+    warn unless length($_->{data}) == $_->{data_len};
+
+    my $failed;
+    # Test OO interface
+    my $hasher = Digest::HMAC_MD5->new($_->{key});
+    $hasher->add($_->{data});
+    $failed++ unless $hasher->digest eq $_->{digest};
+
+    # Test functional interface
+    $failed++ if hmac_md5($_->{data}, $_->{key}) ne $_->{digest};
+    print "not " if $failed;
+    print "ok $testno\n";
+}
+
+# Digest::SHA1 might fail if the SHA module is not installed
+eval {
+   # use Digest::HMAC_SHA1 qw(hmac_sha1);
+   require Digest::HMAC_SHA1;
+   *hmac_sha1 = \&Digest::HMAC_SHA1::hmac_sha1;
+};
+if ($@) {
+   print "\n# HMAC-SHA-1 tests skipped\n$@\n";
+   for (8..14) { print "ok $_\n"; }
+}
+else {
+
+print "\n# HMAC-SHA-1 tests\n";
+foreach (@{$case{"HMAC-SHA-1"}}) {
+    $testno++;
+    #use Data::Dumper; print Dumper($_);
+    warn unless length($_->{key}) == $_->{key_len};
+    warn unless length($_->{data}) == $_->{data_len};
+
+    my $failed;
+    # Test OO interface
+    my $hasher = Digest::HMAC_SHA1->new($_->{key});
+    $hasher->add($_->{data});
+    $failed++ unless $hasher->digest eq $_->{digest};
+
+    # Test functional interface
+    $failed++ if hmac_sha1($_->{data}, $_->{key}) ne $_->{digest};
+
+    print "not " if $failed;
+    print "ok $testno\n";
+}
+}
+
+__END__
+
+
+Network Working Group                                          P. Cheng
+Request for Comments: 2202                                          IBM
+Category: Informational                                        R. Glenn
+                                                                   NIST
+                                                         September 1997
+
+
+                 Test Cases for HMAC-MD5 and HMAC-SHA-1
+
+Status of This Memo
+
+   This memo provides information for the Internet community.  This memo
+   does not specify an Internet standard of any kind.  Distribution of
+   this memo is unlimited.
+
+Abstract
+
+   This document provides two sets of test cases for HMAC-MD5 and HMAC-
+   SHA-1, respectively. HMAC-MD5 and HMAC-SHA-1 are two constructs of
+   the HMAC [HMAC] message authentication function using the MD5 [MD5]
+   hash function and the SHA-1 [SHA] hash function. Both constructs are
+   used by IPSEC [OG,CG] and other protocols to authenticate messages.
+   The test cases and results provided in this document are meant to be
+   used as a conformance test for HMAC-MD5 and HMAC-SHA-1
+   implementations.
+
+1. Introduction
+
+   The general method for constructing a HMAC message authentication
+   function using a particular hash function is described in section 2
+   of [HMAC]. We will not repeat the description here. Section 5 of
+   [HMAC] also discusses truncating the output of HMAC; the rule is that
+   we should keep the more significant bits (the bits in the left,
+   assuming a network byte order (big-endian)).
+
+   In sections 2 and 3 we provide test cases for HMAC-MD5 and HMAC-SHA-
+   1, respectively. Each case includes the key, the data, and the
+   result.  The values of keys and data are either hexadecimal numbers
+   (prefixed by "0x") or ASCII character strings in double quotes. If a
+   value is an ASCII character string, then the HMAC computation for the
+   corresponding test case DOES NOT include the trailing null character
+   ('\0') in the string.
+
+
+
+
+
+
+
+
+
+Cheng & Glenn                Informational                      [Page 1]
+
+RFC 2202         Test Cases for HMAC-MD5 and HMAC-SHA-1   September 1997
+
+
+   The C source code of the functions used to generate HMAC-SHA-1
+   results is listed in the Appendix. Note that these functions are
+   meant to be simple and easy to understand; they are not optimized in
+   any way. The C source code for computing HMAC-MD5 can be found in
+   [MD5]; or you can do a simple modification to HMAC-SHA-1 code to get
+   HMAC-MD5 code, as explained in the Appendix.
+
+   The test cases in this document are cross-verified by three
+   independent implementations, one from NIST and two from IBM Research.
+   One IBM implementation uses optimized code that is very different
+   from the code in the Appendix. An implemenation that concurs with the
+   results provided in this document should be interoperable with other
+   similar implemenations.  We do not claim that such an implementation
+   is absolutely correct with respect to the HMAC definition in [HMAC].
+
+2. Test Cases for HMAC-MD5
+
+test_case =     1
+key =           0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
+key_len =       16
+data =          "Hi There"
+data_len =      8
+digest =        0x9294727a3638bb1c13f48ef8158bfc9d
+
+test_case =     2
+key =           "Jefe"
+key_len =       4
+data =          "what do ya want for nothing?"
+data_len =      28
+digest =        0x750c783e6ab0b503eaa86e310a5db738
+
+test_case =     3
+key =           0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+key_len =       16
+data =          0xdd repeated 50 times
+data_len =      50
+digest =        0x56be34521d144c88dbb8c733f0e8b3f6
+
+test_case =     4
+key =           0x0102030405060708090a0b0c0d0e0f10111213141516171819
+key_len =       25
+data =          0xcd repeated 50 times
+data_len =      50
+digest =        0x697eaf0aca3a3aea3a75164746ffaa79
+
+
+
+
+
+
+
+Cheng & Glenn                Informational                      [Page 2]
+
+RFC 2202         Test Cases for HMAC-MD5 and HMAC-SHA-1   September 1997
+
+
+test_case =     5
+key =           0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c
+key_len =       16
+data =          "Test With Truncation"
+data_len =      20
+digest =        0x56461ef2342edc00f9bab995690efd4c
+digest-96 =     0x56461ef2342edc00f9bab995
+
+test_case =     6
+key =           0xaa repeated 80 times
+key_len =       80
+data =          "Test Using Larger Than Block-Size Key - Hash Key First"
+data_len =      54
+digest =        0x6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd
+
+test_case =     7
+key =           0xaa repeated 80 times
+key_len =       80
+data =          "Test Using Larger Than Block-Size Key and Larger
+                Than One Block-Size Data"
+data_len =      73
+digest =        0x6f630fad67cda0ee1fb1f562db3aa53e
+
+3. Test Cases for HMAC-SHA-1
+
+test_case =     1
+key =           0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
+key_len =       20
+data =          "Hi There"
+data_len =      8
+digest =        0xb617318655057264e28bc0b6fb378c8ef146be00
+
+test_case =     2
+key =           "Jefe"
+key_len =       4
+data =          "what do ya want for nothing?"
+data_len =      28
+digest =        0xeffcdf6ae5eb2fa2d27416d5f184df9c259a7c79
+
+test_case =     3
+key =           0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+key_len =       20
+data =          0xdd repeated 50 times
+data_len =      50
+digest =        0x125d7342b9ac11cd91a39af48aa17b4f63f175d3
+
+
+
+
+
+
+Cheng & Glenn                Informational                      [Page 3]
+
+RFC 2202         Test Cases for HMAC-MD5 and HMAC-SHA-1   September 1997
+
+
+test_case =     4
+key =           0x0102030405060708090a0b0c0d0e0f10111213141516171819
+key_len =       25
+data =          0xcd repeated 50 times
+data_len =      50
+digest =        0x4c9007f4026250c6bc8414f9bf50c86c2d7235da
+
+test_case =     5
+key =           0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c
+key_len =       20
+data =          "Test With Truncation"
+data_len =      20
+digest =        0x4c1a03424b55e07fe7f27be1d58bb9324a9a5a04
+digest-96 =     0x4c1a03424b55e07fe7f27be1
+
+test_case =     6
+key =           0xaa repeated 80 times
+key_len =       80
+data =          "Test Using Larger Than Block-Size Key - Hash Key First"
+data_len =      54
+digest =        0xaa4ae5e15272d00e95705637ce8a3b55ed402112
+
+test_case =     7
+key =           0xaa repeated 80 times
+key_len =       80
+data =          "Test Using Larger Than Block-Size Key and Larger
+                Than One Block-Size Data"
+data_len =      73
+digest =        0xe8e99d0f45237d786d6bbaa7965c7808bbff1a91
+
+
+
+
+Cheng & Glenn                Informational                      [Page 4]
+
+RFC 2202         Test Cases for HMAC-MD5 and HMAC-SHA-1   September 1997
+
+
+4. Security Considerations
+
+   This docuemnt raises no security issues. Discussion on the strength
+   of the HMAC construction can be found in [HMAC].
+
+References
+
+   [HMAC]    Krawczyk, H., Bellare, M., and R. Canetti,
+             "HMAC: Keyed-Hashing for Message Authentication",
+             RFC 2104, February 1997.
+
+   [MD5]     Rivest, R., "The MD5 Message-Digest Algorithm",
+             RFC 1321, April 1992.
+
+   [SHA]     NIST, FIPS PUB 180-1: Secure Hash Standard, April 1995.
+
+   [OG]      Oehler, M., and R. Glenn,
+             "HMAC-MD5 IP Authentication with Replay Prevention",
+             RFC 2085, February 1997.
+
+   [CG]      Chang, S., and R. Glenn,
+             "HMAC-SHA IP Authentication with Replay Prevention",
+             Work in Progress.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Cheng & Glenn                Informational                      [Page 5]
+
+RFC 2202         Test Cases for HMAC-MD5 and HMAC-SHA-1   September 1997
+
+
+Authors' Addresses
+
+   Pau-Chen Cheng
+   IBM T.J. Watson Research Center
+   P.O.Box 704
+   Yorktown Heights, NY 10598
+
+   EMail: pau at watson.ibm.com
+
+
+   Robert Glenn
+   NIST
+   Building 820, Room 455
+   Gaithersburg, MD 20899
+
+   EMail: rob.glenn at nist.gov
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Cheng & Glenn                Informational                      [Page 6]
+
+RFC 2202         Test Cases for HMAC-MD5 and HMAC-SHA-1   September 1997
+
+
+Appendix
+
+   This appendix contains the C reference code which implements HMAC-
+   SHA-1 using an existing SHA-1 library.  It assumes that the SHA-1
+   library has similar API's as those of the MD5 code described in RFC
+   1321.  The code for HMAC-MD5 is similar, just replace the strings
+   "SHA" and "sha" with "MD5" and "md5". HMAC-MD5 code is also listed in
+   RFC 2104.
+
+   #ifndef SHA_DIGESTSIZE
+   #define SHA_DIGESTSIZE  20
+   #endif
+
+   #ifndef SHA_BLOCKSIZE
+   #define SHA_BLOCKSIZE   64
+   #endif
+
+   #ifndef MD5_DIGESTSIZE
+   #define MD5_DIGESTSIZE  16
+   #endif
+
+   #ifndef MD5_BLOCKSIZE
+   #define MD5_BLOCKSIZE   64
+   #endif
+
+   /* Function to print the digest */
+   void
+   pr_sha(FILE* fp, char* s, int t)
+   {
+           int     i ;
+
+           fprintf(fp, "0x") ;
+           for (i = 0 ; i < t ; i++)
+                   fprintf(fp, "%02x", s[i]) ;
+           fprintf(fp, "0) ;
+   }
+
+   void truncate
+   (
+    char*   d1,   /* data to be truncated */
+    char*   d2,   /* truncated data */
+    int     len   /* length in bytes to keep */
+   )
+   {
+           int     i ;
+           for (i = 0 ; i < len ; i++) d2[i] = d1[i];
+   }
+
+
+
+
+Cheng & Glenn                Informational                      [Page 7]
+
+RFC 2202         Test Cases for HMAC-MD5 and HMAC-SHA-1   September 1997
+
+
+   /* Function to compute the digest */
+   void
+   hmac_sha
+   (
+    char*    k,     /* secret key */
+    int      lk,    /* length of the key in bytes */
+    char*    d,     /* data */
+    int      ld,    /* length of data in bytes */
+    char*    out,   /* output buffer, at least "t" bytes */
+    int      t
+   )
+   {
+           SHA_CTX ictx, octx ;
+           char    isha[SHA_DIGESTSIZE], osha[SHA_DIGESTSIZE] ;
+           char    key[SHA_DIGESTSIZE] ;
+           char    buf[SHA_BLOCKSIZE] ;
+           int     i ;
+
+           if (lk > SHA_BLOCKSIZE) {
+
+                   SHA_CTX         tctx ;
+
+                   SHAInit(&tctx) ;
+                   SHAUpdate(&tctx, k, lk) ;
+                   SHAFinal(key, &tctx) ;
+
+                   k = key ;
+                   lk = SHA_DIGESTSIZE ;
+           }
+
+           /**** Inner Digest ****/
+
+           SHAInit(&ictx) ;
+
+           /* Pad the key for inner digest */
+           for (i = 0 ; i < lk ; ++i) buf[i] = k[i] ^ 0x36 ;
+           for (i = lk ; i < SHA_BLOCKSIZE ; ++i) buf[i] = 0x36 ;
+
+           SHAUpdate(&ictx, buf, SHA_BLOCKSIZE) ;
+           SHAUpdate(&ictx, d, ld) ;
+
+           SHAFinal(isha, &ictx) ;
+
+           /**** Outter Digest ****/
+
+           SHAInit(&octx) ;
+
+           /* Pad the key for outter digest */
+
+
+
+Cheng & Glenn                Informational                      [Page 8]
+
+RFC 2202         Test Cases for HMAC-MD5 and HMAC-SHA-1   September 1997
+
+
+           for (i = 0 ; i < lk ; ++i) buf[i] = k[i] ^ 0x5C ;
+           for (i = lk ; i < SHA_BLOCKSIZE ; ++i) buf[i] = 0x5C ;
+
+           SHAUpdate(&octx, buf, SHA_BLOCKSIZE) ;
+           SHAUpdate(&octx, isha, SHA_DIGESTSIZE) ;
+
+           SHAFinal(osha, &octx) ;
+
+           /* truncate and print the results */
+           t = t > SHA_DIGESTSIZE ? SHA_DIGESTSIZE : t ;
+           truncate(osha, out, t) ;
+           pr_sha(stdout, out, t) ;
+
+   }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Cheng & Glenn                Informational                      [Page 9]
+

Added: trunk/orca/packages/Digest-MD5-2.07/t/files.t
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/t/files.t	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/t/files.t	Sat Jul 13 18:45:57 2002
@@ -0,0 +1,130 @@
+print "1..5\n";
+
+use strict;
+use Digest::MD5 qw(md5 md5_hex md5_base64);
+
+#
+# This is the output of: 'md5sum Changes README MD5.pm MD5.xs rfc1321.txt'
+#
+my $EXPECT = <<EOT;
+2eb85a6e3342d3dcd4695ef65e208a9b  Changes
+3bb95afbdd85db7bb46b230b81c10466  README
+4cccdccc1aab2df360757e9034fa448f  MD5.pm
+0ebd4a0bd1cc9840114d811254826cdd  MD5.xs
+754b9db19f79dbc4992f7166eb0f37ce  rfc1321.txt
+EOT
+
+if (!(-f "README") && -f "../README") {
+   chdir("..") or die "Can't chdir: $!";
+}
+
+my $testno = 0;
+
+my $B64 = 1;
+eval { require MIME::Base64; };
+if ($@) {
+    print $@;
+    print "Will not test base64 methods\n";
+    $B64 = 0;
+}
+
+for (split /^/, $EXPECT) {
+     my($md5hex, $file) = split ' ';
+     my $md5bin = pack("H*", $md5hex);
+     my $md5b64;
+     if ($B64) {
+	 $md5b64 = MIME::Base64::encode($md5bin, "");
+	 chop($md5b64); chop($md5b64);   # remove padding
+     }
+     my $failed;
+
+     if (digest_file($file, 'digest') ne $md5bin) {
+	 print "$file: Bad digest\n";
+	 $failed++;
+     }
+
+     if (digest_file($file, 'hexdigest') ne $md5hex) {
+	 print "$file: Bad hexdigest\n";
+	 $failed++;
+     }
+
+     if ($B64 && digest_file($file, 'b64digest') ne $md5b64) {
+	 print "$file: Bad b64digest\n";
+	 $failed++;
+     }
+
+     my $data = cat_file($file);
+     if (md5($data) ne $md5bin) {
+	 print "$file: md5() failed\n";
+	 $failed++;
+     }
+     if (md5_hex($data) ne $md5hex) {
+	 print "$file: md5_hex() failed\n";
+	 $failed++;
+     }
+     if ($B64 && md5_base64($data) ne $md5b64) {
+	 print "$file: md5_base64() failed\n";
+	 $failed++;
+     }
+
+     if (Digest::MD5->new->add($data)->digest ne $md5bin) {
+	 print "$file: MD5->new->add(...)->digest failed\n";
+	 $failed++;
+     }
+     if (Digest::MD5->new->add($data)->hexdigest ne $md5hex) {
+	 print "$file: MD5->new->add(...)->hexdigest failed\n";
+	 $failed++;
+     }
+     if ($B64 && Digest::MD5->new->add($data)->b64digest ne $md5b64) {
+	 print "$file: MD5->new->add(...)->b64digest failed\n";
+	 $failed++;
+     }
+
+     my @data = split //, $data;
+     if (md5(@data) ne $md5bin) {
+	 print "$file: md5(\@data) failed\n";
+	 $failed++;
+     }
+     if (Digest::MD5->new->add(@data)->digest ne $md5bin) {
+	 print "$file: MD5->new->add(\@data)->digest failed\n";
+	 $failed++;
+     }
+     my $md5 = Digest::MD5->new;
+     for (@data) {
+	 $md5->add($_);
+     }
+     if ($md5->digest ne $md5bin) {
+	 print "$file: $md5->add()-loop failed\n";
+	 $failed++;
+     }
+
+     print "not " if $failed;
+     print "ok ", ++$testno, "\n";
+}
+
+
+sub digest_file
+{
+    my($file, $method) = @_;
+    $method ||= "digest";
+    #print "$file $method\n";
+
+    open(FILE, $file) or die "Can't open $file: $!";
+    binmode(FILE);
+    my $digest = Digest::MD5->new->addfile(*FILE)->$method();
+    close(FILE);
+
+    $digest;
+}
+
+sub cat_file
+{
+    my($file) = @_;
+    local $/;  # slurp
+    open(FILE, $file) or die "Can't open $file: $!";
+    binmode(FILE);
+    my $tmp = <FILE>;
+    close(FILE);
+    $tmp;
+}
+

Added: trunk/orca/packages/Digest-MD5-2.07/t/md5.t
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/t/md5.t	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/t/md5.t	Sat Jul 13 18:45:57 2002
@@ -0,0 +1,173 @@
+######################### We start with some black magic to print on failure.
+
+# Change 1..1 below to 1..last_test_to_print .
+# (It may become useful if the test is moved to ./t subdirectory.)
+
+BEGIN {print "1..14\n";}
+END {print "not ok 1\n" unless $loaded;}
+use MD5;
+$loaded = 1;
+print "ok 1\n";
+
+######################### End of black magic.
+
+# Insert your test code below (better if it prints "ok 13"
+# (correspondingly "not ok 13") depending on the success of chunk 13
+# of the test code):
+
+package MD5Test;
+
+# 2: Constructor
+
+print (($md5 = new MD5) ? "ok 2\n" : "not ok 2\n");
+
+# 3: Basic test data as defined in RFC 1321
+
+%data = (
+	 ""	=> "d41d8cd98f00b204e9800998ecf8427e",
+	 "a"	=> "0cc175b9c0f1b6a831c399e269772661",
+	 "abc"	=> "900150983cd24fb0d6963f7d28e17f72",
+	 "message digest"
+		=> "f96b697d7cb7938d525a2f31aaf161d0",
+	 "abcdefghijklmnopqrstuvwxyz"
+		=> "c3fcd3d76192e4007dfb496cca67e13b",
+	 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
+		=> "d174ab98d277d9f5a5611c2c9f419d9f",
+	 "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
+		=> "57edf4a22be3c955ac49da2e2107b67a",
+);
+
+$failed = 0;
+foreach (sort(keys(%data)))
+{
+    $md5->reset;
+    $md5->add($_);
+    $digest = $md5->digest;
+    $hex = unpack("H*", $digest);
+    if ($hex ne $data{$_}) {
+        print STDERR "\$md5->digest: $_\n";
+        print STDERR "expected: $data{$_}\n",
+                     "got     : $hex\n";
+	$failed++;
+    }
+
+    if (Digest::MD5::md5($_) ne $digest) {
+	print STDERR "md5($_) failed\n";
+	$failed++;
+    }
+
+    if (Digest::MD5::md5_hex($_) ne $hex) {
+	print STDERR "md5_hex($_) failed\n";
+	$failed++;
+    }
+
+    # same stuff ending with $md5->hexdigest instead
+    $md5->reset;
+    $md5->add($_);
+    $hex = $md5->hexdigest;
+    if ($hex ne $data{$_}) {
+        print STDERR "\$md5->hexdigest: $_\n";
+        print STDERR "expected: $data{$_}\n",
+                     "got     : $hex\n";
+	$failed++;
+    }
+}
+print ($failed ? "not ok 3\n" : "ok 3\n");
+
+# 4: Various flavours of file-handle to addfile
+
+open(F, "<$0");
+
+$md5->reset;
+
+$md5->addfile(F);
+$hex = $md5->hexdigest;
+print ($hex ne '' ? "ok 4\n" : "not ok 4\n");
+
+$orig = $hex;
+
+# 5: Fully qualified with ' operator
+
+seek(F, 0, 0);
+$md5->reset;
+$md5->addfile(MD5Test'F);
+$hex = $md5->hexdigest;
+print ($hex eq $orig ? "ok 5\n" : "not ok 5\n");
+
+# 6: Fully qualified with :: operator
+
+seek(F, 0, 0);
+$md5->reset;
+$md5->addfile(MD5Test::F);
+$hex = $md5->hexdigest;
+print ($hex eq $orig ? "ok 6\n" : "not ok 6\n");
+
+# 7: Type glob
+
+seek(F, 0, 0);
+$md5->reset;
+$md5->addfile(*F);
+$hex = $md5->hexdigest;
+print ($hex eq $orig ? "ok 7\n" : "not ok 7\n");
+
+# 8: Type glob reference (the prefered mechanism)
+
+seek(F, 0, 0);
+$md5->reset;
+$md5->addfile(\*F);
+$hex = $md5->hexdigest;
+print ($hex eq $orig ? "ok 8\n" : "not ok 8\n");
+
+# 9: File-handle passed by name (really the same as 6)
+
+seek(F, 0, 0);
+$md5->reset;
+$md5->addfile("MD5Test::F");
+$hex = $md5->hexdigest;
+print ($hex eq $orig ? "ok 9\n" : "not ok 9\n");
+
+# 10: Other ways of reading the data -- line at a time
+
+seek(F, 0, 0);
+$md5->reset;
+while (<F>)
+{
+    $md5->add($_);
+}
+$hex = $md5->hexdigest;
+print ($hex eq $orig ? "ok 10\n" : "not ok 10\n");
+
+# 11: Input lines as a list to add()
+
+seek(F, 0, 0);
+$md5->reset;
+$md5->add(<F>);
+$hex = $md5->hexdigest;
+print ($hex eq $orig ? "ok 11\n" : "not ok 11\n");
+
+# 12: Random chunks up to 128 bytes
+
+seek(F, 0, 0);
+$md5->reset;
+while (read(F, $hexata, (rand % 128) + 1))
+{
+    $md5->add($hexata);
+}
+$hex = $md5->hexdigest;
+print ($hex eq $orig ? "ok 12\n" : "not ok 12\n");
+
+# 13: All the data at once
+
+seek(F, 0, 0);
+$md5->reset;
+undef $/;
+$data = <F>;
+$hex = $md5->hexhash($data);
+print ($hex eq $orig ? "ok 13\n" : "not ok 13\n");
+
+close(F);
+
+# 14: Using static member function
+
+$hex = MD5->hexhash($data);
+print ($hex eq $orig ? "ok 14\n" : "not ok 14\n");

Added: trunk/orca/packages/Digest-MD5-2.07/t/md5-aaa.t
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/t/md5-aaa.t	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/t/md5-aaa.t	Sat Jul 13 18:45:57 2002
@@ -0,0 +1,282 @@
+use strict;
+print "1..256\n";
+
+use Digest::MD5 qw(md5_hex);
+
+my $testno = 0;
+while (<DATA>) {
+   my($hexdigest, $message) = split;
+   $message =~ s/\"//g;
+
+   my $failed;
+   $failed++ unless md5_hex($message) eq $hexdigest;
+   $failed++ unless Digest::MD5->new->add(split(//, $message))->digest
+                                              eq pack("H*", $hexdigest);
+
+   print "not " if $failed;
+   print "ok ", ++$testno, "\n";
+}
+
+
+
+# This data was generated with:
+#
+# perl -e 'for (1..256) { system("md5sum --string=" . ("a" x $_)); }'
+#
+__END__
+0cc175b9c0f1b6a831c399e269772661  "a"
+4124bc0a9335c27f086f24ba207a4912  "aa"
+47bce5c74f589f4867dbd57e9ca9f808  "aaa"
+74b87337454200d4d33f80c4663dc5e5  "aaaa"
+594f803b380a41396ed63dca39503542  "aaaaa"
+0b4e7a0e5fe84ad35fb5f95b9ceeac79  "aaaaaa"
+5d793fc5b00a2348c3fb9ab59e5ca98a  "aaaaaaa"
+3dbe00a167653a1aaee01d93e77e730e  "aaaaaaaa"
+552e6a97297c53e592208cf97fbb3b60  "aaaaaaaaa"
+e09c80c42fda55f9d992e59ca6b3307d  "aaaaaaaaaa"
+d57f21e6a273781dbf8b7657940f3b03  "aaaaaaaaaaa"
+45e4812014d83dde5666ebdf5a8ed1ed  "aaaaaaaaaaaa"
+c162de19c4c3731ca3428769d0cd593d  "aaaaaaaaaaaaa"
+451599a5f9afa91a0f2097040a796f3d  "aaaaaaaaaaaaaa"
+12f9cf6998d52dbe773b06f848bb3608  "aaaaaaaaaaaaaaa"
+23ca472302f49b3ea5592b146a312da0  "aaaaaaaaaaaaaaaa"
+88e42e96cc71151b6e1938a1699b0a27  "aaaaaaaaaaaaaaaaa"
+2c60c24e7087e18e45055a33f9a5be91  "aaaaaaaaaaaaaaaaaa"
+639d76897485360b3147e66e0a8a3d6c  "aaaaaaaaaaaaaaaaaaa"
+22d42eb002cefa81e9ad604ea57bc01d  "aaaaaaaaaaaaaaaaaaaa"
+bd049f221af82804c5a2826809337c9b  "aaaaaaaaaaaaaaaaaaaaa"
+ff49cfac3968dbce26ebe7d4823e58bd  "aaaaaaaaaaaaaaaaaaaaaa"
+d95dbfee231e34cccb8c04444412ed7d  "aaaaaaaaaaaaaaaaaaaaaaa"
+40edae4bad0e5bf6d6c2dc5615a86afb  "aaaaaaaaaaaaaaaaaaaaaaaa"
+a5a8bfa3962f49330227955e24a2e67c  "aaaaaaaaaaaaaaaaaaaaaaaaa"
+ae791f19bdf77357ff10bb6b0e97e121  "aaaaaaaaaaaaaaaaaaaaaaaaaa"
+aaab9c59a88bf0bdfcb170546c5459d6  "aaaaaaaaaaaaaaaaaaaaaaaaaaa"
+b0f0545856af1a340acdedce23c54b97  "aaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+f7ce3d7d44f3342107d884bfa90c966a  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+59e794d45697b360e18ba972bada0123  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+3b0845db57c200be6052466f87b2198a  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+5eca9bd3eb07c006cd43ae48dfde7fd3  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+b4f13cb081e412f44e99742cb128a1a5  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+4c660346451b8cf91ef50f4634458d41  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+11db24dc3f6c2145701db08625dd6d76  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+80dad3aad8584778352c68ab06250327  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+1227fe415e79db47285cb2689c93963f  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+8e084f489f1bdf08c39f98ff6447ce6d  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+08b2f2b0864bac1ba1585043362cbec9  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+4697843037d962f62a5a429e611e0f5f  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+10c4da18575c092b486f8ab96c01c02f  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+af205d729450b663f48b11d839a1c8df  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+0d3f91798fac6ee279ec2485b25f1124  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+4c3c7c067634daec9716a80ea886d123  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+d1e358e6e3b707282cdd06e919f7e08c  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+8c6ded4f0af86e0a7e301f8a716c4363  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+4c2d8bcb02d982d7cb77f649c0a2dea8  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+bdb662f765cd310f2a547cab1cfecef6  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+08ff5f7301d30200ab89169f6afdb7af  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+6eb6a030bcce166534b95bc2ab45d9cf  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+1bb77918e5695c944be02c16ae29b25e  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+b6fe77c19f0f0f4946c761d62585bfea  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+e9e7e260dce84ffa6e0e7eb5fd9d37fc  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+eced9e0b81ef2bba605cbc5e2e76a1d0  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ef1772b6dff9a122358552954ad0df65  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+3b0c8ac703f828b04c6c197006d17218  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+652b906d60af96844ebd21b674f35e93  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+dc2f2f2462a0d72358b2f99389458606  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+762fc2665994b217c52c3c2eb7d9f406  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+cc7ed669cf88f201c3297c6a91e1d18d  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+cced11f7bbbffea2f718903216643648  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+24612f0ce2c9d2cf2b022ef1e027a54f  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+b06521f39153d618550606be297466d5  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+014842d480b571495a4a0363793f7367  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+c743a45e0d2e6a95cb859adae0248435  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+def5d97e01e1219fb2fc8da6c4d6ba2f  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+92cb737f8687ccb93022fdb411a77cca  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+a0d1395c7fb36247bfe2d49376d9d133  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ab75504250558b788f99d1ebd219abf2  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+0f5c6c4e740bfcc08c3c26ccb2673d46  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+cddd19bec7f310d8c87149ef47a1828f  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+96b39b8b95e016c79d104d83395b8133  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+f1fc0b14ff8fa674b02344577e23eeb1  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+0e8d28a1cafa3ffcff22afd480cce7d8  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+448539ffc17e1e81005b65581855cef4  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+61e39aae7c53e6e77db2e4405d9fb157  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+618a426895ee6133a372bebd1129b63e  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+046c90690c9e36578b9d4a7e1d249c75  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+aadab38075c43296ee7e12466ebb03e3  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+b15af9cdabbaea0516866a33d8fd0f98  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+986e6938ed767a8ae9530eef54bfe5f1  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+7ae25a72b71a42ccbc5477fd989cd512  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+98d34e50d4aa7a893cc7919a91acb0e3  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+3fc53fc22ea40f1a0afd78fc2cd9aa0f  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+923e37c738b9d7b1526f70b65229cc3d  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+b3966b7a08e5d46fd0774b797ba78dc2  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+f50c7286b540bb181db1d6e05a51a296  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+4efd6c8826e65a61f82af954d431b59b  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ef1031e79e7a15a4470a5e98b23781b5  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+067876bfd0df0f4c5002780ec85e6f8c  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+789851dfa4c03563e9cef5f7bc050a7e  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+baf934720818ee49477e74fc644faa5e  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+9a0ea77ca26d2c121ddcc179edb76308  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+20c825561572e33d026f99ddfd999538  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+464c461455c5a927079a13609c20b637  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+cf37d42f89b6adb0e1a9e99104501b82  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+d266af45e3d06b70d9f52e2df4344186  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+f8b59fa22eb0ba944e2b7aa24d67b681  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+0918d7c2f9062743450a86eae9dde1a3  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+36a92cc94a9e0fa21f625f8bfb007adf  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+681d73898dad5685d48b5e8438bc3a66  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+337ccef058459c3c16411381778da0c4  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+6ccdfcc742862036ce07583633c5f77e  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ddfa1adc974649dc5b414be86def7457  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+650ebc28ad85f11aa4b63b6ee565b89d  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+e4571793bcaba284017eeabd8df85697  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+4fc040d354ad9ba5e4f62862109d3e17  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+25814274e02aa7cc03d6314eb703e655  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+11378ecaee0089c840d26352704027e3  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+86f950bfcd824d5546da01c40576db31  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+089f243d1e831c5879aa375ee364a06e  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+9146ef3527c7cfcc66dc615c3986e391  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+d727cfdfc9ed0347e6917a68b982f7bc  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+da8f45e1fdc12deecfe56aeb5288796e  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+29cfcf52d8250a253a535cf7989c7bd2  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+0f6eb555b8e3c35411eebe9348594193  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+a922439f963e7e59040e4756992c6f1b  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+81f8453cf3f7e5ee5479c777e5a8d80c  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+8a7bd0732ed6a28ce75f6dabc90e1613  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+5f61c0ccad4cac44c75ff505e1f1e537  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+f6acfca2d47c87f2b14ca038234d3614  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+269fc62c517f3d55c368152addca57e7  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+50587cb16413da779b35508018721647  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+5e4a3ecfdaa4636b84a39b6a7be7c047  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+c5339dc2af6bf595580281ffb07353f6  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+e51176a47347e167ed0ed766b6de1a0c  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+020406e1d05cdc2aa287641f7ae2cc39  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+e510683b3f5ffe4093d021808bc6ff70  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+b325dc1c6f5e7a2b7cf465b9feab7948  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+e016e4ccc7fdaea56fc377600b58c4cb  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+3870ec709d2fc64b255d65be3123ad69  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+a92bde1f862c3fe797ecd69510bbd266  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+04daa146f3a2256fdcbf015c0f67e168  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+3d13c8bf627421ccc937aa1c9ac87bf1  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+247dc7ffc545e4dda64ae12def481c4e  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+2dfd4def392ee9563241b7db7eb7c346  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+d11a18a4743a1a0a699d1704efb74a0d  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+55b62fabd9c77d44d86e992eeeb093e6  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+9a72cf7d0bd5ae2907c79f91837e3ced  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+d3828cce1835534475029202ebd799e4  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+b0bebbf0015658d4740679f263a3f01f  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+02368ebf1f53bc4634211b1693021666  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+04960f7d18960e348372949e4baa9752  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+c6041e7a86d407e9402b175670519260  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+439fd4c056bec1d14acd393746f6ae59  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+81a855120e04494c5a6c874a2360fd57  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ef57bd47a964dc3aadd959c4131e64ac  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+0b0ab27b16cbba267c141fe0f4ee9189  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+abccd84f340bfe4ba59095cc3d5ca6ad  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+bc620e8c15265f195c8818e2f3e3c58b  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+fdcd84c4143286f6fc70c69208acd18d  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+50e05071e773b1e9f3009a4a559ce6b2  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+9e69c7a6c1863fbba2532f09ba665bde  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+47a962111aa5187eeef3d17a278d95f2  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+c13e57e33526bc713b5a1825f92651bc  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+72b392f15593e42404b38e5c889fa75e  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+5327acd3278274265d44e22ccfc4042c  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+930dcac6da160b2a4c51879da76d3417  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+41292c326f926f1534ead47fe302f0a0  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+2bdecb5cf6b69a00f7832299ef2fb5a5  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+8bf93e9e8a3e4396de3f211c788e177e  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+eea9cb566e19d6a7f55fbae78d94ef2a  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+3b8452700a829dec78397aa5c0458dd3  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+7950059f699eaea1e0a1759340d7c153  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+40840c5f1de00f17a8e70d5bd4d00af2  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+80f86f6af38be9ca8e40c2dc44491a0a  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+7aab2c2e72c77163e7102412dc332125  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+bfd6869ae2ee2fe2675846d341eaa67d  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+7e4d976f6d552d1d5bac7e2693dc8759  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+37d9884c32abfc6f372ee899434e64ad  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+e362cd83a4b49d81ac6788b7839a56fd  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+9203cbb93b25d80b9d1b75e3c6c4b0dc  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+77441eda11554ec5b915d942605f66ed  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+e0fe0c02b5c9c5afe10ab9d6a3769efe  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+cc7682cf11b214e928f3df899772e789  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ade0901d347afb25ecf9df4955bb8061  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+987379587cbe8e94b7057269232ff826  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+fd44a60101b04b7ddbc2b4e9b509ca1f  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+53107a7f1e6f13a2e63239b6f2bf0ef1  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+0b82cdd562f26aaa2459610a7ba8cd76  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+79f12de7255e9c8c0ec9a9be45ee6210  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+92338d8de02ed7aa8b3adc9120b94e71  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+8fc48efda580fce85b8705d540e8382e  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+63642b027ee89938c922722650f2eb9b  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+fe54daa473502e9cc2c26dd66d564eab  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+b90f3d4b7dcd8cdd8d96cb14695f4793  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+3e73392e7a03bca45b67650d79a8fc63  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+7fe51f2642dffbabc33eea2fcc2039ba  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+bc33790e52f99718cf920329961ee753  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+54d1e41ebac5db7886f01ab0afb65b17  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+16e2824f7a3f00ef0028994182071953  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+234c07907df5019d5f40f03936939bce  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+8ea3af1d9476fa0b6c04ce4f3a336c03  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+e95b69eae07d498d484afc771d1c45fc  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+f22a673abbc4372544ba37b51a5f5a91  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+7e6161eb1be7b06928c536fada91b7f1  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+4dfe3c301e88fff67822e1cfcfece43f  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+edda210ac6645fbf5815eb4c58821f6d  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+6a514de2bf1926129b08f9234cd0115e  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+887f30b43b2867f4a9accceee7d16e6c  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+15936442c22dab9b685de350bfe75971  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+281a39e10bab29f1f2dead149a1f3f87  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+04d5f8a53b0eeda82d3c0ccafd02c98e  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+a91e6b80fe9d6db74fac76c7a67f065a  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+30334486fa9841044afb07f2573107a5  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+0183c0cf15a3c2ed97d326f421b6d62c  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+4dc2a01b2161653753019b5228f765f8  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+71ef2dbdec7f78005354abebbfec8d8f  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+a1d1cd1446c113726ba50cc86d8b6519  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ed6da79cfd13ece051c4cb7c88e80c2e  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+d2047852ce178d4ddb7978da3883f9c5  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+d75382e07dd096b618faeeac033eefff  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+3fb48e286d462dcc237c3335aa63ba14  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+55b959972677ea06c4d0e32f7fb2f10a  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+0a479c3623cfb9745e54d3376d0b9ae2  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+7825ad1ba19db7eec57d88b16936f32f  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+833ccf25509cb423a4aa98accb15512d  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+cae9609b05a9782610a5a43d7cd4b8ff  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+6c303e1da7f8a3032d13fe995847a722  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+4c47143a568e30ecde86dafe3bcb0558  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+9c48f0592f504b86360cfb6de00203b3  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+e1524f5686f170209366f9723880d9b0  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+a96164a43a192543d40e538b9e9e4ece  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+b774a4f788458a60e131d998705e4a06  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+1e97f0a7dfd3fac6ae585acdcf51a549  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+b6364c77b6dd495c2a7f6b0211ac6fce  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+5d22315e78df2bc4146aa66f6c405dbb  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+2a773d5b04e910612543a42deeaaaa62  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+0165449ac66b086accdec3051e0b691e  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+54884ba571054eae72b2a5271828a1fc  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+520fb61f8625ea916d72a54a37937bc6  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+7717f05d6e424a2c7a20ab7977b21ec8  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+b64e4f62e3e14317e3a90f9ff2cde576  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+a49128259cfe50ba3bed80bbd11add7f  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+b10cb153b79c2e4af6a8431c265aa82d  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+2e50fee6f574241042bdfabfdd46a153  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+5d5656a09b98c24edd01c530d3aad5e2  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+5ac1e1609d82274371c349d5b7875298  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+b7b40d64ffccebd78abcf522376b3aae  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+8619933469d908a2d4a2d890909bea43  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+591a0ee6dccd872b46ae184eb0f9450e  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+8cd256a02c8c5c1676e9220e655d9ac4  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+e48c0e2ed3e4e299a6e62e5416eb6d83  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+f30f75dce71e757ee562218c1efa0645  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+06bd7e90c0410dacb155732cf956f520  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+531a0a821a9304c215f1829b880306f1  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+93f4621c0b88499297ec3f8fbb3fb9c4  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+6af3d61e2e3ef8e189cffbea802c7e69  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+df84d21c884f99d6764d9bca4dec26e1  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+1bdbdf1c9087c796394bcda5789f7206  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+21f5b107cda33036590a19419afd7fb6  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+0eae304c738191613302fb6721ea3605  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+abed9cdef66dcec954b87124ba18c1ab  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+dfde09457e2017e31d4ecfaea010db8f  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+46bc249a5a8fc5d622cf12c42c463ae0  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+81109eec5aa1a284fb5327b10e9c16b9  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"

Added: trunk/orca/packages/Digest-MD5-2.07/hints/irix_6.pl
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/hints/irix_6.pl	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/hints/irix_6.pl	Sat Jul 13 18:45:57 2002
@@ -0,0 +1,6 @@
+# The Mongoose v7.1 compiler freezes up somewhere in the optimization of
+# MD5Transform() in MD5.c with optimization -O3.  This is a workaround:
+
+if ($Config{cc} =~ /64|n32/ && `$Config{cc} -version 2>&1` =~ /\s7\.1/) {
+    $self->{OPTIMIZE} = "-O1";
+}

Added: trunk/orca/packages/Digest-MD5-2.07/hints/dec_osf.pl
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/hints/dec_osf.pl	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/hints/dec_osf.pl	Sat Jul 13 18:45:57 2002
@@ -0,0 +1,13 @@
+if ($] < 5.00503 and !$Config{gccversion}) {
+  print "
+  Because of a bug with the DEC system C compiler, some tests in
+  t/rfc2202.t will be skipped.  These tests fail because the compiler
+  bug breaks Perl's 'x' operator for eight-bit characters.  The
+  Digest:: modules themselves work and should be safe to install
+  anyway.
+
+  Versions of Perl after 5.005_03 will contain a workaround for the
+  bug.
+
+";
+}

Added: trunk/orca/packages/Digest-MD5-2.07/MANIFEST
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/MANIFEST	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/MANIFEST	Sat Jul 13 18:45:57 2002
@@ -0,0 +1,36 @@
+README			Guess what?
+MANIFEST		This file
+MD2/MD2.pm		Digest::MD2 Perl Module
+MD2/MD2.xs		MD2 XS implementation
+MD2/Makefile.PL		Perl Makefile builder
+MD2/rfc1319.txt		The MD2 Message-Digest Algorithm
+MD2/t/md2.t		Test if Digest::MD2 works
+MD2/typemap		Supplementary typemap
+MD5.pm			Digest::MD5 Perl Module
+hints/dec_osf.pl	Workaround for DEC compiler bug
+hints/irix_6.pl		Workaround for IRIX compiler bug
+lib/MD5.pm		MD5 backwards compatibility stuff
+lib/Digest.pm		Loading frontend
+lib/Digest/HMAC.pm      HMAC implementation
+lib/Digest/HMAC_MD5.pm  HMAC using MD5
+lib/Digest/HMAC_SHA1.pm HMAC using SHA-1
+MD5.xs			MD5 Perl 'XS' source file
+typemap			Supplementary typemap
+Makefile.PL		Perl Makefile builder
+SHA1/Makefile.PL	Perl Makefile builder
+SHA1/SHA1.pm		Digest::SHA1 module
+SHA1/SHA1.xs		SHA-1 XS implementation
+SHA1/lib/SHA.pm		SHA backwards compatibility stuff
+SHA1/t/sha.t		Uwe's old test
+SHA1/t/sha1.t		Test if Digest::SHA1 works
+SHA1/typemap		Supplementary typemap
+rfc1321.txt		The MD5 Message-Digest Algorithm
+rfc2104.txt		HMAC: Keyed-Hashing for Message Authentication
+t/digest.t		Test Digest.pm loader
+t/files.t		Check a few files.
+t/md5.t			Test suite using standard Perl conventions
+t/md5-aaa.t		Exercise padding code
+t/rfc2202.t		Test Cases for HMAC-MD5 and HMAC-SHA-1
+Changes			Version history
+examples/mddriver.pl	Example driver script after mddriver.c in RFC 1321
+examples/twdigest.pl	Example code to format a digest like Tripwire

Added: trunk/orca/packages/Digest-MD5-2.07/lib/Digest/HMAC_SHA1.pm
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/lib/Digest/HMAC_SHA1.pm	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/lib/Digest/HMAC_SHA1.pm	Sat Jul 13 18:45:58 2002
@@ -0,0 +1,71 @@
+package Digest::HMAC_SHA1;
+$VERSION="1.00";
+
+use strict;
+use Digest::SHA1 qw(sha1);
+use Digest::HMAC qw(hmac);
+
+# OO interface
+use vars qw(@ISA);
+ at ISA=qw(Digest::HMAC);
+sub new
+{
+    my $class = shift;
+    $class->SUPER::new($_[0], "Digest::SHA1", 64);
+}
+
+# Functional interface
+require Exporter;
+*import = \&Exporter::import;
+use vars qw(@EXPORT_OK);
+ at EXPORT_OK=qw(hmac_sha1 hmac_sha1_hex);
+
+sub hmac_sha1
+{
+    hmac($_[0], $_[1], \&sha1, 64);
+}
+
+sub hmac_sha1_hex
+{
+    unpack("H*", &hmac_sha1)
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Digest::HMAC_SHA1 - Keyed-Hashing for Message Authentication
+
+=head1 SYNOPSIS
+
+ # Functional style
+ use Digest::HMAC_SHA1 qw(hmac_sha1 hmac_sha1_hex);
+ $digest = hmac_sha1($data, $key);
+ print hmac_sha1_hex($data, $key);
+
+ # OO style
+ use Digest::HMAC_SHA1;
+ $hmac = Digest::HMAC_SHA1->new($key);
+
+ $hmac->add($data);
+ $hmac->addfile(*FILE);
+
+ $digest = $hmac->digest;
+ $digest = $hmac->hexdigest;
+ $digest = $hmac->b64digest;
+
+=head1 DESCRIPTION
+
+This module provide HMAC-SHA-1 hashing.
+
+=head1 SEE ALSO
+
+L<Digest::HMAC>, L<Digest::SHA1>, L<Digest::HMAC_MD5>
+
+=head1 AUTHOR
+
+Gisle Aas <gisle at aas.no>
+
+=cut

Added: trunk/orca/packages/Digest-MD5-2.07/lib/Digest/HMAC.pm
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/lib/Digest/HMAC.pm	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/lib/Digest/HMAC.pm	Sat Jul 13 18:45:58 2002
@@ -0,0 +1,111 @@
+package Digest::HMAC;
+$VERSION = "1.00";
+
+use strict;
+
+# OO interface
+
+sub new
+{
+    my($class, $key, $hasher, $block_size) =  @_;
+    $block_size ||= 64;
+    $key = $hasher->new->add($key)->digest if length($key) > $block_size;
+
+    my $self = bless {}, $class;
+    $self->{k_ipad} = $key ^ (chr(0x36) x $block_size);
+    $self->{k_opad} = $key ^ (chr(0x5c) x $block_size);
+    $self->{hasher} = $hasher->new->add($self->{k_ipad});
+    $self;
+}
+
+sub reset
+{
+    my $self = shift;
+    $self->{hasher}->reset->add($self->{k_ipad});
+    $self;
+}
+
+sub add     { my $self = shift; $self->{hasher}->add(@_);     $self; }
+sub addfile { my $self = shift; $self->{hasher}->addfile(@_); $self; }
+
+sub _digest
+{
+    my $self = shift;
+    my $inner_digest = $self->{hasher}->digest;
+    $self->{hasher}->reset->add($self->{k_opad}, $inner_digest);
+}
+
+sub digest    { shift->_digest->digest;    }
+sub hexdigest { shift->_digest->hexdigest; }
+sub b64digest { shift->_digest->b64digest; }
+
+
+# Functional interface
+
+require Exporter;
+*import = \&Exporter::import;
+use vars qw(@EXPORT_OK);
+ at EXPORT_OK = qw(hmac hmac_hex);
+
+sub hmac
+{
+    my($data, $key, $hash_func, $block_size) = @_;
+    $block_size ||= 64;
+    $key = &$hash_func($key) if length($key) > $block_size;
+
+    my $k_ipad = $key ^ (chr(0x36) x $block_size);
+    my $k_opad = $key ^ (chr(0x5c) x $block_size);
+
+    &$hash_func($k_opad, &$hash_func($k_ipad, $data));
+}
+
+sub hmac_hex { unpack("H*", &hmac); }
+
+1;
+
+__END__
+
+=head1 NAME
+
+Digest::HMAC - Keyed-Hashing for Message Authentication
+
+=head1 SYNOPSIS
+
+ # Functional style
+ use Digest::HMAC qw(hmac hmac_hex);
+ $digest = hmac($data, $key, \&myhash);
+ print hmac_hex($data, $key, \&myhash);
+
+ # OO style
+ use Digest::HMAC;
+ $hmac = Digest::HMAC->new($key, "Digest::MyHash");
+
+ $hmac->add($data);
+ $hmac->addfile(*FILE);
+
+ $digest = $hmac->digest;
+ $digest = $hmac->hexdigest;
+ $digest = $hmac->b64digest;
+
+=head1 DESCRIPTION
+
+HMAC is used for message integrity checks between two parties that
+share a secret key, and works in combination with some other Digest
+algorithm, usually MD5 or SHA-1.  The HMAC mechanism is described in
+RFC 2104.
+
+HMAC follow the common C<Digest::> interface, but the constructor
+takes the secret key and the name of some other simple C<Digest::>
+as argument.
+
+=head1 SEE ALSO
+
+L<Digest::HMAC_MD5>, L<Digest::HMAC_SHA1>
+
+RFC 2104
+
+=head1 AUTHORS
+
+Graham Barr <gbarr at ti.com>, Gisle Aas <gisle at aas.no>
+
+=cut

Added: trunk/orca/packages/Digest-MD5-2.07/lib/Digest/HMAC_MD5.pm
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/lib/Digest/HMAC_MD5.pm	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/lib/Digest/HMAC_MD5.pm	Sat Jul 13 18:45:58 2002
@@ -0,0 +1,71 @@
+package Digest::HMAC_MD5;
+$VERSION="1.00";
+
+use strict;
+use Digest::MD5  qw(md5);
+use Digest::HMAC qw(hmac);
+
+# OO interface
+use vars qw(@ISA);
+ at ISA=qw(Digest::HMAC);
+sub new
+{
+    my $class = shift;
+    $class->SUPER::new($_[0], "Digest::MD5", 64);
+}
+
+# Functional interface
+require Exporter;
+*import = \&Exporter::import;
+use vars qw(@EXPORT_OK);
+ at EXPORT_OK=qw(hmac_md5 hmac_md5_hex);
+
+sub hmac_md5
+{
+    hmac($_[0], $_[1], \&md5, 64);
+}
+
+sub hmac_md5_hex
+{
+    unpack("H*", &hmac_md5)
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Digest::HMAC_MD5 - Keyed-Hashing for Message Authentication
+
+=head1 SYNOPSIS
+
+ # Functional style
+ use Digest::HMAC_MD5 qw(hmac_md5 hmac_md5_hex);
+ $digest = hmac_md5($data, $key);
+ print hmac_md5_hex($data, $key);
+
+ # OO style
+ use Digest::HMAC_MD5;
+ $hmac = Digest::HMAC_MD5->new($key);
+
+ $hmac->add($data);
+ $hmac->addfile(*FILE);
+
+ $digest = $hmac->digest;
+ $digest = $hmac->hexdigest;
+ $digest = $hmac->b64digest;
+
+=head1 DESCRIPTION
+
+This module provide HMAC-MD5 hashing.
+
+=head1 SEE ALSO
+
+L<Digest::HMAC>, L<Digest::MD5>, L<Digest::HMAC_SHA1>
+
+=head1 AUTHOR
+
+Gisle Aas <gisle at aas.no>
+
+=cut

Added: trunk/orca/packages/Digest-MD5-2.07/lib/MD5.pm
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/lib/MD5.pm	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/lib/MD5.pm	Sat Jul 13 18:45:58 2002
@@ -0,0 +1,54 @@
+package MD5;  # legacy stuff
+
+use strict;
+use vars qw($VERSION @ISA);
+
+$VERSION = '2.00';  # $Date: 1998/10/23 11:19:27 $
+
+require Digest::MD5;
+ at ISA=qw(Digest::MD5);
+
+sub hash    { shift->new->add(@_)->digest;    }
+sub hexhash { shift->new->add(@_)->hexdigest; }
+
+1;
+__END__
+
+=head1 NAME
+
+MD5 - Perl interface to the MD5 Message-Digest Algorithm
+
+=head1 SYNOPSIS
+
+ use MD5;
+
+ $context = new MD5;
+ $context->reset();
+    
+ $context->add(LIST);
+ $context->addfile(HANDLE);
+    
+ $digest = $context->digest();
+ $string = $context->hexdigest();
+
+ $digest = MD5->hash(SCALAR);
+ $string = MD5->hexhash(SCALAR);
+
+=head1 DESCRIPTION
+
+The C<MD5> module is B<depreciated>.  Use C<Digest::MD5> instead.
+
+The current C<MD5> module is just a wrapper around the C<Digest::MD5>
+module.  It is provided so that legacy code that rely on the old
+interface get the speed benefit of the new module.
+
+In addition to the methods provided by C<Digest::MD5> this module
+provide the class methods MD5->hash() and MD5->hexhash() that
+basically do the same as the md5() and md5_hex() functions provided
+C<Digest::MD5>.
+
+=head1 SEE ALSO
+
+L<Digest::MD5>
+
+=cut

Added: trunk/orca/packages/Digest-MD5-2.07/lib/Digest.pm
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/lib/Digest.pm	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/lib/Digest.pm	Sat Jul 13 18:45:58 2002
@@ -0,0 +1,178 @@
+package Digest;
+
+use strict;
+use vars qw($VERSION %MMAP $AUTOLOAD);
+
+$VERSION = "0.02";
+
+%MMAP = (
+  "SHA-1"      => "Digest::SHA1",
+  "HMAC-MD5"   => "Digest::HMAC_MD5",
+  "HMAC-SHA-1" => "Digest::HMAC_SHA1",
+);
+
+sub new
+{
+    shift;  # class ignored
+    my $algorithm = shift;
+    my $class = $MMAP{$algorithm} || "Digest::$algorithm";
+    no strict 'refs';
+    unless (exists ${"$class\::"}{"VERSION"}) {
+	eval "require $class";
+	die $@ if $@;
+    }
+    $class->new(@_);
+}
+
+sub AUTOLOAD
+{
+    my $class = shift;
+    my $algorithm = substr($AUTOLOAD, rindex($AUTOLOAD, '::')+2);
+    $class->new($algorithm, @_);
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Digest:: - Modules that calculate message digests
+
+=head1 SYNOPSIS
+
+  $md2 = Digest->MD2;
+  $md5 = Digest->MD5;
+
+  $sha1 = Digest->SHA1;
+  $sha1 = Digest->new("SHA-1");
+
+  $hmac = Digest->HMAC_MD5($key);
+
+=head1 DESCRIPTION
+
+The C<Digest::> modules calculate digests, also called "fingerprints"
+or "hashes", of some data, called a message.  The digest is some small
+fixed size string.  The actual size depend of the algorithm used.  The
+message is simply a sequence of arbitrary bytes.
+
+An important property of the digest algorithms is that the digest is
+I<likely> to change if the message change in some way.  Another
+property is that digest functions are one-way functions, i.e. it
+should be I<hard> to find a message that correspond to some given
+digest.  Algorithms differ in how "likely" and how "hard", as well as
+how efficient they are to compute.
+
+All C<Digest::> modules provide the same programming interface.  A
+functional interface for simple use, as well as an object oriented
+interface that can handle messages of arbitrary length and which can
+read files directly.
+
+The digest can be delivered in three formats:
+
+=over 8
+
+=item I<binary>
+
+This is the most compact form, but it is not well suited for printing
+or embedding in places that can't handle arbitrary data.
+
+=item I<hex>
+
+A twice as long string of (lowercase) hexadecimal digits.
+
+=item I<base64>
+
+A string of portable printable characters.  This is the base64 encoded
+representation of the digest with any trailing padding removed.  The
+string will be about 30% longer than the binary version. The
+L<MIME::Base64> tells you more about this encoding.
+
+=back
+
+
+The functional interface is simply importable functions with the same
+name as the algorithm.  The functions take the message as argument and
+return the digest.  Example:
+
+  use Digest::MD5 qw(md5);
+  $digest = md5($message);
+
+There are also versions of the functions with "_hex" or "_base64"
+appended to the name, which returns the digest in the indicated form.
+
+=head1 OO INTERFACE
+
+The following methods are available for all C<Digest::> modules:
+
+=over 4
+
+=item $ctx = Digest->XXX($arg,...)
+
+=item $ctx = Digest->new(XXX => $arg,...)
+
+=item $ctx = Digest::XXX->new($arg,...)
+
+The constructor returns some object that encapsulate the state of the
+message-digest algorithm.  You can add data to the object and finally
+ask for the digest.  The "XXX" should of course be replaced by the proper
+name of the digest algorithm you want to use.
+
+The two first forms are simply syntactic sugar which automatically
+load the right module on first use.  The second form allow you to use
+algorithm names which contains letters which are not legal perl
+identifiers, e.g. "SHA-1".
+
+If new() is called as a instance method (i.e. $ctx->new) it will just
+reset the state the object to the state of a newly created object.  No
+new object is created in this case.
+
+=item $ctx->reset
+
+This is just an alias for $ctx->new.
+
+=item $ctx->add($data,...)
+
+The $data provided as argument are appended to the message we
+calculate the digest for.  The return value is the $ctx object itself.
+
+=item $ctx->addfile($io_handle)
+
+The $io_handle is read until EOF and the content is appended to the
+message we calculate the digest for.  The return value is the $ctx
+object itself.
+
+=item $ctx->digest
+
+Return the binary digest for the message.
+
+Note that the C<digest> operation is effectively a destructive,
+read-once operation. Once it has been performed, the $ctx object is
+automatically C<reset> and can be used to calculate another digest
+value.
+
+=item $ctx->hexdigest
+
+Same as $ctx->digest, but will return the digest in hexadecimal form.
+
+=item $ctx->b64digest
+
+Same as $ctx->digest, but will return the digest as a base64 encoded
+string.
+
+=back
+
+=head1 SEE ALSO
+
+L<Digest::MD5>, L<Digest::SHA1>, L<Digest::HMAC>, L<Digest::MD2>
+
+L<MIME::Base64>
+
+=head1 AUTHOR
+
+Gisle Aas <gisle at aas.no>
+
+The C<Digest::> interface is based on the interface originally
+developed by Neil Winton for his C<MD5> module.
+
+=cut

Added: trunk/orca/packages/Digest-MD5-2.07/Makefile.PL
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/Makefile.PL	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/Makefile.PL	Sat Jul 13 18:45:58 2002
@@ -0,0 +1,118 @@
+require 5.004;
+use strict;
+use Config qw(%Config);
+use ExtUtils::MakeMaker;
+
+my @extra;
+ at extra = (DEFINE => "-DU32_ALIGNMENT_REQUIRED") unless free_u32_alignment();
+
+WriteMakefile(
+    'NAME'	   => 'Digest::MD5',
+    'VERSION_FROM' => 'MD5.pm',
+    @extra,
+    'dist'         => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', },
+);
+exit;
+
+#--------------
+
+
+sub free_u32_alignment
+{
+    $|=1;
+    print "Testing alignment requirements for U32... ";
+    return 1 if $^O eq 'VMS';
+
+    open(ALIGN_TEST, ">u32align.c") or die "$!";
+    print ALIGN_TEST <<'EOT'; close(ALIGN_TEST);
+/*--------------------------------------------------------------*/
+/*  This program allocates a buffer of U8 (char) and then tries */
+/*  to access it through a U32 pointer at every offset.  The    */
+/*  program  is expected to die with a bus error/seg fault for  */
+/*  machines that do not support unaligned integer read/write   */
+/*--------------------------------------------------------------*/
+
+#include <stdio.h>
+#include "EXTERN.h"
+#include "perl.h"
+
+int main(int argc, char** argv, char** env)
+{
+#if BYTEORDER == 0x1234 || BYTEORDER == 0x4321
+    U8 buf[] = "\0\0\0\1\0\0\0\0";
+    U32 *up;
+    int i;
+
+    if (sizeof(U32) != 4) {
+	printf("sizeof(U32) is not 4, but %d\n", sizeof(U32));
+	exit(1);
+    }
+
+    fflush(stdout);
+
+    for (i = 0; i < 4; i++) {
+	up = (U32*)(buf + i);
+	if (! ((*up == 1 << (8*i)) ||   /* big-endian */
+	       (*up == 1 << (8*(3-i)))  /* little-endian */
+	      )
+	   )
+	{
+	    printf("read failed (%x)\n", *up);
+	    exit(2);
+	}
+    }
+
+    /* write test */
+    for (i = 0; i < 4; i++) {
+	up = (U32*)(buf + i);
+	*up = 0xBeef;
+	if (*up != 0xBeef) {
+	    printf("write failed (%x)\n", *up);
+	    exit(3);
+	}
+    }
+
+    printf("no restrictions\n");
+    exit(0);
+#else
+    printf("unusual byteorder, playing safe\n");
+    exit(1);
+#endif
+    return 0;
+}
+/*--------------------------------------------------------------*/
+EOT
+
+    my $cc_cmd = "$Config{cc} $Config{ccflags} -I$Config{archlibexp}/CORE";
+    my $exe = "u32align$Config{_exe}";
+    if ($^O eq 'MSWin32') {
+        $cc_cmd .= ' -DWIN32IO_IS_STDIO';
+    } else {
+	$cc_cmd .= " -o $exe";
+    }
+    my $rc;
+    $rc = system("$cc_cmd $Config{ldflags} u32align.c $Config{libs}");
+    if ($rc) {
+	print "Can't compile test program\n";
+	unlink("u32align.c", $exe, "u32align$Config{_o}");
+	return;
+    }
+
+    $rc = system("./$exe");
+    unlink("u32align.c", $exe, "u32align$Config{_o}");
+
+    return 1 unless $rc;
+
+    if ($rc > 0x80) {
+	$rc >>= 8;
+	print "Test program exit status was $rc\n";
+    } else {
+	if ($rc & 0x80) {
+	    $rc &= ~0x80;
+	    print "Core dump deleted\n";
+	    unlink("core");
+	}
+	print "signal $rc\n";
+    }
+    return;
+}

Added: trunk/orca/packages/Digest-MD5-2.07/Changes
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/Changes	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/Changes	Sat Jul 13 18:45:58 2002
@@ -0,0 +1,383 @@
+1999-04-26   Gisle Aas <gisle at aas.no>
+
+   Release 2.07
+
+   The Digest::SHA1 module failed on some 64-bit systems, because I
+   assumed there was a correspondence between the U32 size and
+   BYTEORDER.  This version use 'unsigned long' as Uwe's original
+   SHA module did.
+
+   The module should now work better when liked statically with perl,
+   because we know use a safer module-loaded test in Digest.pm.
+
+   Assume we know the outcome of the alignment test on VMS. Patch by
+   Chuck Lane <lane at duphy4.physics.drexel.edu>
+
+
+
+1999-03-26   Gisle Aas <gisle at aas.no>
+
+   Release 2.06
+
+   Avoid LONG and BYTE types in SHA.xs as they was in conflict
+   with similar definitions in <winnt.h>.
+
+   Patch by Marko Asplund <aspa at hip.fi> to make the the alignment
+   test program link successfully with sfio-perl.
+
+   Fixed a typo in MD5.xs that might have affected 64-bit systems.
+   Spotted by Nick Ing-Simmons
+
+
+
+1999-03-15   Gisle Aas <gisle at aas.no>
+
+   Release 2.05
+
+   Included Digest::SHA1 based on Uwe Hollerbach's SHA module.
+
+
+
+1999-03-05   Gisle Aas <gisle at aas.no>
+
+   Release 2.04
+
+   Avoid the -o option when compiling alignment test program
+   for Win32 as suggested by Gurusamy Sarathy.
+
+   DEC Compiler bug workaround.  Contributed by D Roland Walker
+   <walker at ncbi.nlm.nih.gov>
+
+   Having references to a local variable called "na" was not
+   very safe either.  Some older versions of Perl can apparently
+   macroize this into something completely different.
+
+
+
+1999-02-27   Gisle Aas <gisle at aas.no>
+
+   Release 2.03
+
+   Patch from Christopher J. Madsen <chris_madsen at geocities.com> that
+   should help getting the u32align test program to compile with
+   Visual C++ 5 on Windows NT.
+
+   Got rid of references to PL_na.
+
+
+
+1999-01-31   Gisle Aas <gisle at aas.no>
+
+   Release 2.02
+
+   Added a hints file as workaround for an IRIX compiler bug.
+   Contributed by D Roland Walker <walker at ncbi.nlm.nih.gov>.
+
+   Note that the rfc2202 test can still fail on some DEC Alpha,
+   because of a compiler bug that affects the perl 'x' operator.
+   The Digest:: modules should work and be safe to install anyway.
+
+
+
+1998-12-18   Gisle Aas <aas at sn.no>
+
+   Release 2.01
+
+   Some casts and tweaks to make picky compilers more happy.
+
+
+
+1998-11-04   Gisle Aas <aas at sn.no>
+
+   Release 2.00.
+
+   Taken out Digest::SHA1 as this module will be provided from Uwe
+   Hollerbach later.
+
+   Some tweaks to MD2.xs and MD5.xs since "na" disappeared in
+   perl5.005_53
+
+
+
+1998-10-30   Gisle Aas <aas at sn.no>
+
+   Release 1.99_60
+
+   The 1.99_59 release introduced compilation problems for big-endian
+   systems with free U32 alignment.  Bug reported, and fix suggested
+   by Paul J. Schinder <schinder at pobox.com>.
+
+
+
+1998-10-28   Gisle Aas <aas at sn.no>
+
+   Release 1.99_59
+
+   Makefile.PL will run a test program to find out if U32 values can
+   be aligned anywhere.  This hopefully cures the core dumps reported
+   on Solaris and other big endian systems.  Thanks to Graham Barr for
+   debugging this.
+
+
+
+1998-10-28   Gisle Aas <aas at sn.no>
+
+   Release 1.99_58
+
+   Should be very close to a 2.00 release now.  Need some success
+   reports from people running on big-endian machines first I think.
+
+   Added a Digest::MD2 implementation.
+
+   Wrote Digest.pm documentation.  This define the interface that all
+   Digest:: modules should provide.
+
+   Avoided some code duplication in MD5.xs
+
+   Fixed typo, that prevented Digest::SHA1::sha1_base64() from working.
+
+
+
+1998-10-27   Gisle Aas <aas at sn.no>
+
+   Release 1.99_57
+
+   Rewritten most of the MD5 C code to make it real fast (especially
+   on little-endian machines without alignment restrictions for U32).
+   Compared to MD5-1.7 we can process files 4 times as fast and we
+   digest small stuff in memory 7 times faster.  I came to these
+   conclusions after these tests (gcc -O2, i586, Linux):
+
+   First tested calculation of the digest of a 31 MB file, using
+   perl -le 'print Digest::MD5->new->addfile(*STDIN)->hexdigest'
+   and similar stuff:
+
+      MD5-1.7:                 21.06s
+      Digest::MD5-1.99_57:      5.23s
+      md5sum (GNU textutils):   4.90s
+
+   As you can see, we do nearly as good as the md5sum program.  I
+   think the reason we don't beat md5sum is that perl always insist on
+   loading extra modules like Config.pm, Carp.pm, strict.pm, vars.pm,
+   AutoLoader.pm and DynaLoader.pm.  When I simply wrapped the MD5.xs
+   hasher code in a C program I managed to process the file in 4.68s.
+
+   Then we calculated the digest of the same 6 byte sting, 20000
+   times:
+
+      MD5-1.7:                 11.81s
+      Digest::MD5-1.99_57:      1.68s
+
+   Digest::MD5 benefit from making this into a plain procedure call
+   instead of a static method call.
+
+
+   Other changes in this release are:
+
+   Documentation update
+
+   Internal MD5.xs cleanup.
+
+   $md5->digest will automatically reset now.
+
+   Digest::HMAC methods add() and addfile() did not return the
+   corret object.
+
+   Added Digest.pm loading module.  I am not sure this is a good idea.
+
+   Added Digest::SHA1 and Digest::HMAC_SHA1 module.  The Digest::SHA1
+   module is just a wrapper around SHA.pm.  I hope to get the author
+   of SHA.pm to move his module to the Digest:: category.
+
+
+
+1998-10-25   Gisle Aas <aas at sn.no>
+
+   Release 1.99_56
+
+   Fix memcpy_byteswap() function in MD5.xs.  Must be careful with
+   htovl() as it might evaluate its arguments more than once.
+
+
+
+1998-10-25   Gisle Aas <aas at sn.no>
+
+   Release 1.99_55
+
+   Grahams HMAC_MD5.pm splitted into two modules.  Digest::HMAC and
+   Digest::HMAC_MD5.  Also provide functional interface.  Documentation
+   is still lacking.
+
+   Included RFC 2202 based test for HMAC-MD5.
+
+
+
+1998-10-24   Gisle Aas <aas at sn.no>
+
+   Release 1.99_54
+
+   Included HMAC_MD5.pm, contributed by Graham Barr <gbarr at ti.com>.
+
+   I have a hard time to make up my mind :-)  md5_bin() renamed back
+   to md5().   Functions are not exported by default any more.
+
+   Try to Encode/Decode with memcpy_byteswap for 32-bit big-endian
+   machines.
+
+
+
+1998-10-23   Gisle Aas <aas at sn.no>
+
+   Release 1.99_53
+
+   Renamed core module as Digest::MD5.  Leave a MD5.pm stub for
+   legacy code.
+
+   The md5() function renamed as md5_bin().
+
+   The constructor, Digest::MD5->new, no longer takes any extra
+   arguments.
+
+   Added some new tests.
+
+   Updated the documentation.
+
+   $md5->b64digest implemented with same base64 encoder as md5_base64.
+
+
+
+1998-10-23   Gisle Aas <aas at sn.no>
+
+   Release 1.99_52
+
+   Patch from Graham Barr which make it work for big-endian machines
+   again.
+
+
+
+1998-10-22   Gisle Aas <aas at sn.no>
+
+   Release 1.99_51
+
+   The MD5 class is now subclassable.
+
+   The add() and addfile() methods now return $self.
+
+   The reset() method is just an alias for new().
+
+   The constructor (MD5->new) now takes optional arguments which are
+   automatically added.  It means that we can now write:
+
+      MD5->new($data)->hexdigest;
+
+   New $md5->b64digest method.
+
+   New functions that are exported on request: md5, md5_hex, md5_base64
+
+   Included RFC 1321
+
+   Barely started to update the documentation.
+
+
+
+1998-10-22   Gisle Aas <aas at sn.no>
+
+   Release 1.99_50
+
+   Much better performance (more than twice as fast now).  Mostly
+   because we use Copy/Zero instead of the original MD5_memcpy and
+   MD5_memset functions.
+
+   The addfile() and hexdigest() methods are now XS implemented.
+
+   All RSA functions now included in MD5.xs and made static.
+
+   Use perl's Copy/Zero.
+
+   Random cleanup, simplifications and reformatting.
+   Merged things better with the perl configuration.
+
+
+
+Neil Winton's versions below:
+
+
+*** 96/06/20 Version 1.7
+
+MD5 is now completely 64-bit clean (I hope). The basic MD5 code uses
+32-bit quantities and requires a typedef UINT4 to be defined in
+global.h. Perl configuration data (the value of BYTEORDER) is used to
+determine if unsigned longs have 4 or 8 bytes. On 64-bit platforms (eg
+DEC Alpha) then it assumes that "unsigned int" will be a 32-bit type.
+If this is incorrect then adding -DUINT4_IS_LONG to the DEFINES line in
+Makefile.PL will override this.
+
+On some machines (at least Cray that I know of) there is no 32-bit
+integer type. In this case defining TRUNCATE_UINT4 (which is done
+automatically for a Cray) will ensure that 64-bit values are masked
+down to 32 bits. I have done my best to test this but without easy
+access to a true 64-bit machine I can not totally guarantee it (unless
+anyone wants to lend me a spare Cray :-)
+
+There is one remaining limitation for 64-bit enabled processors. The
+amount of data passed to any single call to the underlying MD5
+routines is limited to (2^32 - 1) bytes -- that's 4 gigabytes. I'm
+sorry if that's a real problem for you ...
+
+And finally, a minor complilation warning (unsigned char * used with
+function having char * prototype) has also been eliminated.
+
+*** 96/04/09 Version 1.6
+
+Re-generated module framework using h2xs to pick up the latest module
+conventions for versions etc. You can now say "use MD5 1.6;" and things
+should work correctly. MD5.pod has been integrated into MD5.pm and
+CHANGES renamed to Changes. There is a fairly comprehensive test.pl
+which can be invoked via "make test". There are no functional changes
+to the MD5 routines themselves.
+
+*** 96/03/14 Version 1.5.3
+
+Fixed addfile method to accept type-glob references for the file-handle
+(eg \*STDOUT). This is more consistent with other routines and is now the
+recommended way of passing file-handles. The documentation now gives more
+examples as to how the routines might be used.
+
+*** 96/03/12 Version 1.5.2
+
+Minor fixes from Christopher J Madsen <madsen at computek.net> to provide
+support for building on OS/2 (and to work arround a perl -w bug).
+
+Remove warning about possible difference between add('foo', 'bar') and
+add('foobar'). This is not true (it may have been true in the earliest
+version of the module but is no longer the case).
+
+*** 96/03/08 Version 1.5.1
+
+Add CHANGES file to make it easier for people to figure out what has
+been going on. (Meant to do this as part of 1.5)
+
+*** 96/03/05 Version 1.5
+
+Add hash() and hexhash() methods at the suggestion/request of Gary
+Howland <gary at kampai.euronet.nl> before inclusion in a wider library
+of cryptography modules.
+
+*** 96/02/27 Version 1.4
+
+Finally fixed the pesky Solaris dynamic loading bug. All kudos to Ken
+Pizzini <kenp at spry.com>!
+
+*** 95/11/29 Version 1.3.1
+
+Add explanations of current known problems.
+
+*** 95/06/02 Version 1.3
+
+Fix problems with scope resolution in addfile() reported by
+Jean-Claude Giese <Jean-Claude.Giese at loria.fr>. Basically ARGV is
+always implicitly in package main while other filehandles aren't.
+ 
+*** 95/05/23 Version 1.2.1
+
+[Changes pre 1.2.1 not recorded]

Added: trunk/orca/packages/Digest-MD5-2.07/SHA1/typemap
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/SHA1/typemap	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/SHA1/typemap	Sat Jul 13 18:45:58 2002
@@ -0,0 +1,5 @@
+SHA_INFO*	T_SHA_INFO
+
+INPUT
+T_SHA_INFO
+	$var = get_sha_info($arg)

Added: trunk/orca/packages/Digest-MD5-2.07/SHA1/t/sha.t
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/SHA1/t/sha.t	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/SHA1/t/sha.t	Sat Jul 13 18:45:58 2002
@@ -0,0 +1,48 @@
+#!/usr/local/bin/perl -w
+
+print "1..1\n";
+my $bad;
+
+use SHA qw(sha_version);
+$ver = &sha_version();
+
+sub do_test
+{
+    my ($label, $str, $expect0, $expect1, $skip_big_test) = @_;
+    my ($c, @tmp);
+    my $sha = new SHA;
+    $sha->add($str);
+    $expect = ($ver eq 'SHA-1') ? $expect1 : $expect0;
+    print "$label:\nEXPECT:   $expect\n";
+    my $hexdigest = $sha->hexdigest();
+    my $hexhash   =  $sha->hexhash($str);
+    print "RESULT 1: $hexdigest\n";
+    print "RESULT 2: $hexhash\n";
+    $bad++ if $hexdigest ne $expect || $hexhash ne $expect;
+    unless ($skip_big_test) {
+	$sha->reset();
+	@tmp = split(//, $str);
+	foreach $c (@tmp) {
+	    $sha->add($c);
+	}
+	my $hexdigest = $sha->hexdigest();
+	print "RESULT 3: $hexdigest\n";
+	$bad++ if $hexdigest ne $expect;
+    } else {
+	print "skipping RESULT 3\n";
+    }
+}
+
+print "Using digest version $ver, library version $SHA::VERSION\nIf the following results don't match, there's something wrong.\n";
+do_test("test1", "abc",
+    "0164b8a9 14cd2a5e 74c4f7ff 082c4d97 f1edf880",
+    "a9993e36 4706816a ba3e2571 7850c26c 9cd0d89d");
+do_test("test2", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+    "d2516ee1 acfa5baf 33dfc1c4 71e43844 9ef134c8",
+    "84983e44 1c3bd26e baae4aa1 f95129e5 e54670f1");
+do_test("test3", "a" x 1000000,
+    "3232affa 48628a26 653b5aaa 44541fd9 0d690603",
+    "34aa973c d4c4daa4 f61eeb2b dbad2731 6534016f", 1);
+
+print "not " if $bad;
+print "ok 1\n";

Added: trunk/orca/packages/Digest-MD5-2.07/SHA1/t/sha1.t
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/SHA1/t/sha1.t	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/SHA1/t/sha1.t	Sat Jul 13 18:45:58 2002
@@ -0,0 +1,30 @@
+print "1..5\n";
+
+use Digest::SHA1 qw(sha1 sha1_hex sha1_base64);
+
+print "not " unless Digest::SHA1->new->add("abc")->hexdigest eq "a9993e364706816aba3e25717850c26c9cd0d89d";
+print "ok 1\n";
+
+print "not " unless sha1("abc") eq pack("H*", "a9993e364706816aba3e25717850c26c9cd0d89d");
+print "ok 2\n";
+
+print "not " unless sha1_hex("abc") eq "a9993e364706816aba3e25717850c26c9cd0d89d";
+print "ok 3\n";
+
+print "not " unless sha1_base64("abc") eq "qZk+NkcGgWq6PiVxeFDCbJzQ2J0";
+print "ok 4\n";
+
+# Test file checking from too...
+open(FILE, ">stest$$.txt") || die;
+binmode(FILE);
+for (1..512) {
+    print FILE "This is line $_\n";
+}
+close(FILE);
+
+open(FILE, "stest$$.txt") || die;
+$digest = Digest::SHA1->new->addfile(*FILE)->b64digest;
+print "$digest\nnot " unless $digest eq "1ZuIK/sQeBwqh+dIACqpnoRQUE4";
+print "ok 5\n";
+
+unlink("stest$$.txt");

Added: trunk/orca/packages/Digest-MD5-2.07/SHA1/SHA1.xs
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/SHA1/SHA1.xs	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/SHA1/SHA1.xs	Sat Jul 13 18:45:58 2002
@@ -0,0 +1,485 @@
+/* $Id: SHA1.xs,v 1.4 1999/04/26 09:30:29 gisle Exp $ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+#ifdef __cplusplus
+}
+#endif
+
+/* NIST Secure Hash Algorithm */
+/* heavily modified by Uwe Hollerbach <uh at alumni.caltech edu> */
+/* from Peter C. Gutmann's implementation as found in */
+/* Applied Cryptography by Bruce Schneier */
+/* Further modifications to include the "UNRAVEL" stuff, below */
+
+/* This code is in the public domain */
+
+/* Useful defines & typedefs */
+
+typedef unsigned long ULONG;     /* 32-or-more-bit quantity */
+
+#define SHA_BLOCKSIZE		64
+#define SHA_DIGESTSIZE		20
+
+typedef struct {
+    ULONG digest[5];		/* message digest */
+    ULONG count_lo, count_hi;	/* 64-bit bit count */
+    U8 data[SHA_BLOCKSIZE];	/* SHA data buffer */
+    int local;			/* unprocessed amount in data */
+} SHA_INFO;
+
+
+/* UNRAVEL should be fastest & biggest */
+/* UNROLL_LOOPS should be just as big, but slightly slower */
+/* both undefined should be smallest and slowest */
+
+#define SHA_VERSION 1
+#define UNRAVEL
+/* #define UNROLL_LOOPS */
+
+/* SHA f()-functions */
+#define f1(x,y,z)	((x & y) | (~x & z))
+#define f2(x,y,z)	(x ^ y ^ z)
+#define f3(x,y,z)	((x & y) | (x & z) | (y & z))
+#define f4(x,y,z)	(x ^ y ^ z)
+
+/* SHA constants */
+#define CONST1		0x5a827999L
+#define CONST2		0x6ed9eba1L
+#define CONST3		0x8f1bbcdcL
+#define CONST4		0xca62c1d6L
+
+/* truncate to 32 bits -- should be a null op on 32-bit machines */
+#define T32(x)	((x) & 0xffffffffL)
+
+/* 32-bit rotate */
+#define R32(x,n)	T32(((x << n) | (x >> (32 - n))))
+
+/* the generic case, for when the overall rotation is not unraveled */
+#define FG(n)	\
+    T = T32(R32(A,5) + f##n(B,C,D) + E + *WP++ + CONST##n);	\
+    E = D; D = C; C = R32(B,30); B = A; A = T
+
+/* specific cases, for when the overall rotation is unraveled */
+#define FA(n)	\
+    T = T32(R32(A,5) + f##n(B,C,D) + E + *WP++ + CONST##n); B = R32(B,30)
+
+#define FB(n)	\
+    E = T32(R32(T,5) + f##n(A,B,C) + D + *WP++ + CONST##n); A = R32(A,30)
+
+#define FC(n)	\
+    D = T32(R32(E,5) + f##n(T,A,B) + C + *WP++ + CONST##n); T = R32(T,30)
+
+#define FD(n)	\
+    C = T32(R32(D,5) + f##n(E,T,A) + B + *WP++ + CONST##n); E = R32(E,30)
+
+#define FE(n)	\
+    B = T32(R32(C,5) + f##n(D,E,T) + A + *WP++ + CONST##n); D = R32(D,30)
+
+#define FT(n)	\
+    A = T32(R32(B,5) + f##n(C,D,E) + T + *WP++ + CONST##n); C = R32(C,30)
+
+
+static void sha_transform(SHA_INFO *sha_info)
+{
+    int i;
+    U8 *dp;
+    ULONG T, A, B, C, D, E, W[80], *WP;
+
+    dp = sha_info->data;
+
+/*
+the following makes sure that at least one code block below is
+traversed or an error is reported, without the necessity for nested
+preprocessor if/else/endif blocks, which are a great pain in the
+nether regions of the anatomy...
+*/
+#undef SWAP_DONE
+
+#if BYTEORDER == 0x1234
+#define SWAP_DONE
+    for (i = 0; i < 16; ++i) {
+	T = *((ULONG *) dp);
+	dp += 4;
+	W[i] =  ((T << 24) & 0xff000000) | ((T <<  8) & 0x00ff0000) |
+		((T >>  8) & 0x0000ff00) | ((T >> 24) & 0x000000ff);
+    }
+#endif
+
+#if BYTEORDER == 0x4321
+#define SWAP_DONE
+    for (i = 0; i < 16; ++i) {
+	T = *((ULONG *) dp);
+	dp += 4;
+	W[i] = T32(T);
+    }
+#endif
+
+#if BYTEORDER == 0x12345678
+#define SWAP_DONE
+    for (i = 0; i < 16; i += 2) {
+	T = *((ULONG *) dp);
+	dp += 8;
+	W[i] =  ((T << 24) & 0xff000000) | ((T <<  8) & 0x00ff0000) |
+		((T >>  8) & 0x0000ff00) | ((T >> 24) & 0x000000ff);
+	T >>= 32;
+	W[i+1] = ((T << 24) & 0xff000000) | ((T <<  8) & 0x00ff0000) |
+		 ((T >>  8) & 0x0000ff00) | ((T >> 24) & 0x000000ff);
+    }
+#endif
+
+#if BYTEORDER == 0x87654321
+#define SWAP_DONE
+    for (i = 0; i < 16; i += 2) {
+	T = *((ULONG *) dp);
+	dp += 8;
+	W[i] = T32(T >> 32);
+	W[i+1] = T32(T);
+    }
+#endif
+
+#ifndef SWAP_DONE
+#error Unknown byte order -- you need to add code here
+#endif /* SWAP_DONE */
+
+    for (i = 16; i < 80; ++i) {
+	W[i] = W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16];
+#if (SHA_VERSION == 1)
+	W[i] = R32(W[i], 1);
+#endif /* SHA_VERSION */
+    }
+    A = sha_info->digest[0];
+    B = sha_info->digest[1];
+    C = sha_info->digest[2];
+    D = sha_info->digest[3];
+    E = sha_info->digest[4];
+    WP = W;
+#ifdef UNRAVEL
+    FA(1); FB(1); FC(1); FD(1); FE(1); FT(1); FA(1); FB(1); FC(1); FD(1);
+    FE(1); FT(1); FA(1); FB(1); FC(1); FD(1); FE(1); FT(1); FA(1); FB(1);
+    FC(2); FD(2); FE(2); FT(2); FA(2); FB(2); FC(2); FD(2); FE(2); FT(2);
+    FA(2); FB(2); FC(2); FD(2); FE(2); FT(2); FA(2); FB(2); FC(2); FD(2);
+    FE(3); FT(3); FA(3); FB(3); FC(3); FD(3); FE(3); FT(3); FA(3); FB(3);
+    FC(3); FD(3); FE(3); FT(3); FA(3); FB(3); FC(3); FD(3); FE(3); FT(3);
+    FA(4); FB(4); FC(4); FD(4); FE(4); FT(4); FA(4); FB(4); FC(4); FD(4);
+    FE(4); FT(4); FA(4); FB(4); FC(4); FD(4); FE(4); FT(4); FA(4); FB(4);
+    sha_info->digest[0] = T32(sha_info->digest[0] + E);
+    sha_info->digest[1] = T32(sha_info->digest[1] + T);
+    sha_info->digest[2] = T32(sha_info->digest[2] + A);
+    sha_info->digest[3] = T32(sha_info->digest[3] + B);
+    sha_info->digest[4] = T32(sha_info->digest[4] + C);
+#else /* !UNRAVEL */
+#ifdef UNROLL_LOOPS
+    FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1);
+    FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1);
+    FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2);
+    FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2);
+    FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3);
+    FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3);
+    FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4);
+    FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4);
+#else /* !UNROLL_LOOPS */
+    for (i =  0; i < 20; ++i) { FG(1); }
+    for (i = 20; i < 40; ++i) { FG(2); }
+    for (i = 40; i < 60; ++i) { FG(3); }
+    for (i = 60; i < 80; ++i) { FG(4); }
+#endif /* !UNROLL_LOOPS */
+    sha_info->digest[0] = T32(sha_info->digest[0] + A);
+    sha_info->digest[1] = T32(sha_info->digest[1] + B);
+    sha_info->digest[2] = T32(sha_info->digest[2] + C);
+    sha_info->digest[3] = T32(sha_info->digest[3] + D);
+    sha_info->digest[4] = T32(sha_info->digest[4] + E);
+#endif /* !UNRAVEL */
+}
+
+/* initialize the SHA digest */
+
+static void sha_init(SHA_INFO *sha_info)
+{
+    sha_info->digest[0] = 0x67452301L;
+    sha_info->digest[1] = 0xefcdab89L;
+    sha_info->digest[2] = 0x98badcfeL;
+    sha_info->digest[3] = 0x10325476L;
+    sha_info->digest[4] = 0xc3d2e1f0L;
+    sha_info->count_lo = 0L;
+    sha_info->count_hi = 0L;
+    sha_info->local = 0;
+}
+
+/* update the SHA digest */
+
+static void sha_update(SHA_INFO *sha_info, U8 *buffer, int count)
+{
+    int i;
+    ULONG clo;
+
+    clo = T32(sha_info->count_lo + ((ULONG) count << 3));
+    if (clo < sha_info->count_lo) {
+	++sha_info->count_hi;
+    }
+    sha_info->count_lo = clo;
+    sha_info->count_hi += (ULONG) count >> 29;
+    if (sha_info->local) {
+	i = SHA_BLOCKSIZE - sha_info->local;
+	if (i > count) {
+	    i = count;
+	}
+	memcpy(((U8 *) sha_info->data) + sha_info->local, buffer, i);
+	count -= i;
+	buffer += i;
+	sha_info->local += i;
+	if (sha_info->local == SHA_BLOCKSIZE) {
+	    sha_transform(sha_info);
+	} else {
+	    return;
+	}
+    }
+    while (count >= SHA_BLOCKSIZE) {
+	memcpy(sha_info->data, buffer, SHA_BLOCKSIZE);
+	buffer += SHA_BLOCKSIZE;
+	count -= SHA_BLOCKSIZE;
+	sha_transform(sha_info);
+    }
+    memcpy(sha_info->data, buffer, count);
+    sha_info->local = count;
+}
+
+/* finish computing the SHA digest */
+
+static void sha_final(unsigned char digest[20], SHA_INFO *sha_info)
+{
+    int count;
+    ULONG lo_bit_count, hi_bit_count;
+
+    lo_bit_count = sha_info->count_lo;
+    hi_bit_count = sha_info->count_hi;
+    count = (int) ((lo_bit_count >> 3) & 0x3f);
+    ((U8 *) sha_info->data)[count++] = 0x80;
+    if (count > SHA_BLOCKSIZE - 8) {
+	memset(((U8 *) sha_info->data) + count, 0, SHA_BLOCKSIZE - count);
+	sha_transform(sha_info);
+	memset((U8 *) sha_info->data, 0, SHA_BLOCKSIZE - 8);
+    } else {
+	memset(((U8 *) sha_info->data) + count, 0,
+	    SHA_BLOCKSIZE - 8 - count);
+    }
+    sha_info->data[56] = (hi_bit_count >> 24) & 0xff;
+    sha_info->data[57] = (hi_bit_count >> 16) & 0xff;
+    sha_info->data[58] = (hi_bit_count >>  8) & 0xff;
+    sha_info->data[59] = (hi_bit_count >>  0) & 0xff;
+    sha_info->data[60] = (lo_bit_count >> 24) & 0xff;
+    sha_info->data[61] = (lo_bit_count >> 16) & 0xff;
+    sha_info->data[62] = (lo_bit_count >>  8) & 0xff;
+    sha_info->data[63] = (lo_bit_count >>  0) & 0xff;
+    sha_transform(sha_info);
+    digest[ 0] = (unsigned char) ((sha_info->digest[0] >> 24) & 0xff);
+    digest[ 1] = (unsigned char) ((sha_info->digest[0] >> 16) & 0xff);
+    digest[ 2] = (unsigned char) ((sha_info->digest[0] >>  8) & 0xff);
+    digest[ 3] = (unsigned char) ((sha_info->digest[0]      ) & 0xff);
+    digest[ 4] = (unsigned char) ((sha_info->digest[1] >> 24) & 0xff);
+    digest[ 5] = (unsigned char) ((sha_info->digest[1] >> 16) & 0xff);
+    digest[ 6] = (unsigned char) ((sha_info->digest[1] >>  8) & 0xff);
+    digest[ 7] = (unsigned char) ((sha_info->digest[1]      ) & 0xff);
+    digest[ 8] = (unsigned char) ((sha_info->digest[2] >> 24) & 0xff);
+    digest[ 9] = (unsigned char) ((sha_info->digest[2] >> 16) & 0xff);
+    digest[10] = (unsigned char) ((sha_info->digest[2] >>  8) & 0xff);
+    digest[11] = (unsigned char) ((sha_info->digest[2]      ) & 0xff);
+    digest[12] = (unsigned char) ((sha_info->digest[3] >> 24) & 0xff);
+    digest[13] = (unsigned char) ((sha_info->digest[3] >> 16) & 0xff);
+    digest[14] = (unsigned char) ((sha_info->digest[3] >>  8) & 0xff);
+    digest[15] = (unsigned char) ((sha_info->digest[3]      ) & 0xff);
+    digest[16] = (unsigned char) ((sha_info->digest[4] >> 24) & 0xff);
+    digest[17] = (unsigned char) ((sha_info->digest[4] >> 16) & 0xff);
+    digest[18] = (unsigned char) ((sha_info->digest[4] >>  8) & 0xff);
+    digest[19] = (unsigned char) ((sha_info->digest[4]      ) & 0xff);
+}
+
+
+
+
+/*----------------------------------------------------------------*/
+
+static SHA_INFO* get_sha_info(SV* sv)
+{
+    if (sv_derived_from(sv, "Digest::SHA1"))
+	return (SHA_INFO*)SvIV(SvRV(sv));
+    croak("Not a reference to a Digest::SHA1 object");
+    return (SHA_INFO*)0; /* some compilers insist on a return value */
+}
+
+
+static char* hex_20(const unsigned char* from, char* to)
+{
+    static char *hexdigits = "0123456789abcdef";
+    const unsigned char *end = from + 20;
+    char *d = to;
+
+    while (from < end) {
+	*d++ = hexdigits[(*from >> 4)];
+	*d++ = hexdigits[(*from & 0x0F)];
+	from++;
+    }
+    *d = '\0';
+    return to;
+}
+
+static char* base64_20(const unsigned char* from, char* to)
+{
+    static char* base64 =
+	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+    const unsigned char *end = from + 20;
+    unsigned char c1, c2, c3;
+    char *d = to;
+
+    while (1) {
+	c1 = *from++;
+	c2 = *from++;
+	*d++ = base64[c1>>2];
+	*d++ = base64[((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4)];
+	if (from == end) {
+	    *d++ = base64[(c2 & 0xF) << 2];
+	    break;
+	}
+	c3 = *from++;
+	*d++ = base64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
+	*d++ = base64[c3 & 0x3F];
+    }
+    *d = '\0';
+    return to;
+}
+
+/* Formats */
+#define F_BIN 0
+#define F_HEX 1
+#define F_B64 2
+
+static SV* make_mortal_sv(const unsigned char *src, int type)
+{
+    STRLEN len;
+    char result[41];
+    char *ret;
+    
+    switch (type) {
+    case F_BIN:
+	ret = (char*)src;
+	len = 20;
+	break;
+    case F_HEX:
+	ret = hex_20(src, result);
+	len = 40;
+	break;
+    case F_B64:
+	ret = base64_20(src, result);
+	len = 27;
+	break;
+    default:
+	croak("Bad convertion type (%d)", type);
+	break;
+    }
+    return sv_2mortal(newSVpv(ret,len));
+}
+
+
+/********************************************************************/
+
+typedef PerlIO* InputStream;
+
+MODULE = Digest::SHA1		PACKAGE = Digest::SHA1
+
+PROTOTYPES: DISABLE
+
+void
+new(xclass)
+	SV* xclass
+    PREINIT:
+	SHA_INFO* context;
+    PPCODE:
+	if (!SvROK(xclass)) {
+	    STRLEN my_na;
+	    char *sclass = SvPV(xclass, my_na);
+	    New(55, context, 1, SHA_INFO);
+	    ST(0) = sv_newmortal();
+	    sv_setref_pv(ST(0), sclass, (void*)context);
+	    SvREADONLY_on(SvRV(ST(0)));
+	} else {
+	    context = get_sha_info(xclass);
+	}
+	sha_init(context);
+	XSRETURN(1);
+
+void
+DESTROY(context)
+	SHA_INFO* context
+    CODE:
+        Safefree(context);
+
+void
+add(self, ...)
+	SV* self
+    PREINIT:
+	SHA_INFO* context = get_sha_info(self);
+	int i;
+	unsigned char *data;
+	STRLEN len;
+    PPCODE:
+	for (i = 1; i < items; i++) {
+	    data = (unsigned char *)(SvPV(ST(i), len));
+	    sha_update(context, data, len);
+	}
+	XSRETURN(1);  /* self */
+
+void
+addfile(self, fh)
+	SV* self
+	InputStream fh
+    PREINIT:
+	SHA_INFO* context = get_sha_info(self);
+	unsigned char buffer[4096];
+	int  n;
+    CODE:
+	/* Process blocks until EOF */
+        while ( (n = PerlIO_read(fh, buffer, sizeof(buffer)))) {
+	    sha_update(context, buffer, n);
+	}
+	XSRETURN(1);  /* self */
+
+void
+digest(context)
+	SHA_INFO* context
+    ALIAS:
+	Digest::SHA1::digest    = F_BIN
+	Digest::SHA1::hexdigest = F_HEX
+	Digest::SHA1::b64digest = F_B64
+    PREINIT:
+	unsigned char digeststr[20];
+    PPCODE:
+        sha_final(digeststr, context);
+	sha_init(context);  /* In case it is reused */
+        ST(0) = make_mortal_sv(digeststr, ix);
+        XSRETURN(1);
+
+void
+sha1(...)
+    ALIAS:
+	Digest::SHA1::sha1        = F_BIN
+	Digest::SHA1::sha1_hex    = F_HEX
+	Digest::SHA1::sha1_base64 = F_B64
+    PREINIT:
+	SHA_INFO ctx;
+	int i;
+	unsigned char *data;
+        STRLEN len;
+	unsigned char digeststr[20];
+    PPCODE:
+	sha_init(&ctx);
+	for (i = 0; i < items; i++) {
+	    data = (unsigned char *)(SvPV(ST(i), len));
+	    sha_update(&ctx, data, len);
+	}
+	sha_final(digeststr, &ctx);
+        ST(0) = make_mortal_sv(digeststr, ix);
+        XSRETURN(1);

Added: trunk/orca/packages/Digest-MD5-2.07/SHA1/lib/SHA.pm
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/SHA1/lib/SHA.pm	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/SHA1/lib/SHA.pm	Sat Jul 13 18:45:58 2002
@@ -0,0 +1,73 @@
+package SHA;
+
+use strict;
+use vars qw($VERSION @ISA @EXPORT_OK);
+
+$VERSION = '2.00'; # $Date: 1999/03/08 12:04:41 $
+
+require Digest::SHA1;
+ at ISA=qw(Digest::SHA1);
+
+require Exporter;
+*import = *Exporter::imprt;
+ at EXPORT_OK=qw(sha_version);
+
+sub hexdigest
+{
+    my $self = shift;
+    join(" ", unpack("A8 A8 A8 A8 A8", $self->SUPER::hexdigest(@_)));
+}
+
+sub hash        { shift->new->add(@_)->digest;    }
+sub hexhash     { shift->new->add(@_)->hexdigest; }
+sub sha_version { "SHA-1"; }
+
+1;
+
+__END__
+
+=head1 NAME
+
+SHA - Perl interface to the NIST Secure Hash Algorithm
+
+=head1 SYNOPSIS
+
+    use SHA;
+
+    $version = &SHA::sha_version;
+
+    $context = new SHA;
+    $context->reset();
+
+    $context->add(LIST);
+    $context->addfile(HANDLE);
+
+    $digest = $context->digest();
+    $string = $context->hexdigest();
+
+    $digest = $context->hash($string);
+    $string = $context->hexhash($string);
+
+=head1 DESCRIPTION
+
+The C<SHA> module is B<depreciated>.  Use C<Digest::SHA1> instead.
+
+The current C<SHA> module is just a wrapper around the C<Digest::SHA1>
+module.  It is provided so that legacy code that rely on the old
+interface still work.  This wrapper does not support the old (and
+buggy) SHA-0 algorithm.
+
+In addition to the methods provided by C<Digest::SHA1> this module
+provide the class methods SHA->hash() and SHA->hexhash() that
+basically do the same as the sha1() and sha1_hex() functions provided
+C<Digest::SHA1>.
+
+The SHA->hex* methods will insert spaces between groups of 8 hex
+characters, while the Digest::SHA1 version of the same methods will not
+do this.
+
+=head1 SEE ALSO
+
+L<Digest::SHA1>
+
+=cut

Added: trunk/orca/packages/Digest-MD5-2.07/SHA1/Makefile.PL
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/SHA1/Makefile.PL	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/SHA1/Makefile.PL	Sat Jul 13 18:45:59 2002
@@ -0,0 +1,8 @@
+require 5.004;
+use ExtUtils::MakeMaker;
+
+WriteMakefile(
+    'NAME'	   => 'Digest::SHA1',
+    'VERSION_FROM' => 'SHA1.pm',
+    'dist'         => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', },
+);

Added: trunk/orca/packages/Digest-MD5-2.07/SHA1/SHA1.pm
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/SHA1/SHA1.pm	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/SHA1/SHA1.pm	Sat Jul 13 18:45:59 2002
@@ -0,0 +1,120 @@
+package Digest::SHA1;
+
+use strict;
+use vars qw($VERSION @ISA @EXPORT_OK);
+
+$VERSION = '1.01';  # $Date: 1999/04/26 09:24:25 $
+
+require Exporter;
+*import = \&Exporter::import;
+ at EXPORT_OK = qw(sha1 sha1_hex sha1_base64);
+
+require DynaLoader;
+ at ISA=qw(DynaLoader);
+Digest::SHA1->bootstrap($VERSION);
+
+*reset = \&new;
+
+1;
+__END__
+
+=head1 NAME
+
+Digest::SHA1 - Perl interface to the SHA-1 Algorithm
+
+=head1 SYNOPSIS
+
+ # Functional style
+ use Digest::SHA1  qw(sha1 sha1_hex sha1_base64);
+
+ $digest = sha1($data);
+ $digest = sha1_hex($data);
+ $digest = sha1_base64($data);
+    
+
+ # OO style
+ use Digest::SHA1;
+
+ $ctx = Digest::SHA1->new;
+
+ $ctx->add($data);
+ $ctx->addfile(*FILE);
+
+ $digest = $ctx->digest;
+ $digest = $ctx->hexdigest;
+ $digest = $ctx->b64digest;
+
+=head1 DESCRIPTION
+
+The C<Digest::SHA1> module allows you to use the NIST SHA-1 message
+digest algorithm from within Perl programs.  The algorithm takes as
+input a message of arbitrary length and produces as output a 160-bit
+"fingerprint" or "message digest" of the input.
+
+The C<Digest::SHA1> module provide a procedural interface for simple
+use, as well as an object oriented interface that can handle messages
+of arbitrary length and which can read files directly.
+
+A binary digest will be 20 bytes long.  A hex digest will be 40
+characters long.  A base64 digest will be 27 characters long.
+
+
+=head1 FUNCTIONS
+
+The following functions can be exported from the C<Digest::SHA1>
+module.  No functions are exported by default.
+
+=over 4
+
+=item sha1($data,...)
+
+This function will concatenate all arguments, calculate the SHA-1
+digest of this "message", and return it in binary form.
+
+=item sha1_hex($data,...)
+
+Same as sha1(), but will return the digest in hexadecimal form.
+
+=item sha1_base64($data,...)
+
+Same as sha1(), but will return the digest as a base64 encoded string.
+
+=back
+
+=head1 METHODS
+
+The C<Digest::SHA1> module provide the standard C<Digest> OO-interface.
+The constructor looks like this:
+
+=over 4
+
+=item $sha1 = Digest->new('SHA-1')
+
+=item $sha1 = Digest::SHA1->new
+
+The constructor returns a new C<Digest::SHA1> object which encapsulate
+the state of the SHA-1 message-digest algorithm.  You can add data to
+the object and finally ask for the digest using the methods described
+in L<Digest>.
+
+=back
+
+=head1 SEE ALSO
+
+L<Digest>, L<Digest::HMAC_SHA1>, L<Digest::MD5>
+
+=head1 COPYRIGHT
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+ Copyright 1999 Gisle Aas.
+ Copyright 1997 Uwe Hollerbach.
+
+=head1 AUTHORS
+
+Peter C. Gutmann,
+Uwe Hollerbach <uh at alumni.caltech.edu>,
+Gisle Aas <gisle at aas.no>
+
+=cut

Added: trunk/orca/packages/Digest-MD5-2.07/README
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/README	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/README	Sat Jul 13 18:45:59 2002
@@ -0,0 +1,22 @@
+Digest:: MD5, MD2, SHA1, and HMAC
+---------------------------------
+
+This is a Perl extension interface to the RSA Data Security Inc. MD5,
+MD2, as well as NIST SHA-1, Message Digest algorithms.  This package
+also provide modules which calculate HMAC digests.
+
+To build the extensions, unpack this distribution somewhere, create
+the Makefile by running 'perl Makefile.PL' and do a 'make', 'make
+test', and if successful 'make install'.
+
+You will need perl version 5.004 or better to install these modules.
+Further documentation is embedded in the individual modules.
+
+Copyright 1998-1999 Gisle Aas.
+Copyright 1998 Graham Barr.
+Copyright 1997 Uwe Hollerbach.
+Copyright 1995-1996 Neil Winton.
+Copyright 1990-1992 RSA Data Security, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.

Added: trunk/orca/packages/Digest-MD5-2.07/MD5.xs
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/MD5.xs	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/MD5.xs	Sat Jul 13 18:45:59 2002
@@ -0,0 +1,611 @@
+/* $Id: MD5.xs,v 1.23 1999/03/26 13:27:49 gisle Exp $ */
+
+/* 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the same terms as Perl itself.
+ * 
+ *  Copyright 1998 Gisle Aas.
+ *  Copyright 1995-1996 Neil Winton.
+ *  Copyright 1991-1992 RSA Data Security, Inc.
+ *
+ * This code is derived from Neil Winton's MD5-1.7 Perl module, which in
+ * turn is derived from the reference implementation in RFC 1231 which
+ * comes with this message:
+ *
+ * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ * rights reserved.
+ *
+ * License to copy and use this software is granted provided that it
+ * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ *
+ * License is also granted to make and use derivative works provided
+ * that such works are identified as "derived from the RSA Data
+ * Security, Inc. MD5 Message-Digest Algorithm" in all material
+ * mentioning or referencing the derived work.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software for any particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+#ifdef __cplusplus
+}
+#endif
+
+/*#define MD5_DEBUG /**/
+
+/* Perl does not guarantee that U32 is exactly 32 bits.  Some system
+ * has no integral type with exactly 32 bits.  For instance, A Cray has
+ * short, int and long all at 64 bits so we need to apply this macro
+ * to reduce U32 values to 32 bits at appropriate places. If U32
+ * really does have 32 bits then this is a no-op.
+ */
+#if BYTEORDER > 0x4321 || defined(TRUNCATE_U32)
+  #define TO32(x)    ((x) &  0xFFFFffff)
+  #define TRUNC32(x) ((x) &= 0xFFFFffff)
+#else
+  #define TO32(x)    (x)
+  #define TRUNC32(x) /*nothing*/
+#endif
+
+/* The MD5 algorithm is defined in terms of little endian 32-bit
+ * values.  The following macros (and functions) allow us to convert
+ * between native integers and such values.
+ */
+#undef BYTESWAP
+#ifndef U32_ALIGNMENT_REQUIRED
+ #if BYTEORDER == 0x1234      /* 32-bit little endian */
+  #define BYTESWAP(x) (x)     /* no-op */
+
+ #elif BYTEORDER == 0x4321    /* 32-bit big endian */
+  #define BYTESWAP(x) 	((((x)&0xFF)<<24)	\
+			|(((x)>>24)&0xFF)	\
+			|(((x)&0x0000FF00)<<8)	\
+			|(((x)&0x00FF0000)>>8)	)
+ #endif
+#endif
+
+#ifndef BYTESWAP
+static void u2s(U32 u, U8* s)
+{
+    *s++ = u         & 0xFF;
+    *s++ = (u >>  8) & 0xFF;
+    *s++ = (u >> 16) & 0xFF;
+    *s   = (u >> 24) & 0xFF;
+}
+
+#define s2u(s,u) ((u) =  (U32)(*s)            |  \
+                        ((U32)(*(s+1)) << 8)  |  \
+                        ((U32)(*(s+2)) << 16) |  \
+                        ((U32)(*(s+3)) << 24))
+#endif
+
+
+/* This stucture keeps the current state of algorithm.
+ */
+typedef struct {
+  U32 A, B, C, D;  /* current digest */
+  U32 bytes_low;   /* counts bytes in message */
+  U32 bytes_high;  /* turn it into a 64-bit counter */
+  U8 buffer[128];  /* collect complete 64 byte blocks */
+} MD5_CTX;
+
+
+/* Padding is added at the end of the message in order to fill a
+ * complete 64 byte block (- 8 bytes for the message length).  The
+ * padding is also the reason the buffer in MD5_CTX have to be
+ * 128 bytes.
+ */
+static unsigned char PADDING[64] = {
+  0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* Constants for MD5Transform routine.
+ */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & ((y) ^ (z)) ^ (z)))
+#define G(x, y, z) F(z, x, y)
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n) | ((x) >> (32-(n)))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+ * Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, s, ac)                    \
+ (a) += F ((b), (c), (d)) + (NEXTx) + (U32)(ac); \
+ TRUNC32((a));                                   \
+ (a) = ROTATE_LEFT ((a), (s));                   \
+ (a) += (b);                                     \
+ TRUNC32((a));
+
+#define GG(a, b, c, d, x, s, ac)                 \
+ (a) += G ((b), (c), (d)) + X[x] + (U32)(ac);    \
+ TRUNC32((a));                                   \
+ (a) = ROTATE_LEFT ((a), (s));                   \
+ (a) += (b);                                     \
+ TRUNC32((a));
+
+#define HH(a, b, c, d, x, s, ac)                 \
+ (a) += H ((b), (c), (d)) + X[x] + (U32)(ac);    \
+ TRUNC32((a));                                   \
+ (a) = ROTATE_LEFT ((a), (s));                   \
+ (a) += (b);                                     \
+ TRUNC32((a));
+
+#define II(a, b, c, d, x, s, ac)                 \
+ (a) += I ((b), (c), (d)) + X[x] + (U32)(ac);    \
+ TRUNC32((a));                                   \
+ (a) = ROTATE_LEFT ((a), (s));                   \
+ (a) += (b);                                     \
+ TRUNC32((a));
+
+
+static void
+MD5Init(MD5_CTX *ctx)
+{
+  /* Start state */
+  ctx->A = 0x67452301;
+  ctx->B = 0xefcdab89;
+  ctx->C = 0x98badcfe;
+  ctx->D = 0x10325476;
+
+  /* message length */
+  ctx->bytes_low = ctx->bytes_high = 0;
+}
+
+
+static void
+MD5Transform(MD5_CTX* ctx, const U8* buf, STRLEN blocks)
+{
+    static int tcount = 0;
+
+    U32 A = ctx->A;
+    U32 B = ctx->B;
+    U32 C = ctx->C;
+    U32 D = ctx->D;
+
+#ifndef U32_ALIGNMENT_REQUIRED
+    const U32 *x = (U32*)buf;  /* really just type casting */
+#endif
+
+    do {
+	U32 a = A;
+	U32 b = B;
+	U32 c = C;
+	U32 d = D;
+
+#if BYTEORDER == 0x1234 && !defined(U32_ALIGNMENT_REQUIRED)
+	const U32 *X = x;
+        #define NEXTx  (*x++)
+#else
+	U32 X[16];      /* converted values, used in round 2-4 */
+	U32 *uptr = X;
+	U32 tmp;
+ #ifdef BYTESWAP
+        #define NEXTx  (tmp=*x++, *uptr++ = BYTESWAP(tmp))
+ #else
+        #define NEXTx  (s2u(buf,tmp), buf += 4, *uptr++ = tmp)
+ #endif
+#endif
+
+#ifdef MD5_DEBUG
+	if (buf == ctx->buffer)
+	    fprintf(stderr,"%5d: Transform ctx->buffer", ++tcount);
+	else 
+	    fprintf(stderr,"%5d: Transform %p (%d)", ++tcount, buf, blocks);
+
+	{
+	    int i;
+	    fprintf(stderr,"[");
+	    for (i = 0; i < 16; i++) {
+		fprintf(stderr,"%x,", x[i]);
+	    }
+	    fprintf(stderr,"]\n");
+	}
+#endif
+
+	/* Round 1 */
+	FF (a, b, c, d, S11, 0xd76aa478); /* 1 */
+	FF (d, a, b, c, S12, 0xe8c7b756); /* 2 */
+	FF (c, d, a, b, S13, 0x242070db); /* 3 */
+	FF (b, c, d, a, S14, 0xc1bdceee); /* 4 */
+	FF (a, b, c, d, S11, 0xf57c0faf); /* 5 */
+	FF (d, a, b, c, S12, 0x4787c62a); /* 6 */
+	FF (c, d, a, b, S13, 0xa8304613); /* 7 */
+	FF (b, c, d, a, S14, 0xfd469501); /* 8 */
+	FF (a, b, c, d, S11, 0x698098d8); /* 9 */
+	FF (d, a, b, c, S12, 0x8b44f7af); /* 10 */
+	FF (c, d, a, b, S13, 0xffff5bb1); /* 11 */
+	FF (b, c, d, a, S14, 0x895cd7be); /* 12 */
+	FF (a, b, c, d, S11, 0x6b901122); /* 13 */
+	FF (d, a, b, c, S12, 0xfd987193); /* 14 */
+	FF (c, d, a, b, S13, 0xa679438e); /* 15 */
+	FF (b, c, d, a, S14, 0x49b40821); /* 16 */
+
+	/* Round 2 */
+	GG (a, b, c, d,  1, S21, 0xf61e2562); /* 17 */
+	GG (d, a, b, c,  6, S22, 0xc040b340); /* 18 */
+	GG (c, d, a, b, 11, S23, 0x265e5a51); /* 19 */
+	GG (b, c, d, a,  0, S24, 0xe9b6c7aa); /* 20 */
+	GG (a, b, c, d,  5, S21, 0xd62f105d); /* 21 */
+	GG (d, a, b, c, 10, S22,  0x2441453); /* 22 */
+	GG (c, d, a, b, 15, S23, 0xd8a1e681); /* 23 */
+	GG (b, c, d, a,  4, S24, 0xe7d3fbc8); /* 24 */
+	GG (a, b, c, d,  9, S21, 0x21e1cde6); /* 25 */
+	GG (d, a, b, c, 14, S22, 0xc33707d6); /* 26 */
+	GG (c, d, a, b,  3, S23, 0xf4d50d87); /* 27 */
+	GG (b, c, d, a,  8, S24, 0x455a14ed); /* 28 */
+	GG (a, b, c, d, 13, S21, 0xa9e3e905); /* 29 */
+	GG (d, a, b, c,  2, S22, 0xfcefa3f8); /* 30 */
+	GG (c, d, a, b,  7, S23, 0x676f02d9); /* 31 */
+	GG (b, c, d, a, 12, S24, 0x8d2a4c8a); /* 32 */
+
+	/* Round 3 */
+	HH (a, b, c, d,  5, S31, 0xfffa3942); /* 33 */
+	HH (d, a, b, c,  8, S32, 0x8771f681); /* 34 */
+	HH (c, d, a, b, 11, S33, 0x6d9d6122); /* 35 */
+	HH (b, c, d, a, 14, S34, 0xfde5380c); /* 36 */
+	HH (a, b, c, d,  1, S31, 0xa4beea44); /* 37 */
+	HH (d, a, b, c,  4, S32, 0x4bdecfa9); /* 38 */
+	HH (c, d, a, b,  7, S33, 0xf6bb4b60); /* 39 */
+	HH (b, c, d, a, 10, S34, 0xbebfbc70); /* 40 */
+	HH (a, b, c, d, 13, S31, 0x289b7ec6); /* 41 */
+	HH (d, a, b, c,  0, S32, 0xeaa127fa); /* 42 */
+	HH (c, d, a, b,  3, S33, 0xd4ef3085); /* 43 */
+	HH (b, c, d, a,  6, S34,  0x4881d05); /* 44 */
+	HH (a, b, c, d,  9, S31, 0xd9d4d039); /* 45 */
+	HH (d, a, b, c, 12, S32, 0xe6db99e5); /* 46 */
+	HH (c, d, a, b, 15, S33, 0x1fa27cf8); /* 47 */
+	HH (b, c, d, a,  2, S34, 0xc4ac5665); /* 48 */
+
+	/* Round 4 */
+	II (a, b, c, d,  0, S41, 0xf4292244); /* 49 */
+	II (d, a, b, c,  7, S42, 0x432aff97); /* 50 */
+	II (c, d, a, b, 14, S43, 0xab9423a7); /* 51 */
+	II (b, c, d, a,  5, S44, 0xfc93a039); /* 52 */
+	II (a, b, c, d, 12, S41, 0x655b59c3); /* 53 */
+	II (d, a, b, c,  3, S42, 0x8f0ccc92); /* 54 */
+	II (c, d, a, b, 10, S43, 0xffeff47d); /* 55 */
+	II (b, c, d, a,  1, S44, 0x85845dd1); /* 56 */
+	II (a, b, c, d,  8, S41, 0x6fa87e4f); /* 57 */
+	II (d, a, b, c, 15, S42, 0xfe2ce6e0); /* 58 */
+	II (c, d, a, b,  6, S43, 0xa3014314); /* 59 */
+	II (b, c, d, a, 13, S44, 0x4e0811a1); /* 60 */
+	II (a, b, c, d,  4, S41, 0xf7537e82); /* 61 */
+	II (d, a, b, c, 11, S42, 0xbd3af235); /* 62 */
+	II (c, d, a, b,  2, S43, 0x2ad7d2bb); /* 63 */
+	II (b, c, d, a,  9, S44, 0xeb86d391); /* 64 */
+
+	A += a;  TRUNC32(A);
+	B += b;  TRUNC32(B);
+	C += c;  TRUNC32(C);
+	D += d;  TRUNC32(D);
+
+    } while (--blocks);
+    ctx->A = A;
+    ctx->B = B;
+    ctx->C = C;
+    ctx->D = D;
+}
+
+
+#ifdef MD5_DEBUG
+static char*
+ctx_dump(MD5_CTX* ctx)
+{
+    static char buf[1024];
+    sprintf(buf, "{A=%x,B=%x,C=%x,D=%x,%d,%d(%d)}",
+	    ctx->A, ctx->B, ctx->C, ctx->D,
+	    ctx->bytes_low, ctx->bytes_high, (ctx->bytes_low&0x3F));
+    return buf;
+}
+#endif
+
+
+static void
+MD5Update(MD5_CTX* ctx, const U8* buf, STRLEN len)
+{
+    STRLEN blocks;
+    STRLEN fill = ctx->bytes_low & 0x3F;
+
+#ifdef MD5_DEBUG  
+    static int ucount = 0;
+    fprintf(stderr,"%5i: Update(%s, %p, %d)\n", ++ucount, ctx_dump(ctx),
+	                                        buf, len);
+#endif
+
+    ctx->bytes_low += len;
+    if (ctx->bytes_low < len) /* wrap around */
+	ctx->bytes_high++;
+
+    if (fill) {
+	STRLEN missing = 64 - fill;
+	if (len < missing) {
+	    Copy(buf, ctx->buffer + fill, len, U8);
+	    return;
+	}
+	Copy(buf, ctx->buffer + fill, missing, U8);
+	MD5Transform(ctx, ctx->buffer, 1);
+	buf += missing;
+	len -= missing;
+    }
+
+    blocks = len >> 6;
+    if (blocks)
+	MD5Transform(ctx, buf, blocks);
+    if ( (len &= 0x3F)) {
+	Copy(buf + (blocks << 6), ctx->buffer, len, U8);
+    }
+}
+
+
+static void
+MD5Final(U8* digest, MD5_CTX *ctx)
+{
+    STRLEN fill = ctx->bytes_low & 0x3F;
+    STRLEN padlen = (fill < 56 ? 56 : 120) - fill;
+    U32 bits_low, bits_high;
+#ifdef MD5_DEBUG
+    fprintf(stderr,"       Final:  %s\n", ctx_dump(ctx));
+#endif
+    Copy(PADDING, ctx->buffer + fill, padlen, U8);
+    fill += padlen;
+
+    bits_low = ctx->bytes_low << 3;
+    bits_high = (ctx->bytes_high << 3) | (ctx->bytes_low  >> 29);
+#ifdef BYTESWAP
+    *(U32*)(ctx->buffer + fill) = BYTESWAP(bits_low);    fill += 4;
+    *(U32*)(ctx->buffer + fill) = BYTESWAP(bits_high);   fill += 4;
+#else
+    u2s(bits_low,  ctx->buffer + fill);   fill += 4;
+    u2s(bits_high, ctx->buffer + fill);   fill += 4;
+#endif
+
+    MD5Transform(ctx, ctx->buffer, fill >> 6);
+#ifdef MD5_DEBUG
+    fprintf(stderr,"       Result: %s\n", ctx_dump(ctx));
+#endif
+
+#ifdef BYTESWAP
+    *(U32*)digest = BYTESWAP(ctx->A);  digest += 4;
+    *(U32*)digest = BYTESWAP(ctx->B);  digest += 4;
+    *(U32*)digest = BYTESWAP(ctx->C);  digest += 4;
+    *(U32*)digest = BYTESWAP(ctx->D);
+#else
+    u2s(ctx->A, digest);
+    u2s(ctx->B, digest+4);
+    u2s(ctx->C, digest+8);
+    u2s(ctx->D, digest+12);
+#endif
+}
+
+
+static MD5_CTX* get_md5_ctx(SV* sv)
+{
+    if (sv_derived_from(sv, "Digest::MD5"))
+	return (MD5_CTX*)SvIV(SvRV(sv));
+    croak("Not a reference to a Digest::MD5 object");
+    return (MD5_CTX*)0; /* some compilers insist on a return value */
+}
+
+
+static char* hex_16(const unsigned char* from, char* to)
+{
+    static char *hexdigits = "0123456789abcdef";
+    const unsigned char *end = from + 16;
+    char *d = to;
+
+    while (from < end) {
+	*d++ = hexdigits[(*from >> 4)];
+	*d++ = hexdigits[(*from & 0x0F)];
+	from++;
+    }
+    *d = '\0';
+    return to;
+}
+
+static char* base64_16(const unsigned char* from, char* to)
+{
+    static char* base64 =
+	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+    const unsigned char *end = from + 16;
+    unsigned char c1, c2, c3;
+    char *d = to;
+
+    while (1) {
+	c1 = *from++;
+	*d++ = base64[c1>>2];
+	if (from == end) {
+	    *d++ = base64[(c1 & 0x3) << 4];
+	    break;
+	}
+	c2 = *from++;
+	c3 = *from++;
+	*d++ = base64[((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4)];
+	*d++ = base64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
+	*d++ = base64[c3 & 0x3F];
+    }
+    *d = '\0';
+    return to;
+}
+
+/* Formats */
+#define F_BIN 0
+#define F_HEX 1
+#define F_B64 2
+
+static SV* make_mortal_sv(const unsigned char *src, int type)
+{
+    STRLEN len;
+    char result[33];
+    char *ret;
+    
+    switch (type) {
+    case F_BIN:
+	ret = (char*)src;
+	len = 16;
+	break;
+    case F_HEX:
+	ret = hex_16(src, result);
+	len = 32;
+	break;
+    case F_B64:
+	ret = base64_16(src, result);
+	len = 22;
+	break;
+    default:
+	croak("Bad convertion type (%d)", type);
+	break;
+    }
+    return sv_2mortal(newSVpv(ret,len));
+}
+
+
+/********************************************************************/
+
+typedef PerlIO* InputStream;
+
+MODULE = Digest::MD5		PACKAGE = Digest::MD5
+
+PROTOTYPES: DISABLE
+
+void
+new(xclass)
+	SV* xclass
+    PREINIT:
+	MD5_CTX* context;
+    PPCODE:
+	if (!SvROK(xclass)) {
+	    STRLEN my_na;
+	    char *sclass = SvPV(xclass, my_na);
+	    New(55, context, 1, MD5_CTX);
+	    ST(0) = sv_newmortal();
+	    sv_setref_pv(ST(0), sclass, (void*)context);
+	    SvREADONLY_on(SvRV(ST(0)));
+	} else {
+	    context = get_md5_ctx(xclass);
+	}
+        MD5Init(context);
+	XSRETURN(1);
+
+void
+DESTROY(context)
+	MD5_CTX* context
+    CODE:
+        Safefree(context);
+
+void
+add(self, ...)
+	SV* self
+    PREINIT:
+	MD5_CTX* context = get_md5_ctx(self);
+	int i;
+	unsigned char *data;
+	STRLEN len;
+    PPCODE:
+	for (i = 1; i < items; i++) {
+	    data = (unsigned char *)(SvPV(ST(i), len));
+	    MD5Update(context, data, len);
+	}
+	XSRETURN(1);  /* self */
+
+void
+addfile(self, fh)
+	SV* self
+	InputStream fh
+    PREINIT:
+	MD5_CTX* context = get_md5_ctx(self);
+	STRLEN fill = context->bytes_low & 0x3F;
+	unsigned char buffer[4096];
+	int  n;
+    CODE:
+        if (fill) {
+	    /* The MD5Update() function is faster if it can work with
+	     * complete blocks.  This will fill up any buffered block
+	     * first.
+	     */
+	    STRLEN missing = 64 - fill;
+	    if ( (n = PerlIO_read(fh, buffer, missing)))
+		MD5Update(context, buffer, n);
+	    else
+		XSRETURN(1);  /* self */
+	}
+
+	/* Process blocks until EOF */
+        while ( (n = PerlIO_read(fh, buffer, sizeof(buffer)))) {
+	    MD5Update(context, buffer, n);
+	}
+	XSRETURN(1);  /* self */
+
+void
+digest(context)
+	MD5_CTX* context
+    ALIAS:
+	Digest::MD5::digest    = F_BIN
+	Digest::MD5::hexdigest = F_HEX
+	Digest::MD5::b64digest = F_B64
+    PREINIT:
+	unsigned char digeststr[16];
+    PPCODE:
+        MD5Final(digeststr, context);
+	MD5Init(context);  /* In case it is reused */
+        ST(0) = make_mortal_sv(digeststr, ix);
+        XSRETURN(1);
+
+void
+md5(...)
+    ALIAS:
+	Digest::MD5::md5        = F_BIN
+	Digest::MD5::md5_hex    = F_HEX
+	Digest::MD5::md5_base64 = F_B64
+    PREINIT:
+	MD5_CTX ctx;
+	int i;
+	unsigned char *data;
+        STRLEN len;
+	unsigned char digeststr[16];
+    PPCODE:
+	MD5Init(&ctx);
+	for (i = 0; i < items; i++) {
+	    data = (unsigned char *)(SvPV(ST(i), len));
+	    MD5Update(&ctx, data, len);
+	}
+	MD5Final(digeststr, &ctx);
+        ST(0) = make_mortal_sv(digeststr, ix);
+        XSRETURN(1);

Added: trunk/orca/packages/Digest-MD5-2.07/examples/twdigest.pl
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/examples/twdigest.pl	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/examples/twdigest.pl	Sat Jul 13 18:45:59 2002
@@ -0,0 +1,35 @@
+#!/usr/local/bin/perl
+
+use MD5;
+
+#
+# twdigest -- format MD5 digest like TripWire does
+#
+# This converts the md5->digest binary string to
+# 64-radix ascii, given the base-vector:
+# 0 - 9, A - Z, a - z, :, .
+#
+
+sub twdigest {
+    my($digest) = @_;
+    my(@chunks, $bits);
+
+    # Convert to ASCII bit-string
+    $bits = unpack("B*", $digest);
+
+    # Round up length to multiple of 6 by prepending zeros
+    $bits = ("0" x ((6 - (length($bits) % 6)) % 6)) . $bits;
+
+    # Split into 6-bit chunks
+    @chunks = grep {$_ ne ''} (split(/(.{6})/, $bits, -1));
+
+    # Convert each 6-bit value to a single character
+    foreach (@chunks)
+    {
+	$_ = pack("B8", "00" . $_);
+	tr/\000-\011\012-\043\044-\075\076\077/0-9A-Za-z:./;
+    }
+
+    # Join all of the chunks into one string
+    join('', @chunks);
+}

Added: trunk/orca/packages/Digest-MD5-2.07/examples/mddriver.pl
==============================================================================
--- trunk/orca/packages/Digest-MD5-2.07/examples/mddriver.pl	(original)
+++ trunk/orca/packages/Digest-MD5-2.07/examples/mddriver.pl	Sat Jul 13 18:45:59 2002
@@ -0,0 +1,69 @@
+#!/usr/local/bin/perl
+# SCCS ID @(#)mddriver.pl	1.3 95/05/01
+
+require 'getopts.pl';
+use MD5;
+sub DoTest;
+
+&Getopts('s:x');
+
+$md5 = new MD5;
+
+if (defined($opt_s))
+{
+    $md5->add($opt_s);
+    $digest = $md5->digest();
+    print("MD5(\"$opt_s\") = " . unpack("H*", $digest) . "\n");
+}
+elsif ($opt_x)
+{
+    DoTest("", "d41d8cd98f00b204e9800998ecf8427e");
+    DoTest("a", "0cc175b9c0f1b6a831c399e269772661");
+    DoTest("abc", "900150983cd24fb0d6963f7d28e17f72");
+    DoTest("message digest", "f96b697d7cb7938d525a2f31aaf161d0");
+    DoTest("abcdefghijklmnopqrstuvwxyz", "c3fcd3d76192e4007dfb496cca67e13b");
+    DoTest("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+	   "d174ab98d277d9f5a5611c2c9f419d9f");
+    DoTest("12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+	   "57edf4a22be3c955ac49da2e2107b67a");
+}
+else
+{
+    if ($#ARGV >= 0)
+    {
+	foreach $ARGV (@ARGV)
+	{
+	    die "Can't open file '$ARGV' ($!)\n" unless open(ARGV, $ARGV);
+
+	    $md5->reset();
+	    $md5->addfile(ARGV);
+	    $hex = $md5->hexdigest();
+	    print "MD5($ARGV) = $hex\n";
+
+	    close(ARGV);
+	}
+    }
+    else
+    {
+	$md5->reset();
+	$md5->addfile(STDIN);
+	$hex = $md5->hexdigest();
+
+	print "$hex\n";
+    }
+}
+
+exit 0;
+
+sub DoTest
+{
+    my ($str, $expect) = @_;
+    my ($digest, $hex);
+    my $md5 = new MD5;
+
+    $md5->add($str);
+    $digest = $md5->digest();
+    $hex = unpack("H*", $digest);
+
+    print "MD5(\"$str\") =>\nEXPECT: $expect\nRESULT: $hex\n"
+}

Added: trunk/orca/packages/rrdtool-0.99.29.1/Makefile.dist
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/Makefile.dist	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/Makefile.dist	Sat Jul 13 18:45:59 2002
@@ -0,0 +1,41 @@
+SHELL = /bin/sh
+.SUFFIXES:
+.SUFFIXES: .c .o .pl .pm .pod .html .man
+
+# variables we got from configure
+# (you can mess with these, if you want)
+
+###
+### Things you might NOT want to play with ... 
+###
+
+VER  = 0.99.29
+PVER = 0.99029 
+
+ARCHIVE = rrdtool-$(VER).tar.gz
+DIRNAME = rrdtool-$(VER)
+
+perl-piped/examples/%.pl.in: perl-piped/examples/%.pl
+	perl -p -e 's|^#!\s*/\S+perl\S* +|#! \@PERL\@ |' $< > $@
+
+perl-shared/examples/%.pl.in: perl-shared/examples/%.pl
+	perl -p -e 's|^#!\s*/\S+perl\S* +|#! \@PERL\@ |' $< > $@
+
+all:	dist
+
+docs:
+	(cd doc && $(MAKE))
+versync:
+	perl -i -p -e 's|VERSION\s*=\s*[\d.]+|VERSION = $(PVER)|' perl-piped/RRDp.pm perl-shared/RRDs.pm
+	perl -i -p -e 's|RRDTOOL\s+\d+\.\d+\.\d+|RRDTOOL $(VER)|' src/*.c src/*.h
+
+tar:	perl-piped/examples/piped-demo.pl.in  perl-shared/examples/shared-demo.pl.in docs versync
+
+	(cd .. ; ln -s rrdtool $(DIRNAME))
+	(cd .. ; sed -e "s/^/$(DIRNAME)\//" $(DIRNAME)/MANIFEST | xargs tar zcvf $(DIRNAME)/archive/$(ARCHIVE) --exclude="*~")
+	rm ../$(DIRNAME)
+
+dist: tar
+	scp CHANGES tardis:/home/oetiker/public_html/webtools/rrdtool/pub/
+	cat archive/$(ARCHIVE) | ssh tardis dd of=/home/oetiker/public_html/webtools/rrdtool/pub/$(ARCHIVE)
+

Added: trunk/orca/packages/rrdtool-0.99.29.1/configure
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/configure	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/configure	Sat Jul 13 18:46:00 2002
@@ -0,0 +1,2138 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13 
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval "$ac_prev=\$ac_option"
+    ac_prev=
+    continue
+  fi
+
+  case "$ac_option" in
+  -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) ac_optarg= ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case "$ac_option" in
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir="$ac_optarg" ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build="$ac_optarg" ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file="$ac_optarg" ;;
+
+  -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+  | --da=*)
+    datadir="$ac_optarg" ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    eval "enable_${ac_feature}=no" ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix="$ac_optarg" ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he)
+    # Omit some internal or obsolete options to make the list less imposing.
+    # This message is too long to be a string in the A/UX 3.1 sh.
+    cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+  --cache-file=FILE       cache test results in FILE
+  --help                  print this message
+  --no-create             do not create output files
+  --quiet, --silent       do not print \`checking...' messages
+  --version               print the version of autoconf that created configure
+Directory and file names:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [same as prefix]
+  --bindir=DIR            user executables in DIR [EPREFIX/bin]
+  --sbindir=DIR           system admin executables in DIR [EPREFIX/sbin]
+  --libexecdir=DIR        program executables in DIR [EPREFIX/libexec]
+  --datadir=DIR           read-only architecture-independent data in DIR
+                          [PREFIX/share]
+  --sysconfdir=DIR        read-only single-machine data in DIR [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data in DIR
+                          [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data in DIR [PREFIX/var]
+  --libdir=DIR            object code libraries in DIR [EPREFIX/lib]
+  --includedir=DIR        C header files in DIR [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc in DIR [/usr/include]
+  --infodir=DIR           info documentation in DIR [PREFIX/info]
+  --mandir=DIR            man documentation in DIR [PREFIX/man]
+  --srcdir=DIR            find the sources in DIR [configure dir or ..]
+  --program-prefix=PREFIX prepend PREFIX to installed program names
+  --program-suffix=SUFFIX append SUFFIX to installed program names
+  --program-transform-name=PROGRAM
+                          run sed PROGRAM on installed program names
+EOF
+    cat << EOF
+Host type:
+  --build=BUILD           configure for building on BUILD [BUILD=HOST]
+  --host=HOST             configure for HOST [guessed]
+  --target=TARGET         configure for TARGET [TARGET=HOST]
+Features and packages:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --x-includes=DIR        X include files are in DIR
+  --x-libraries=DIR       X library files are in DIR
+EOF
+    if test -n "$ac_help"; then
+      echo "--enable and --with options recognized:$ac_help"
+    fi
+    exit 0 ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host="$ac_optarg" ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir="$ac_optarg" ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir="$ac_optarg" ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir="$ac_optarg" ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir="$ac_optarg" ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst \
+  | --locals | --local | --loca | --loc | --lo)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+  | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+    localstatedir="$ac_optarg" ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir="$ac_optarg" ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir="$ac_optarg" ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix="$ac_optarg" ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix="$ac_optarg" ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix="$ac_optarg" ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name="$ac_optarg" ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir="$ac_optarg" ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir="$ac_optarg" ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site="$ac_optarg" ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir="$ac_optarg" ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir="$ac_optarg" ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target="$ac_optarg" ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers)
+    echo "configure generated by autoconf version 2.13"
+    exit 0 ;;
+
+  -with-* | --with-*)
+    ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "with_${ac_package}='$ac_optarg'" ;;
+
+  -without-* | --without-*)
+    ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    eval "with_${ac_package}=no" ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes="$ac_optarg" ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries="$ac_optarg" ;;
+
+  -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+    ;;
+
+  *)
+    if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+      echo "configure: warning: $ac_option: invalid host type" 1>&2
+    fi
+    if test "x$nonopt" != xNONE; then
+      { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+    fi
+    nonopt="$ac_option"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+  exec 6>/dev/null
+else
+  exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+  case "$ac_arg" in
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c) ;;
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+  *" "*|*"	"*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+  ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+  *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+  esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set.  These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}"   = set; then LANG=C;   export LANG;   fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}"    = set; then LC_CTYPE=C;    export LC_CTYPE;    fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=src/rrd_tool.c
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then its parent.
+  ac_prog=$0
+  ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+  test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+  srcdir=$ac_confdir
+  if test ! -r $srcdir/$ac_unique_file; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+  if test "$ac_srcdir_defaulted" = yes; then
+    { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+  else
+    { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+  fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+  if test "x$prefix" != xNONE; then
+    CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+  else
+    CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+  fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+  if test -r "$ac_site_file"; then
+    echo "loading site script $ac_site_file"
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  echo "loading cache $cache_file"
+  . $cache_file
+else
+  echo "creating cache $cache_file"
+  > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+  # Stardent Vistra SVR4 grep lacks -e, says ghazi at caip.rutgers.edu.
+  if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+    ac_n= ac_c='
+' ac_t='	'
+  else
+    ac_n=-n ac_c= ac_t=
+  fi
+else
+  ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:530: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="gcc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:560: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_prog_rejected=no
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+        ac_prog_rejected=yes
+	continue
+      fi
+      ac_cv_prog_CC="cc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# -gt 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    set dummy "$ac_dir/$ac_word" "$@"
+    shift
+    ac_cv_prog_CC="$@"
+  fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+  if test -z "$CC"; then
+    case "`uname -s`" in
+    *win32* | *WIN32*)
+      # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:611: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="cl"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+ ;;
+    esac
+  fi
+  test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:643: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 654 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:659: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  ac_cv_prog_cc_works=yes
+  # If we can't run a trivial program, we are probably using a cross compiler.
+  if (./conftest; exit) 2>/dev/null; then
+    ac_cv_prog_cc_cross=no
+  else
+    ac_cv_prog_cc_cross=yes
+  fi
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+  { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:685: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:690: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.c <<EOF
+#ifdef __GNUC__
+  yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:699: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+  ac_cv_prog_gcc=yes
+else
+  ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:718: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+  ac_cv_prog_cc_g=yes
+else
+  ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:750: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    # This must be in double quotes, not single quotes, because CPP may get
+  # substituted into the Makefile and "${CC-cc}" will confuse make.
+  CPP="${CC-cc} -E"
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp.
+  cat > conftest.$ac_ext <<EOF
+#line 765 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:771: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -E -traditional-cpp"
+  cat > conftest.$ac_ext <<EOF
+#line 782 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:788: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -nologo -E"
+  cat > conftest.$ac_ext <<EOF
+#line 799 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:805: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+  ac_cv_prog_CPP="$CPP"
+fi
+  CPP="$ac_cv_prog_CPP"
+else
+  ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+  if test -f $ac_dir/install-sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f $ac_dir/install.sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:860: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    IFS="${IFS= 	}"; ac_save_IFS="$IFS"; IFS=":"
+  for ac_dir in $PATH; do
+    # Account for people who put trailing slashes in PATH elements.
+    case "$ac_dir/" in
+    /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+    *)
+      # OSF1 and SCO ODT 3.0 have their own names for install.
+      # Don't use installbsd from OSF since it installs stuff as root
+      # by default.
+      for ac_prog in ginstall scoinst install; do
+        if test -f $ac_dir/$ac_prog; then
+	  if test $ac_prog = install &&
+            grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  else
+	    ac_cv_path_install="$ac_dir/$ac_prog -c"
+	    break 2
+	  fi
+	fi
+      done
+      ;;
+    esac
+  done
+  IFS="$ac_save_IFS"
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL="$ac_cv_path_install"
+  else
+    # As a last resort, use the slow shell script.  We don't cache a
+    # path for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the path is relative.
+    INSTALL="$ac_install_sh"
+  fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6
+echo "configure:913: checking whether ln -s works" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  rm -f conftestdata
+if ln -s X conftestdata 2>/dev/null
+then
+  rm -f conftestdata
+  ac_cv_prog_LN_S="ln -s"
+else
+  ac_cv_prog_LN_S=ln
+fi
+fi
+LN_S="$ac_cv_prog_LN_S"
+if test "$ac_cv_prog_LN_S" = "ln -s"; then
+  echo "$ac_t""yes" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:934: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftestmake <<\EOF
+all:
+	@echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+  eval ac_cv_prog_make_${ac_make}_set=yes
+else
+  eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  SET_MAKE=
+else
+  echo "$ac_t""no" 1>&6
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+# Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:963: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_RANLIB="ranlib"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+  echo "$ac_t""$RANLIB" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+# Extract the first word of "perl", so it can be a program name with args.
+set dummy perl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:993: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_PERL'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$PERL" in
+  /*)
+  ac_cv_path_PERL="$PERL" # Let the user override the test with a path.
+  ;;
+  ?:/*)			 
+  ac_cv_path_PERL="$PERL" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_PERL="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_PERL" && ac_cv_path_PERL="no"
+  ;;
+esac
+fi
+PERL="$ac_cv_path_PERL"
+if test -n "$PERL"; then
+  echo "$ac_t""$PERL" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+
+echo $ac_n "checking for acos in -lm""... $ac_c" 1>&6
+echo "configure:1029: checking for acos in -lm" >&5
+ac_lib_var=`echo m'_'acos | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lm  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1037 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char acos();
+
+int main() {
+acos()
+; return 0; }
+EOF
+if { (eval echo configure:1048: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo m | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lm $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:1077: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1082 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1090: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  ac_cv_header_stdc=yes
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1107 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "memchr" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1125 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "free" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+  :
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1146 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:1157: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+  cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+for ac_hdr in fcntl.h malloc.h unistd.h math.h sys/time.h sys/times.h sys/resource.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1184: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1189 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1194: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+
+echo $ac_n "checking for working const""... $ac_c" 1>&6
+echo "configure:1222: checking for working const" >&5
+if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1227 "configure"
+#include "confdefs.h"
+
+int main() {
+
+/* Ultrix mips cc rejects this.  */
+typedef int charset[2]; const charset x;
+/* SunOS 4.1.1 cc rejects this.  */
+char const *const *ccp;
+char **p;
+/* NEC SVR4.0.2 mips cc rejects this.  */
+struct point {int x, y;};
+static struct point const zero = {0,0};
+/* AIX XL C 1.02.0.0 rejects this.
+   It does not let you subtract one const X* pointer from another in an arm
+   of an if-expression whose if-part is not a constant expression */
+const char *g = "string";
+ccp = &g + (g ? g-g : 0);
+/* HPUX 7.0 cc rejects these. */
+++ccp;
+p = (char**) ccp;
+ccp = (char const *const *) p;
+{ /* SCO 3.2v4 cc rejects this.  */
+  char *t;
+  char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+  *t++ = 0;
+}
+{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
+  int x[] = {25, 17};
+  const int *foo = &x[0];
+  ++foo;
+}
+{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+  typedef const int *iptr;
+  iptr p = 0;
+  ++p;
+}
+{ /* AIX XL C 1.02.0.0 rejects this saying
+     "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+  struct s { int j; const int *ap[3]; };
+  struct s *b; b->j = 5;
+}
+{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+  const int foo = 10;
+}
+
+; return 0; }
+EOF
+if { (eval echo configure:1276: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_c_const=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_c_const=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_c_const" 1>&6
+if test $ac_cv_c_const = no; then
+  cat >> confdefs.h <<\EOF
+#define const 
+EOF
+
+fi
+
+echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
+echo "configure:1297: checking whether time.h and sys/time.h may both be included" >&5
+if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1302 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+int main() {
+struct tm *tp;
+; return 0; }
+EOF
+if { (eval echo configure:1311: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_header_time=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_time=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_time" 1>&6
+if test $ac_cv_header_time = yes; then
+  cat >> confdefs.h <<\EOF
+#define TIME_WITH_SYS_TIME 1
+EOF
+
+fi
+
+echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6
+echo "configure:1332: checking whether struct tm is in sys/time.h or time.h" >&5
+if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1337 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <time.h>
+int main() {
+struct tm *tp; tp->tm_sec;
+; return 0; }
+EOF
+if { (eval echo configure:1345: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_tm=time.h
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_tm=sys/time.h
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_tm" 1>&6
+if test $ac_cv_struct_tm = sys/time.h; then
+  cat >> confdefs.h <<\EOF
+#define TM_IN_SYS_TIME 1
+EOF
+
+fi
+
+
+if test ${CC-gcc} = gcc; then
+  rd_cv_prog_hpcc=no
+oCFLAGS_EXTRA=$CFLAGS_EXTRA
+CFLAGS_EXTRA="$CFLAGS_EXTRA -Wall -pedantic -fPIC"
+echo $ac_n "checking if we can use GCC-specific compiler options""... $ac_c" 1>&6
+echo "configure:1371: checking if we can use GCC-specific compiler options" >&5
+if eval "test \"`echo '$''{'rd_cv_gcc_opt'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  
+cat > conftest.$ac_ext <<EOF
+#line 1377 "configure"
+#include "confdefs.h"
+
+int main() {
+return 0 
+; return 0; }
+EOF
+if { (eval echo configure:1384: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  rd_cv_gcc_opt=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  rd_cv_gcc_opt=no 
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$rd_cv_gcc_opt" 1>&6
+if test $rd_cv_gcc_opt = no; then
+	CFLAGS_EXTRA=$oCFLAGS_EXTRA
+fi
+
+else
+echo $ac_n "checking if we should use HP compiler options""... $ac_c" 1>&6
+echo "configure:1404: checking if we should use HP compiler options" >&5
+if eval "test \"`echo '$''{'rd_cv_prog_hpcc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  
+cat > conftest.c <<EOF
+#ifdef _HPUX_SOURCE
+  yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -Ae -z -E conftest.c'; { (eval echo configure:1414: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1
+then
+  rd_cv_prog_hpcc=yes
+else
+  rd_cv_prog_hpcc=no
+fi
+fi
+
+echo "$ac_t""$rd_cv_prog_hpcc" 1>&6
+fi
+if test $rd_cv_prog_hpcc = yes; then
+	CFLAGS_EXTRA="$CFLAGS_EXTRA -Ae -z"
+fi
+
+echo $ac_n "checking for strftime""... $ac_c" 1>&6
+echo "configure:1429: checking for strftime" >&5
+if eval "test \"`echo '$''{'ac_cv_func_strftime'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1434 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char strftime(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char strftime();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_strftime) || defined (__stub___strftime)
+choke me
+#else
+strftime();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1457: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_strftime=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_strftime=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'strftime`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_STRFTIME 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+# strftime is in -lintl on SCO UNIX.
+echo $ac_n "checking for strftime in -lintl""... $ac_c" 1>&6
+echo "configure:1479: checking for strftime in -lintl" >&5
+ac_lib_var=`echo intl'_'strftime | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lintl  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1487 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char strftime();
+
+int main() {
+strftime()
+; return 0; }
+EOF
+if { (eval echo configure:1498: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_STRFTIME 1
+EOF
+
+LIBS="-lintl $LIBS"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+echo $ac_n "checking for vprintf""... $ac_c" 1>&6
+echo "configure:1525: checking for vprintf" >&5
+if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1530 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char vprintf(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char vprintf();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_vprintf) || defined (__stub___vprintf)
+choke me
+#else
+vprintf();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1553: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_vprintf=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_vprintf=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'vprintf`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_VPRINTF 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test "$ac_cv_func_vprintf" != yes; then
+echo $ac_n "checking for _doprnt""... $ac_c" 1>&6
+echo "configure:1577: checking for _doprnt" >&5
+if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1582 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char _doprnt(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char _doprnt();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub__doprnt) || defined (__stub____doprnt)
+choke me
+#else
+_doprnt();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1605: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func__doprnt=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func__doprnt=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'_doprnt`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_DOPRNT 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+
+for ac_func in mktime getrusage gettimeofday
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:1633: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1638 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1661: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+
+oCFLAGS_EXTRA=$CFLAGS_EXTRA
+echo $ac_n "checking if the compiler does proper IEEE math""... $ac_c" 1>&6
+echo "configure:1688: checking if the compiler does proper IEEE math" >&5
+if eval "test \"`echo '$''{'rd_cv_ieee_works'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  :
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1696 "configure"
+#include "confdefs.h"
+int main(void){
+              double a=0.0/0.0,b=0.0,c;
+              c=a/b;if (c==a) c=a;return isnan(a/c)?0:1;
+             }
+EOF
+if { (eval echo configure:1703: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  rd_cv_ieee_works=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  
+echo "$ac_t""no it does not" 1>&6
+CFLAGS_EXTRA="$CFLAGS_EXTRA -ieee"
+echo $ac_n "checking if the compiler does proper IEEE math with -ieee""... $ac_c" 1>&6
+echo "configure:1714: checking if the compiler does proper IEEE math with -ieee" >&5
+if eval "test \"`echo '$''{'rd_cv_ieee_switch'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  :
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1722 "configure"
+#include "confdefs.h"
+int main(void){
+              double a=0.0/0.0,b=0.0,c;
+              c=a/b;if (c==a) c=a;return isnan(a/c)?0:1;   
+             }
+EOF
+if { (eval echo configure:1729: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  rd_cv_ieee_switch=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  rd_cv_ieee_switch=no;
+echo "$ac_t""nope" 1>&6
+echo "--------------------------------------------------------------"
+echo "Your Compiler does not do propper IEEE math ... "
+echo "Please find out how to make IEEE math work with your Compiler"
+echo "And let me know (oetiker at ee.ethz.ch)"
+echo ""
+exit 1
+
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$rd_cv_ieee_switch" 1>&6
+
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$rd_cv_ieee_works" 1>&6
+
+CFLAGS_EXTRA=$oCFLAGS_EXTRA
+
+if test x$rd_cv_ieee_switch = xyes; then
+	CFLAGS_EXTRA="$CFLAGS_EXTRA -ieee"
+fi
+
+
+
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs.  It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already.  You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+  case `(ac_space=' '; set | grep ac_space) 2>&1` in
+  *ac_space=\ *)
+    # `set' does not quote correctly, so add quotes (double-quote substitution
+    # turns \\\\ into \\, and sed turns \\ into \).
+    sed -n \
+      -e "s/'/'\\\\''/g" \
+      -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+    ;;
+  *)
+    # `set' quotes correctly as required by POSIX, so do not add quotes.
+    sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+    ;;
+  esac >> confcache
+if cmp -s $cache_file confcache; then
+  :
+else
+  if test -w $cache_file; then
+    echo "updating cache $cache_file"
+    cat confcache > $cache_file
+  else
+    echo "not updating unwritable cache $cache_file"
+  fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[ 	]*VPATH[ 	]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+  case "\$ac_option" in
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+    exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+  -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+    echo "$CONFIG_STATUS generated by autoconf version 2.13"
+    exit 0 ;;
+  -help | --help | --hel | --he | --h)
+    echo "\$ac_cs_usage"; exit 0 ;;
+  *) echo "\$ac_cs_usage"; exit 1 ;;
+  esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "Makefile src/Makefile gd1.2/Makefile doc/GNUmakefile perl-shared/examples/shared-demo.pl perl-piped/examples/piped-demo.pl config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@CC@%$CC%g
+s%@CPP@%$CPP%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@LN_S@%$LN_S%g
+s%@SET_MAKE@%$SET_MAKE%g
+s%@RANLIB@%$RANLIB%g
+s%@PERL@%$PERL%g
+s%@CFLAGS_EXTRA@%$CFLAGS_EXTRA%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+  if test $ac_beg -gt 1; then
+    sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+  else
+    sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+  fi
+  if test ! -s conftest.s$ac_file; then
+    ac_more_lines=false
+    rm -f conftest.s$ac_file
+  else
+    if test -z "$ac_sed_cmds"; then
+      ac_sed_cmds="sed -f conftest.s$ac_file"
+    else
+      ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+    fi
+    ac_file=`expr $ac_file + 1`
+    ac_beg=$ac_end
+    ac_end=`expr $ac_end + $ac_max_sed_cmds`
+  fi
+done
+if test -z "$ac_sed_cmds"; then
+  ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile src/Makefile gd1.2/Makefile doc/GNUmakefile perl-shared/examples/shared-demo.pl perl-piped/examples/piped-demo.pl"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+  # Remove last slash and all that follows it.  Not all systems have dirname.
+  ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+  if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+    # The file is in a subdirectory.
+    test ! -d "$ac_dir" && mkdir "$ac_dir"
+    ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+    # A "../" for each directory in $ac_dir_suffix.
+    ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+  else
+    ac_dir_suffix= ac_dots=
+  fi
+
+  case "$ac_given_srcdir" in
+  .)  srcdir=.
+      if test -z "$ac_dots"; then top_srcdir=.
+      else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+  /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+  *) # Relative path.
+    srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+    top_srcdir="$ac_dots$ac_given_srcdir" ;;
+  esac
+
+  case "$ac_given_INSTALL" in
+  [/$]*) INSTALL="$ac_given_INSTALL" ;;
+  *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+  esac
+
+  echo creating "$ac_file"
+  rm -f "$ac_file"
+  configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+  case "$ac_file" in
+  *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+  *) ac_comsub= ;;
+  esac
+
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ 	]*\)#\([ 	]*define[ 	][ 	]*\)'
+ac_dB='\([ 	][ 	]*\)[^ 	]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ 	]*\)#\([ 	]*\)undef\([ 	][ 	]*\)'
+ac_uB='\([ 	]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ 	]*\)#\([ 	]*\)undef\([ 	][ 	]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <<EOF
+  CONFIG_HEADERS="config.h"
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  echo creating $ac_file
+
+  rm -f conftest.frag conftest.in conftest.out
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h.  And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments.  This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[ 	]*#[ 	]*undef[ 	][ 	]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+  ac_lines=`grep -c . conftest.vals`
+  # grep -c gives empty output for an empty file on some AIX systems.
+  if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+  # Write a limited-size here document to conftest.frag.
+  echo '  cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+  sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+  echo 'CEOF
+  sed -f conftest.frag conftest.in > conftest.out
+  rm -f conftest.in
+  mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+  sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+  rm -f conftest.vals
+  mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+  rm -f conftest.frag conftest.h
+  echo "/* $ac_file.  Generated automatically by configure.  */" > conftest.h
+  cat conftest.in >> conftest.h
+  rm -f conftest.in
+  if cmp -s $ac_file conftest.h 2>/dev/null; then
+    echo "$ac_file is unchanged"
+    rm -f conftest.h
+  else
+    # Remove last slash and all that follows it.  Not all systems have dirname.
+      ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+      if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+      # The file is in a subdirectory.
+      test ! -d "$ac_dir" && mkdir "$ac_dir"
+    fi
+    rm -f $ac_file
+    mv conftest.h $ac_file
+  fi
+fi; done
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+chmod +x perl-*/examples/*.pl
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
+
+echo $ac_n "checking in""... $ac_c" 1>&6
+echo "configure:2134: checking in" >&5
+echo "$ac_t""and out again" 1>&6
+
+echo $ac_n "ordering CD from http://cdnow.com/gift/oetiker@ee.ethz.ch""... $ac_c" 1>&6
+sleep 3
+echo "$ac_t""just kidding ;-)" 1>&6

Added: trunk/orca/packages/rrdtool-0.99.29.1/Makefile.in
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/Makefile.in	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/Makefile.in	Sat Jul 13 18:46:00 2002
@@ -0,0 +1,53 @@
+# things that the GNU standards document suggests all makefiles
+# should have.
+SHELL = /bin/sh
+ at SET_MAKE@
+INSTALL = @INSTALL@
+PREFIX = @prefix@
+CFLAGS = @CFLAGS@
+
+.SUFFIXES:
+.SUFFIXES: .c .o .pl .pm .pod .html .man
+
+all:
+	(cd gd1.2 && $(MAKE) CFLAGS="$(CFLAGS)" libgd.a)
+	(cd src && $(MAKE) CFLAGS="$(CFLAGS)")
+	$(MAKE) perl-piped perl-shared
+	(cd doc && $(MAKE))
+
+perl-piped: perl-piped/Makefile
+	(cd perl-piped && $(MAKE) OPTIMIZE="$(CFLAGS)")
+
+perl-shared: perl-shared/Makefile
+	(cd perl-shared && $(MAKE) OPTIMIZE="$(CFLAGS)")
+
+
+perl-piped/Makefile: perl-piped/Makefile.PL
+	(cd perl-piped && @PERL@ Makefile.PL)
+
+perl-shared/Makefile: perl-shared/Makefile.PL
+	(cd perl-shared && @PERL@ Makefile.PL)
+
+clean:
+	(cd gd1.2 && $(MAKE) clean)
+	(cd src && $(MAKE) clean)
+
+distclean realclean:
+	(cd gd1.2 && $(MAKE) realclean)
+	(cd src && $(MAKE) realclean)
+	@if test -f perl-shared/Makefile; then \
+		echo '(cd perl-shared; $(MAKE) clean)' ; \
+		(cd perl-shared; $(MAKE) clean); \
+	fi
+	@if test -f perl-piped/Makefile; then \
+		echo '(cd perl-piped; $(MAKE) clean)' ; \
+		(cd perl; $(MAKE) clean); \
+	fi
+	-rm -f config.cache config.h config.log config.status Makefile
+
+install: all
+	(cd perl-piped && $(MAKE) install)
+	(cd perl-shared && $(MAKE) install)
+	$(INSTALL) -m 755 -o root -g root src/rrdtool $(PREFIX)/bin
+	$(INSTALL) -m 644 -o root -g root doc/*.3 $(PREFIX)/man/man3
+	$(INSTALL) -m 644 -o root -g root doc/*.1 $(PREFIX)/man/man1

Added: trunk/orca/packages/rrdtool-0.99.29.1/configure.in
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/configure.in	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/configure.in	Sat Jul 13 18:46:00 2002
@@ -0,0 +1,138 @@
+dnl This file is the master file for the configure process.
+dnl It is only edited by developers. If you are trying to compile
+dnl rrd_tool, use "sh configure" instead of this file.
+dnl
+dnl From it, config.h.in and configure are both made.
+dnl To make them, you (a developer) will need to install the latest
+dnl versions of GNU m4 and GNU autoconf. Then you run "autoheader"
+dnl in the distribution directory to make config.h.in, and
+dnl "autoconf" to make the configure script. These two files
+dnl must be shipped with the distribution; end users should not need
+dnl m4 and autoconf to be able to compile. All they need is
+dnl to run "sh configure".
+dnl
+dnl The format of this file is basically one macro to a line.
+dnl Text that is not a macro and not a comment is passed straight
+dnl through to the configure script.
+dnl
+dnl Comments are "dnl" followed by comments. It means delete
+dnl to newline.
+dnl
+dnl When you want to pass a literal bit of text to a macro as
+dnl an argument, you use square brackets. Thus, you cannot use
+dnl the bracket shorthand for /bin/test... you must use the
+dnl actual program name.
+dnl
+dnl Our tests do not cache. This is because I'm too lazy to
+dnl figure out how to use the caching macros. There's not many,
+dnl so it's not a big problem.
+dnl
+dnl 	-jra
+
+AC_INIT(src/rrd_tool.c)
+AC_CONFIG_HEADER(config.h)
+
+dnl Check for programs.
+AC_PROG_CC
+AC_PROG_CPP
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+AC_PROG_RANLIB
+AC_PATH_PROG(PERL, perl, no)
+
+
+dnl Checks for libraries.
+AC_CHECK_LIB(m, acos)
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS(fcntl.h malloc.h unistd.h math.h sys/time.h sys/times.h sys/resource.h)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_HEADER_TIME
+AC_STRUCT_TM
+
+dnl If CC is not set we assume gcc
+if test ${CC-gcc} = gcc; then
+  rd_cv_prog_hpcc=no
+oCFLAGS_EXTRA=$CFLAGS_EXTRA
+CFLAGS_EXTRA="$CFLAGS_EXTRA -Wall -pedantic -fPIC"
+AC_CACHE_CHECK(if we can use GCC-specific compiler options, rd_cv_gcc_opt,
+[
+AC_TRY_COMPILE( , return 0 ,
+	 rd_cv_gcc_opt=yes,
+	 rd_cv_gcc_opt=no )
+])
+if test $rd_cv_gcc_opt = no; then
+	CFLAGS_EXTRA=$oCFLAGS_EXTRA
+fi
+
+else
+AC_CACHE_CHECK(if we should use HP compiler options, rd_cv_prog_hpcc,
+[
+cat > conftest.c <<EOF
+#ifdef _HPUX_SOURCE
+  yes;
+#endif
+EOF
+if AC_TRY_COMMAND(${CC-cc} -Ae -z -E conftest.c) | egrep yes >/dev/null 2>&1
+then
+  rd_cv_prog_hpcc=yes
+else
+  rd_cv_prog_hpcc=no
+fi])
+fi
+if test $rd_cv_prog_hpcc = yes; then
+	CFLAGS_EXTRA="$CFLAGS_EXTRA -Ae -z"
+fi
+
+dnl Checks for library functions.
+AC_FUNC_STRFTIME
+AC_FUNC_VPRINTF
+
+AC_CHECK_FUNCS(mktime getrusage gettimeofday)
+
+oCFLAGS_EXTRA=$CFLAGS_EXTRA
+AC_CACHE_CHECK([if the compiler does proper IEEE math], rd_cv_ieee_works,
+[AC_TRY_RUN([int main(void){
+              double a=0.0/0.0,b=0.0,c;
+              c=a/b;if (c==a) c=a;return isnan(a/c)?0:1;
+             }],
+           [rd_cv_ieee_works=yes],[
+AC_MSG_RESULT(no it does not)
+CFLAGS_EXTRA="$CFLAGS_EXTRA -ieee"
+AC_CACHE_CHECK([if the compiler does proper IEEE math with -ieee], rd_cv_ieee_switch,
+[AC_TRY_RUN([int main(void){
+              double a=0.0/0.0,b=0.0,c;
+              c=a/b;if (c==a) c=a;return isnan(a/c)?0:1;   
+             }],
+           [rd_cv_ieee_switch=yes],[rd_cv_ieee_switch=no;
+AC_MSG_RESULT(nope)
+echo "--------------------------------------------------------------"
+echo "Your Compiler does not do propper IEEE math ... "
+echo "Please find out how to make IEEE math work with your Compiler"
+echo "And let me know (oetiker at ee.ethz.ch)"
+echo ""
+exit 1
+],:)])
+],:)])
+
+CFLAGS_EXTRA=$oCFLAGS_EXTRA
+
+if test x$rd_cv_ieee_switch = xyes; then
+	CFLAGS_EXTRA="$CFLAGS_EXTRA -ieee"
+fi
+
+AC_SUBST(CFLAGS_EXTRA)
+AC_SUBST(CFLAGS)
+
+AC_OUTPUT(Makefile src/Makefile gd1.2/Makefile doc/GNUmakefile perl-shared/examples/shared-demo.pl perl-piped/examples/piped-demo.pl, [chmod +x perl-*/examples/*.pl])
+
+AC_MSG_CHECKING(in)
+AC_MSG_RESULT(and out again)
+
+echo $ac_n "ordering CD from http://cdnow.com/gift/oetiker@ee.ethz.ch""... $ac_c" 1>&6
+sleep 3
+AC_MSG_RESULT([just kidding ;-)])

Added: trunk/orca/packages/rrdtool-0.99.29.1/src/parsetime.h
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/src/parsetime.h	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/src/parsetime.h	Sat Jul 13 18:46:00 2002
@@ -0,0 +1,23 @@
+#ifndef __PARSETIME_H__
+#define __PARSETIME_H__
+
+#include <time.h>
+#include <stdio.h>
+
+typedef enum {
+	ABSOLUTE_TIME,
+	RELATIVE_TO_START_TIME, 
+	RELATIVE_TO_END_TIME
+} timetype;
+
+#define TIME_OK NULL
+
+struct time_value {
+  timetype type;
+  long offset;
+  struct tm tm;
+};
+
+char *parsetime(char *spec, struct time_value *ptv);
+
+#endif

Added: trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_format.c
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_format.c	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_format.c	Sat Jul 13 18:46:01 2002
@@ -0,0 +1,65 @@
+/*****************************************************************************
+ * RRDTOOL 0.99.29 Copyright Tobias Oetiker, 1999
+ *****************************************************************************
+ * rrd_format.c  RRD Database Format helper functions
+ *****************************************************************************
+ * $Id: rrd_format.c,v 1.3 1998/03/08 12:35:11 oetiker Exp oetiker $
+ * $Log: rrd_format.c,v $
+ * Revision 1.3  1998/03/08 12:35:11  oetiker
+ * checkpointing things because the current setup seems to work
+ * according to the things said in the manpages
+ *
+ * Revision 1.2  1998/02/26 22:58:22  oetiker
+ * fixed define
+ *
+ * Revision 1.1  1998/02/21 16:14:41  oetiker
+ * Initial revision
+ *
+ *
+ *****************************************************************************/
+#include "rrd_tool.h"
+
+#define converter(VV,VVV) \
+   if (strcmp(#VV, string) == 0) return VVV;
+
+/* conversion functions to allow symbolic entry of enumerations */
+enum dst_en dst_conv(char *string)
+{
+    converter(COUNTER,DST_COUNTER)
+    converter(ABSOLUTE,DST_ABSOLUTE)
+    converter(GAUGE,DST_GAUGE)
+    converter(DERIVE,DST_DERIVE)
+    rrd_set_error("unknown date aquisition function '%s'",string);
+    return(-1);
+}
+
+
+enum cf_en cf_conv(char *string)
+{
+
+    converter(AVERAGE,CF_AVERAGE)
+    converter(MIN,CF_MINIMUM)
+    converter(MAX,CF_MAXIMUM)
+    converter(LAST,CF_LAST)
+    rrd_set_error("unknown consolidation function '%s'",string);
+    return(-1);
+}
+
+#undef converter	
+
+long
+ds_match(rrd_t *rrd,char *ds_nam){
+    long i;
+    for(i=0;i<rrd->stat_head->ds_cnt;i++)
+	if ((strcmp(ds_nam,rrd->ds_def[i].ds_nam))==0)
+	    return i;
+    rrd_set_error("unknown data source name '%s'",ds_nam);
+    return -1;
+}
+
+
+
+
+
+
+

Added: trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_error.c
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_error.c	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_error.c	Sat Jul 13 18:46:01 2002
@@ -0,0 +1,53 @@
+/*****************************************************************************
+ * RRDTOOL 0.99.29 Copyright Tobias Oetiker, 1997, 1998, 1999
+ *****************************************************************************
+ * rrd_error.c   Common Header File
+ *****************************************************************************
+ * $Id: rrd_tool.h,v 1.5 1998/03/08 12:35:11 oetiker Exp oetiker $
+ * $Log: rrd_tool.h,v $
+ *************************************************************************** */
+
+#include "rrd_tool.h"
+static char* rrd_error = NULL;
+#include <stdarg.h>
+
+
+
+void
+rrd_set_error(char *fmt, ...)
+{
+    int maxlen = strlen(fmt)*4;
+    va_list argp;
+    rrd_clear_error();
+    rrd_error = malloc(sizeof(char)*maxlen);
+    va_start(argp, fmt);
+    vsprintf(rrd_error, fmt, argp);
+    va_end(argp);
+}
+
+int
+rrd_test_error(void) {
+    return rrd_error != NULL;
+}
+
+void
+rrd_clear_error(void){
+    free(rrd_error);
+    rrd_error = NULL;
+}
+
+char *
+rrd_get_error(void){
+    return rrd_error;
+}
+
+
+
+
+
+
+
+
+
+
+

Added: trunk/orca/packages/rrdtool-0.99.29.1/src/rrdtool.dsw
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/src/rrdtool.dsw	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/src/rrdtool.dsw	Sat Jul 13 18:46:01 2002
@@ -0,0 +1,53 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "gd"="..\gd1.2\gd.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "rrd"=".\rrd.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "rrdtool"=".\rrdtool.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
Added: trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_fetch.c
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_fetch.c	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_fetch.c	Sat Jul 13 18:46:01 2002
@@ -0,0 +1,461 @@
+/*****************************************************************************
+ * RRDTOOL 0.99.29 Copyright Tobias Oetiker, 1997, 1998, 1999
+ *****************************************************************************
+ * rrd_fetch.c  read date from an rrd to use for further processing
+ *****************************************************************************
+ * $Id: rrd_fetch.c,v 1.8 1998/03/08 12:35:11 oetiker Exp oetiker $
+ * $Log: rrd_fetch.c,v $
+ *****************************************************************************/
+
+#include "rrd_tool.h"
+/*#define DEBUG*/
+
+int
+rrd_fetch(int argc, 
+	  char **argv,
+	  time_t         *start,
+	  time_t         *end,       /* which time frame do you want ?
+				      * will be changed to represent reality */
+	  unsigned long  *step,      /* which stepsize do you want? 
+				      * will be changed to represent reality */
+	  unsigned long  *ds_cnt,    /* number of data sources in file */
+	  char           ***ds_namv,   /* names of data sources */
+	  rrd_value_t    **data)     /* two dimensional array containing the data */
+{
+
+
+    long     step_tmp = 1, start_tmp = -24*3600, end_tmp=time(NULL);
+    enum     cf_en cf_idx;
+
+#ifdef WANT_AT_STYLE_TIMESPEC
+    struct time_value start_tv, end_tv;
+    char     *parsetime_error = NULL;
+    int      start_tmp_is_ok = 0,
+             end_tmp_is_ok = 0;
+
+    end_tv.type = ABSOLUTE_TIME;
+    end_tv.tm = *localtime(&end_tmp);
+    end_tv.offset = 0;
+        
+    start_tv.type = RELATIVE_TO_END_TIME;
+    start_tv.tm = *localtime(&end_tmp); /* to init tm_zone and tm_gmtoff */
+    start_tv.offset = -24*3600;/* to be compatible with the original code.  */
+    start_tv.tm.tm_sec = 0;    /** alternatively we could set tm_mday to -1 */
+    start_tv.tm.tm_min = 0;    /** but this would yield -23(25) hours offset */
+    start_tv.tm.tm_hour = 0;   /** twice a year, when DST is coming in or   */
+    start_tv.tm.tm_mday = 0;   /** out of effect                            */
+    start_tv.tm.tm_mon = 0;
+    start_tv.tm.tm_year = 0;
+    start_tv.tm.tm_wday = 0;
+    start_tv.tm.tm_yday = 0;
+    start_tv.tm.tm_isdst = -1; /* for mktime to guess */
+#endif
+
+    while (1){
+	static struct option long_options[] =
+	{
+	    {"resolution",      required_argument, 0, 'r'},
+	    {"start",      required_argument, 0, 's'},
+	    {"end",      required_argument, 0, 'e'},
+	    {0,0,0,0}
+	};
+	int option_index = 0;
+	int opt;
+	opt = getopt_long(argc, argv, "r:s:e:", 
+			  long_options, &option_index);
+
+	if (opt == EOF)
+	    break;
+
+	switch(opt) {
+	case 's':
+#ifdef WANT_AT_STYLE_TIMESPEC
+            {
+            char *endp;
+            start_tmp_is_ok = 0;
+            start_tmp = strtol(optarg, &endp, 0);
+            if (*endp == '\0') /* it was a valid number */
+                if (start_tmp > 31122038 || /* 31 Dec 2038 in DDMMYYYY */
+                    start_tmp < 0) {
+                    start_tmp_is_ok = 1;
+                    break;
+                }
+            if ((parsetime_error = parsetime(optarg, &start_tv))) {
+                rrd_set_error( "start time: %s", parsetime_error );
+                return -1;
+             }
+            }
+#else
+            start_tmp = atol(optarg);
+#endif
+	    break;
+	case 'e':
+#ifdef WANT_AT_STYLE_TIMESPEC
+            {
+            char *endp;
+            end_tmp_is_ok = 0;
+            end_tmp = strtol(optarg, &endp, 0);
+            if (*endp == '\0') /* it was a valid number */
+                if (end_tmp > 31122038) { /* 31 Dec 2038 in DDMMYYYY */
+                    end_tmp_is_ok = 1;
+                    break;
+                }
+            if ((parsetime_error = parsetime(optarg, &end_tv))) {
+                rrd_set_error( "end time: %s", parsetime_error );
+                return -1;
+             }
+            }
+#else
+            end_tmp = atol(optarg);
+#endif
+	    break;
+	case 'r':
+	    step_tmp = atol(optarg);
+	    break;
+	case '?':
+	    rrd_set_error("unknown option '-%c'",optopt);
+	    return(-1);
+	}
+    }
+#ifdef WANT_AT_STYLE_TIMESPEC
+    if ((start_tv.type == RELATIVE_TO_END_TIME ||
+           (start_tmp_is_ok && start_tmp < 0)) && /* same as the line above */
+           end_tv.type == RELATIVE_TO_START_TIME) {
+        rrd_set_error("the start and end times cannot be specified "
+                      "relative to each other");
+        return(-1);
+    }
+
+    if (start_tv.type == RELATIVE_TO_START_TIME) {
+        rrd_set_error("the start time cannot be specified relative to itself");
+        return(-1);
+    }
+                
+    if (end_tv.type == RELATIVE_TO_END_TIME) {
+        rrd_set_error("the end time cannot be specified relative to itself");
+        return(-1);
+    }
+                
+    /* We don't care to keep all the values in their range,
+       mktime will do this for us */
+    if (start_tv.type == RELATIVE_TO_END_TIME) {
+        if (end_tmp_is_ok)
+            end_tv.tm = *localtime( &end_tmp );
+        start_tv.tm.tm_sec  += end_tv.tm.tm_sec;
+        start_tv.tm.tm_min  += end_tv.tm.tm_min;
+        start_tv.tm.tm_hour += end_tv.tm.tm_hour;
+        start_tv.tm.tm_mday += end_tv.tm.tm_mday;
+        start_tv.tm.tm_mon  += end_tv.tm.tm_mon;
+        start_tv.tm.tm_year += end_tv.tm.tm_year;
+    }
+    if (end_tv.type == RELATIVE_TO_START_TIME) {
+        if (start_tmp_is_ok)
+            start_tv.tm = *localtime( &start_tmp );
+        end_tv.tm.tm_sec  += start_tv.tm.tm_sec;
+        end_tv.tm.tm_min  += start_tv.tm.tm_min;
+        end_tv.tm.tm_hour += start_tv.tm.tm_hour;
+        end_tv.tm.tm_mday += start_tv.tm.tm_mday;
+        end_tv.tm.tm_mon  += start_tv.tm.tm_mon;
+        end_tv.tm.tm_year += start_tv.tm.tm_year;
+    }
+    if (!start_tmp_is_ok)
+        start_tmp = mktime(&start_tv.tm) + start_tv.offset;
+    if (!end_tmp_is_ok)
+        end_tmp = mktime(&end_tv.tm) + end_tv.offset;
+#endif
+
+    if (start_tmp <= 0)
+	start_tmp = end_tmp + start_tmp;
+    
+    
+    if (start_tmp < 3600*24*365*10){
+	rrd_set_error("the first entry to fetch should be after 1980");
+	return(-1);
+    }
+    
+    if (end_tmp < start_tmp) {
+	rrd_set_error("start (%ld) should be less than end (%ld)", start_tmp, end_tmp);
+	return(-1);
+    }
+    
+    *start = start_tmp;
+    *end = end_tmp;
+
+    if (step_tmp < 1) {
+	rrd_set_error("step must be >= 1 second");
+	return -1;
+    }
+    *step = step_tmp;
+    
+    if (optind + 1 >= argc){
+	rrd_set_error("not enough arguments");
+	return -1;
+    }
+    
+    if ((cf_idx=cf_conv(argv[optind+1])) == -1 ){
+	return -1;
+    }
+
+    if (rrd_fetch_fn(argv[optind],cf_idx,start,end,step,ds_cnt,ds_namv,data) == -1)
+	return(-1);
+    return (0);
+}
+
+int
+rrd_fetch_fn(
+    char           *filename,  /* name of the rrd */
+    enum cf_en     cf_idx,         /* which consolidation function ?*/
+    time_t         *start,
+    time_t         *end,       /* which time frame do you want ?
+			        * will be changed to represent reality */
+    unsigned long  *step,      /* which stepsize do you want? 
+				* will be changed to represent reality */
+    unsigned long  *ds_cnt,    /* number of data sources in file */
+    char           ***ds_namv,   /* names of data_sources */
+    rrd_value_t    **data)     /* two dimensional array containing the data */
+{
+    long           i,ii;
+    FILE           *in_file;
+    time_t         cal_start,cal_end, rra_start_time,rra_end_time;
+    long  best_full_rra=0, best_part_rra=0, chosen_rra=0, rra_pointer=0;
+    long  best_step_diff=0, tmp_step_diff=0, tmp_match=0, best_match=0;
+    long  full_match, rra_base;
+    long           start_offset, end_offset;
+    int            first_full = 1;
+    int            first_part = 1;
+    rrd_t     rrd;
+    rrd_value_t    *data_ptr;
+    unsigned long  rows;
+
+    if(rrd_open(filename,&in_file,&rrd, RRD_READONLY)==-1)
+	return(-1);
+    
+    /* when was the realy last update of this file ? */
+
+    if (((*ds_namv) = (char **) malloc(rrd.stat_head->ds_cnt * sizeof(char*)))==NULL){
+	rrd_set_error("malloc fetch ds_namv array");
+	rrd_free(&rrd);
+	fclose(in_file);
+	return(-1);
+    }
+    
+    for(i=0;i<rrd.stat_head->ds_cnt;i++){
+	if ((((*ds_namv)[i]) = malloc(sizeof(char) * DS_NAM_SIZE))==NULL){
+	    rrd_set_error("malloc fetch ds_namv entry");
+	    rrd_free(&rrd);
+	    free(*ds_namv);
+	    fclose(in_file);
+	    return(-1);
+	}
+	strncpy((*ds_namv)[i],rrd.ds_def[i].ds_nam,DS_NAM_SIZE);
+    }
+    
+    /* find the rra which best matches the requirements */
+    for(i=0;i<rrd.stat_head->rra_cnt;i++){
+	if(cf_conv(rrd.rra_def[i].cf_nam) == cf_idx){
+	    
+	       
+	    cal_end = (rrd.live_head->last_up - (rrd.live_head->last_up 
+			  % (rrd.rra_def[i].pdp_cnt 
+			     * rrd.stat_head->pdp_step)));
+	    cal_start = (cal_end 
+			 - (rrd.rra_def[i].pdp_cnt 
+			    * rrd.rra_def[i].row_cnt
+			    * rrd.stat_head->pdp_step));
+	    
+	    full_match = *start - *end;
+	    /* best full match */
+	    if(cal_end >= *end 
+	       && cal_start <= *start){
+		tmp_step_diff = labs(*step - (rrd.stat_head->pdp_step
+					 * rrd.rra_def[i].pdp_cnt));
+		if (first_full || (tmp_step_diff < best_step_diff)){
+		    first_full=0;
+		    best_step_diff = tmp_step_diff;
+		    best_full_rra=i;
+		} 
+		
+	    } else {
+		/* best partial match */
+		tmp_match = full_match;
+		if (cal_start>*start)
+		    tmp_match -= (cal_start-*start);
+		if (cal_end<*end)
+		    tmp_match -= (*end-cal_end);		
+		if (first_part || best_match < tmp_match){
+		    first_part=0;
+		    best_match = tmp_match;
+		    best_part_rra =i;
+		} 
+	    }
+	}
+    }
+
+    /* lets see how the matching went. */
+    
+    if (first_full==0)
+	chosen_rra = best_full_rra;
+    else if (first_part==0)
+	chosen_rra = best_part_rra;
+    else {
+	rrd_set_error("the RRD does not contain an RRA matching the chosen CF");
+	rrd_free(&rrd);
+	fclose(in_file);
+	return(-1);
+    }
+	
+    /* set the wish parameters to their real values */
+    
+    *step = rrd.stat_head->pdp_step * rrd.rra_def[chosen_rra].pdp_cnt;
+    *start -= (*start % *step);
+    if (*end % *step) *end += (*step - *end % *step);
+    rows = (*end - *start) / *step +1;
+
+#ifdef DEBUG
+    fprintf(stderr,"start %lu end %lu step %lu rows  %lu\n",
+	    *start,*end,*step,rows);
+#endif
+
+    *ds_cnt =   rrd.stat_head->ds_cnt; 
+    if (((*data) = malloc(*ds_cnt * rows * sizeof(rrd_value_t)))==NULL){
+	long i;
+	rrd_set_error("malloc fetch data area");
+	for (i=0;i<*ds_cnt;i++)
+	      free((*ds_namv)[i]);
+	free(*ds_namv);
+	rrd_free(&rrd);
+	fclose(in_file);
+	return(-1);
+    }
+    
+    data_ptr=(*data);
+    
+    /* find base address of rra */
+    rra_base=ftell(in_file);
+    for(i=0;i<chosen_rra;i++)
+	rra_base += ( *ds_cnt
+		      * rrd.rra_def[i].row_cnt
+		      * sizeof(rrd_value_t));
+
+    /* find start and end offset */
+    rra_end_time = (rrd.live_head->last_up 
+		    - (rrd.live_head->last_up % *step));
+    rra_start_time = (rra_end_time
+		 - ( *step * (rrd.rra_def[chosen_rra].row_cnt-1)));
+    start_offset = (*start - rra_start_time) / (long)*step;
+    end_offset = (rra_end_time - *end ) / (long)*step; 
+#ifdef DEBUG
+    fprintf(stderr,"rra_start %lu, rra_end %lu, start_off %li, end_off %li\n",
+	    rra_start_time,rra_end_time,start_offset,end_offset);
+#endif
+
+    /* fill the gap at the start if needs be */
+
+    if (start_offset <= 0)
+	rra_pointer = rrd.rra_ptr[chosen_rra].cur_row+1;
+    else 
+	rra_pointer = rrd.rra_ptr[chosen_rra].cur_row+1+start_offset;
+    
+    if(fseek(in_file,(rra_base 
+		   + (rra_pointer
+		      * *ds_cnt
+		      * sizeof(rrd_value_t))),SEEK_SET) != 0){
+	long i;
+	rrd_set_error("seek error in RRA");
+	for (i=0;i<*ds_cnt;i++)
+	      free((*ds_namv)[i]);
+	free(*ds_namv);
+	rrd_free(&rrd);
+	free(*data);
+	*data = NULL;
+	fclose(in_file);
+	return(-1);
+
+    }
+#ifdef DEBUG
+    fprintf(stderr,"First Seek: rra_base %lu rra_pointer %lu\n",
+	    rra_base, rra_pointer);
+#endif
+    /* step trough the array */
+
+    for (i=start_offset;
+	 i<(long)(rrd.rra_def[chosen_rra].row_cnt-end_offset);
+	 i++){
+	/* no valid data yet */
+	if (i<0) {
+#ifdef DEBUG
+	    fprintf(stderr,"pre fetch %li -- ",i);
+#endif
+	    for(ii=0;ii<*ds_cnt;ii++){
+		*(data_ptr++) = DNAN;
+#ifdef DEBUG
+		fprintf(stderr,"%10.2f ",*(data_ptr-1));
+#endif
+	    }
+	} 
+	/* past the valid data area */
+	else if (i>=rrd.rra_def[chosen_rra].row_cnt) {
+#ifdef DEBUG
+	    fprintf(stderr,"post fetch %li -- ",i);
+#endif
+	    for(ii=0;ii<*ds_cnt;ii++){
+		*(data_ptr++) = DNAN;
+#ifdef DEBUG
+		fprintf(stderr,"%10.2f ",*(data_ptr-1));
+#endif
+	    }
+	} else {
+	    /* OK we are inside the valid area but the pointer has to 
+	     * be wrapped*/
+	    if (rra_pointer >= rrd.rra_def[chosen_rra].row_cnt) {
+		rra_pointer -= rrd.rra_def[chosen_rra].row_cnt;
+		if(fseek(in_file,(rra_base+rra_pointer
+			       * *ds_cnt
+			       * sizeof(rrd_value_t)),SEEK_SET) != 0){
+		    long i;
+		    rrd_set_error("wrap seek in RRA did fail");
+		    for (i=0;i<*ds_cnt;i++)
+			free((*ds_namv)[i]);
+		    free(*ds_namv);
+		    rrd_free(&rrd);
+		    free(*data);
+		    *data = NULL;
+		    fclose(in_file);
+		    return(-1);
+		}
+#ifdef DEBUG
+		fprintf(stderr,"wrap seek ...\n");
+#endif	    
+	    }
+	    
+	    if(fread(data_ptr,
+		     sizeof(rrd_value_t),
+		     *ds_cnt,in_file) != rrd.stat_head->ds_cnt){
+		long i;
+		rrd_set_error("fetching cdp from rra");
+		for (i=0;i<*ds_cnt;i++)
+		    free((*ds_namv)[i]);
+		free(*ds_namv);
+		rrd_free(&rrd);
+		free(*data);
+		*data = NULL;
+		fclose(in_file);
+		return(-1);
+	    }
+#ifdef DEBUG
+	    fprintf(stderr,"post fetch %li -- ",i);
+	    for(ii=0;ii<*ds_cnt;ii++)
+		fprintf(stderr,"%10.2f ",*(data_ptr+ii));
+#endif
+	    data_ptr += *ds_cnt;
+	    rra_pointer ++;
+	}
+#ifdef DEBUG
+	    fprintf(stderr,"\n");
+#endif	    
+	
+    }
+    rrd_free(&rrd);
+    fclose(in_file);
+    return(0);
+}

Added: trunk/orca/packages/rrdtool-0.99.29.1/src/Makefile.in
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/src/Makefile.in	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/src/Makefile.in	Sat Jul 13 18:46:01 2002
@@ -0,0 +1,54 @@
+# things that the GNU standards document suggests all makefiles
+# should have.
+SHELL = /bin/sh
+.SUFFIXES:
+.SUFFIXES: .c .o .pl .pm .pod .html .man
+
+# variables we got from configure
+# (you can mess with these, if you want)
+
+CC = @CC@
+AR = ar
+CFLAGS_EXTRA = @CFLAGS_EXTRA@
+CFLAGS = @CFLAGS@
+CFLAGS_ALL = $(CFLAGS) $(CFLAGS_EXTRA) -I.. -I../gd1.2 -DHAVE_CONFIG_H \
+                 -DWANT_AT_STYLE_TIMESPEC
+LDFLAGS = @LDFLAGS@
+LIBS = -L../gd1.2 -lgd @LIBS@
+LIBS_DEPEND = ../gd1.2/libgd.a
+
+###
+### Things you might NOT want to play with ... 
+###
+
+HEADERS = rrd_tool.h rrd_format.h getopt.h parsetime.h
+
+SRCLIB = rrd_fetch.c rrd_create.c rrd_dump.c rrd_graph.c rrd_tune.c\
+	rrd_open.c rrd_diff.c rrd_last.c rrd_update.c rrd_format.c rrd_error.c\
+	getopt.c getopt1.c parsetime.c
+
+SRC = $(SRCLIB) rrd_tool.c
+
+OBJ = $(SRC:.c=.o)
+OBJLIB = $(SRCLIB:.c=.o)
+
+all: rrdtool librrd.a
+
+rrdtool: $(OBJ) $(LIBS_DEPEND)
+	$(CC) -o rrdtool $(OBJ) $(LDFLAGS) $(LIBS)
+
+librrd.a: $(OBJLIB)
+	$(AR) rc librrd.a $(OBJLIB)
+	@RANLIB@ librrd.a
+
+rrdtool.pure: $(OBJ) $(LIBS_DEPEND)
+	purify $(CC) -o rrdtool.pure $(OBJ) $(LDFLAGS) $(LIBS)
+
+clean:  
+	-rm *.o *.a
+
+realclean: clean
+	-rm rrdtool rrdtool.pure
+
+.c.o:	$(HEADERS)
+	$(CC) $(CFLAGS_ALL) -c $<

Added: trunk/orca/packages/rrdtool-0.99.29.1/src/getopt.c
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/src/getopt.c	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/src/getopt.c	Sat Jul 13 18:46:01 2002
@@ -0,0 +1,1000 @@
+/* Getopt for GNU.
+   NOTE: getopt is now part of the C library, so if you don't know what
+   "Keep this file name-space clean" means, talk to roland at gnu.ai.mit.edu
+   before changing it!
+
+   Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97
+   Free Software Foundation, Inc.
+
+   This file is part of the GNU C Library.  Its master source is NOT part of
+   the C library, however.  The master source lives in /gd/gnu/lib.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+   Ditto for AIX 3.2 and <stdlib.h>.  */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if !defined (__STDC__) || !__STDC__
+/* This is a separate conditional since some stdc systems
+   reject `defined (const)'.  */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2
+#include <gnu-versions.h>
+#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#define ELIDE_CODE
+#endif
+#endif
+
+#ifndef ELIDE_CODE
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef	__GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+   contain conflicting prototypes for getopt.  */
+#include <stdlib.h>
+#include <unistd.h>
+#endif	/* GNU C library.  */
+
+#ifdef VMS
+#include <unixlib.h>
+#if HAVE_STRING_H - 0
+#include <string.h>
+#endif
+#endif
+
+#if defined (WIN32) && !defined (__CYGWIN32__)
+/* It's not Unix, really.  See?  Capital letters.  */
+#include <windows.h>
+#define getpid() GetCurrentProcessId()
+#endif
+
+#ifndef _
+/* This is for other GNU distributions with internationalized messages.
+   When compiling libc, the _ macro is predefined.  */
+#ifdef HAVE_LIBINTL_H
+# include <libintl.h>
+# define _(msgid)	gettext (msgid)
+#else
+# define _(msgid)	(msgid)
+#endif
+#endif
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+   but it behaves differently for the user, since it allows the user
+   to intersperse the options with the other arguments.
+
+   As `getopt' works, it permutes the elements of ARGV so that,
+   when it is done, all the options precede everything else.  Thus
+   all application programs are extended to handle flexible argument order.
+
+   Setting the environment variable POSIXLY_CORRECT disables permutation.
+   Then the behavior is completely standard.
+
+   GNU application programs can use a third alternative mode in which
+   they can distinguish the relative order of options and other arguments.  */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+char *optarg = NULL;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns -1, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+/* 1003.2 says this must be 1 before any call.  */
+int optind = 1;
+
+/* Formerly, initialization of getopt depended on optind==0, which
+   causes problems with re-calling getopt as programs generally don't
+   know that. */
+
+int __getopt_initialized = 0;
+
+/* The next char to be scanned in the option-element
+   in which the last option character we returned was found.
+   This allows us to pick up the scan where we left off.
+
+   If this is zero, or a null string, it means resume the scan
+   by advancing to the next ARGV-element.  */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+   for unrecognized options.  */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+   This must be initialized on some systems to avoid linking in the
+   system's own getopt implementation.  */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+   If the caller did not specify anything,
+   the default is REQUIRE_ORDER if the environment variable
+   POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+   REQUIRE_ORDER means don't recognize them as options;
+   stop option processing when the first non-option is seen.
+   This is what Unix does.
+   This mode of operation is selected by either setting the environment
+   variable POSIXLY_CORRECT, or using `+' as the first character
+   of the list of option characters.
+
+   PERMUTE is the default.  We permute the contents of ARGV as we scan,
+   so that eventually all the non-options are at the end.  This allows options
+   to be given in any order, even with programs that were not written to
+   expect this.
+
+   RETURN_IN_ORDER is an option available to programs that were written
+   to expect options and other ARGV-elements in any order and that care about
+   the ordering of the two.  We describe each non-option ARGV-element
+   as if it were the argument of an option with character code 1.
+   Using `-' as the first character of the list of option characters
+   selects this mode of operation.
+
+   The special argument `--' forces an end of option-scanning regardless
+   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
+   `--' can cause `getopt' to return -1 with `optind' != ARGC.  */
+
+static enum
+{
+  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+/* Value of POSIXLY_CORRECT environment variable.  */
+static char *posixly_correct;
+
+#ifdef	__GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+   because there are many ways it can cause trouble.
+   On some systems, it contains special magic macros that don't work
+   in GCC.  */
+#include <string.h>
+#define	my_index	strchr
+#else
+
+/* Avoid depending on library functions or files
+   whose names are inconsistent.  */
+
+char *getenv ();
+
+static char *
+my_index (str, chr)
+     const char *str;
+     int chr;
+{
+  while (*str)
+    {
+      if (*str == chr)
+	return (char *) str;
+      str++;
+    }
+  return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+   If not using GCC, it is ok not to declare it.  */
+#ifdef __GNUC__
+/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
+   That was relevant to code that was here before.  */
+#if !defined (__STDC__) || !__STDC__
+/* gcc with -traditional declares the built-in strlen to return int,
+   and has done so at least since version 2.4.5. -- rms.  */
+extern int strlen (const char *);
+#endif /* not __STDC__ */
+#endif /* __GNUC__ */
+
+#endif /* not __GNU_LIBRARY__ */
+
+/* Handle permutation of arguments.  */
+
+/* Describe the part of ARGV that contains non-options that have
+   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
+   `last_nonopt' is the index after the last of them.  */
+
+static int first_nonopt;
+static int last_nonopt;
+
+#ifdef _LIBC
+/* Bash 2.0 gives us an environment variable containing flags
+   indicating ARGV elements that should not be considered arguments.  */
+
+static const char *nonoption_flags;
+static int nonoption_flags_len;
+
+static int original_argc;
+static char *const *original_argv;
+
+/* Make sure the environment variable bash 2.0 puts in the environment
+   is valid for the getopt call we must make sure that the ARGV passed
+   to getopt is that one passed to the process.  */
+static void store_args (int argc, char *const *argv) __attribute__ ((unused));
+static void
+store_args (int argc, char *const *argv)
+{
+  /* XXX This is no good solution.  We should rather copy the args so
+     that we can compare them later.  But we must not use malloc(3).  */
+  original_argc = argc;
+  original_argv = argv;
+}
+text_set_element (__libc_subinit, store_args);
+#endif
+
+/* Exchange two adjacent subsequences of ARGV.
+   One subsequence is elements [first_nonopt,last_nonopt)
+   which contains all the non-options that have been skipped so far.
+   The other is elements [last_nonopt,optind), which contains all
+   the options processed since those non-options were skipped.
+
+   `first_nonopt' and `last_nonopt' are relocated so that they describe
+   the new indices of the non-options in ARGV after they are moved.  */
+
+#if defined (__STDC__) && __STDC__
+static void exchange (char **);
+#endif
+
+static void
+exchange (argv)
+     char **argv;
+{
+  int bottom = first_nonopt;
+  int middle = last_nonopt;
+  int top = optind;
+  char *tem;
+
+  /* Exchange the shorter segment with the far end of the longer segment.
+     That puts the shorter segment into the right place.
+     It leaves the longer segment in the right place overall,
+     but it consists of two parts that need to be swapped next.  */
+
+  while (top > middle && middle > bottom)
+    {
+      if (top - middle > middle - bottom)
+	{
+	  /* Bottom segment is the short one.  */
+	  int len = middle - bottom;
+	  register int i;
+
+	  /* Swap it with the top part of the top segment.  */
+	  for (i = 0; i < len; i++)
+	    {
+	      tem = argv[bottom + i];
+	      argv[bottom + i] = argv[top - (middle - bottom) + i];
+	      argv[top - (middle - bottom) + i] = tem;
+	    }
+	  /* Exclude the moved bottom segment from further swapping.  */
+	  top -= len;
+	}
+      else
+	{
+	  /* Top segment is the short one.  */
+	  int len = top - middle;
+	  register int i;
+
+	  /* Swap it with the bottom part of the bottom segment.  */
+	  for (i = 0; i < len; i++)
+	    {
+	      tem = argv[bottom + i];
+	      argv[bottom + i] = argv[middle + i];
+	      argv[middle + i] = tem;
+	    }
+	  /* Exclude the moved top segment from further swapping.  */
+	  bottom += len;
+	}
+    }
+
+  /* Update records for the slots the non-options now occupy.  */
+
+  first_nonopt += (optind - last_nonopt);
+  last_nonopt = optind;
+}
+
+/* Initialize the internal data when the first call is made.  */
+
+#if defined (__STDC__) && __STDC__
+static const char *_getopt_initialize (int, char *const *, const char *);
+#endif
+static const char *
+_getopt_initialize (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  /* Start processing options with ARGV-element 1 (since ARGV-element 0
+     is the program name); the sequence of previously skipped
+     non-option ARGV-elements is empty.  */
+
+  first_nonopt = last_nonopt = optind = 1;
+
+  nextchar = NULL;
+
+  posixly_correct = getenv ("POSIXLY_CORRECT");
+
+  /* Determine how to handle the ordering of options and nonoptions.  */
+
+  if (optstring[0] == '-')
+    {
+      ordering = RETURN_IN_ORDER;
+      ++optstring;
+    }
+  else if (optstring[0] == '+')
+    {
+      ordering = REQUIRE_ORDER;
+      ++optstring;
+    }
+  else if (posixly_correct != NULL)
+    ordering = REQUIRE_ORDER;
+  else
+    ordering = PERMUTE;
+
+#ifdef _LIBC
+  if (posixly_correct == NULL
+      && argc == original_argc && argv == original_argv)
+    {
+      /* Bash 2.0 puts a special variable in the environment for each
+	 command it runs, specifying which ARGV elements are the results of
+	 file name wildcard expansion and therefore should not be
+	 considered as options.  */
+      char var[100];
+      sprintf (var, "_%d_GNU_nonoption_argv_flags_", getpid ());
+      nonoption_flags = getenv (var);
+      if (nonoption_flags == NULL)
+	nonoption_flags_len = 0;
+      else
+	nonoption_flags_len = strlen (nonoption_flags);
+    }
+  else
+    nonoption_flags_len = 0;
+#endif
+
+  return optstring;
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+   given in OPTSTRING.
+
+   If an element of ARGV starts with '-', and is not exactly "-" or "--",
+   then it is an option element.  The characters of this element
+   (aside from the initial '-') are option characters.  If `getopt'
+   is called repeatedly, it returns successively each of the option characters
+   from each of the option elements.
+
+   If `getopt' finds another option character, it returns that character,
+   updating `optind' and `nextchar' so that the next call to `getopt' can
+   resume the scan with the following option character or ARGV-element.
+
+   If there are no more option characters, `getopt' returns -1.
+   Then `optind' is the index in ARGV of the first ARGV-element
+   that is not an option.  (The ARGV-elements have been permuted
+   so that those that are not options now come last.)
+
+   OPTSTRING is a string containing the legitimate option characters.
+   If an option character is seen that is not listed in OPTSTRING,
+   return '?' after printing an error message.  If you set `opterr' to
+   zero, the error message is suppressed but we still return '?'.
+
+   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+   so the following text in the same ARGV-element, or the text of the following
+   ARGV-element, is returned in `optarg'.  Two colons mean an option that
+   wants an optional arg; if there is text in the current ARGV-element,
+   it is returned in `optarg', otherwise `optarg' is set to zero.
+
+   If OPTSTRING starts with `-' or `+', it requests different methods of
+   handling the non-option ARGV-elements.
+   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+   Long-named options begin with `--' instead of `-'.
+   Their names may be abbreviated as long as the abbreviation is unique
+   or is an exact match for some defined option.  If they have an
+   argument, it follows the option name in the same ARGV-element, separated
+   from the option name by a `=', or else the in next ARGV-element.
+   When `getopt' finds a long-named option, it returns 0 if that option's
+   `flag' field is nonzero, the value of the option's `val' field
+   if the `flag' field is zero.
+
+   The elements of ARGV aren't really const, because we permute them.
+   But we pretend they're const in the prototype to be compatible
+   with other systems.
+
+   LONGOPTS is a vector of `struct option' terminated by an
+   element containing a name which is zero.
+
+   LONGIND returns the index in LONGOPT of the long-named option found.
+   It is only valid when a long-named option has been found by the most
+   recent call.
+
+   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+   long-named options.  */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+     const struct option *longopts;
+     int *longind;
+     int long_only;
+{
+  optarg = NULL;
+
+  if (!__getopt_initialized || optind == 0)
+    {
+      optstring = _getopt_initialize (argc, argv, optstring);
+      optind = 1;		/* Don't scan ARGV[0], the program name.  */
+      __getopt_initialized = 1;
+    }
+
+  /* Test whether ARGV[optind] points to a non-option argument.
+     Either it does not have option syntax, or there is an environment flag
+     from the shell indicating it is not an option.  The later information
+     is only used when the used in the GNU libc.  */
+#ifdef _LIBC
+#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0'	      \
+		     || (optind < nonoption_flags_len			      \
+			 && nonoption_flags[optind] == '1'))
+#else
+#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#endif
+
+  if (nextchar == NULL || *nextchar == '\0')
+    {
+      /* Advance to the next ARGV-element.  */
+
+      /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
+	 moved back by the user (who may also have changed the arguments).  */
+      if (last_nonopt > optind)
+	last_nonopt = optind;
+      if (first_nonopt > optind)
+	first_nonopt = optind;
+
+      if (ordering == PERMUTE)
+	{
+	  /* If we have just processed some options following some non-options,
+	     exchange them so that the options come first.  */
+
+	  if (first_nonopt != last_nonopt && last_nonopt != optind)
+	    exchange ((char **) argv);
+	  else if (last_nonopt != optind)
+	    first_nonopt = optind;
+
+	  /* Skip any additional non-options
+	     and extend the range of non-options previously skipped.  */
+
+	  while (optind < argc && NONOPTION_P)
+	    optind++;
+	  last_nonopt = optind;
+	}
+
+      /* The special ARGV-element `--' means premature end of options.
+	 Skip it like a null option,
+	 then exchange with previous non-options as if it were an option,
+	 then skip everything else like a non-option.  */
+
+      if (optind != argc && !strcmp (argv[optind], "--"))
+	{
+	  optind++;
+
+	  if (first_nonopt != last_nonopt && last_nonopt != optind)
+	    exchange ((char **) argv);
+	  else if (first_nonopt == last_nonopt)
+	    first_nonopt = optind;
+	  last_nonopt = argc;
+
+	  optind = argc;
+	}
+
+      /* If we have done all the ARGV-elements, stop the scan
+	 and back over any non-options that we skipped and permuted.  */
+
+      if (optind == argc)
+	{
+	  /* Set the next-arg-index to point at the non-options
+	     that we previously skipped, so the caller will digest them.  */
+	  if (first_nonopt != last_nonopt)
+	    optind = first_nonopt;
+	  return -1;
+	}
+
+      /* If we have come to a non-option and did not permute it,
+	 either stop the scan or describe it to the caller and pass it by.  */
+
+      if (NONOPTION_P)
+	{
+	  if (ordering == REQUIRE_ORDER)
+	    return -1;
+	  optarg = argv[optind++];
+	  return 1;
+	}
+
+      /* We have found another option-ARGV-element.
+	 Skip the initial punctuation.  */
+
+      nextchar = (argv[optind] + 1
+		  + (longopts != NULL && argv[optind][1] == '-'));
+    }
+
+  /* Decode the current option-ARGV-element.  */
+
+  /* Check whether the ARGV-element is a long option.
+
+     If long_only and the ARGV-element has the form "-f", where f is
+     a valid short option, don't consider it an abbreviated form of
+     a long option that starts with f.  Otherwise there would be no
+     way to give the -f short option.
+
+     On the other hand, if there's a long option "fubar" and
+     the ARGV-element is "-fu", do consider that an abbreviation of
+     the long option, just like "--fu", and not "-f" with arg "u".
+
+     This distinction seems to be the most useful approach.  */
+
+  if (longopts != NULL
+      && (argv[optind][1] == '-'
+	  || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
+    {
+      char *nameend;
+      const struct option *p;
+      const struct option *pfound = NULL;
+      int exact = 0;
+      int ambig = 0;
+      int indfound = -1;
+      int option_index;
+
+      for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
+	/* Do nothing.  */ ;
+
+      /* Test all long options for either exact match
+	 or abbreviated matches.  */
+      for (p = longopts, option_index = 0; p->name; p++, option_index++)
+	if (!strncmp (p->name, nextchar, nameend - nextchar))
+	  {
+	    if ((unsigned int) (nameend - nextchar)
+		== (unsigned int) strlen (p->name))
+	      {
+		/* Exact match found.  */
+		pfound = p;
+		indfound = option_index;
+		exact = 1;
+		break;
+	      }
+	    else if (pfound == NULL)
+	      {
+		/* First nonexact match found.  */
+		pfound = p;
+		indfound = option_index;
+	      }
+	    else
+	      /* Second or later nonexact match found.  */
+	      ambig = 1;
+	  }
+
+      if (ambig && !exact)
+	{
+	  if (opterr)
+	    fprintf (stderr, _("%s: option `%s' is ambiguous\n"),
+		     argv[0], argv[optind]);
+	  nextchar += strlen (nextchar);
+	  optind++;
+	  optopt = 0;
+	  return '?';
+	}
+
+      if (pfound != NULL)
+	{
+	  option_index = indfound;
+	  optind++;
+	  if (*nameend)
+	    {
+	      /* Don't test has_arg with >, because some C compilers don't
+		 allow it to be used on enums.  */
+	      if (pfound->has_arg)
+		optarg = nameend + 1;
+	      else
+		{
+		  if (opterr)
+		   if (argv[optind - 1][1] == '-')
+		    /* --option */
+		    fprintf (stderr,
+		     _("%s: option `--%s' doesn't allow an argument\n"),
+		     argv[0], pfound->name);
+		   else
+		    /* +option or -option */
+		    fprintf (stderr,
+		     _("%s: option `%c%s' doesn't allow an argument\n"),
+		     argv[0], argv[optind - 1][0], pfound->name);
+
+		  nextchar += strlen (nextchar);
+
+		  optopt = pfound->val;
+		  return '?';
+		}
+	    }
+	  else if (pfound->has_arg == 1)
+	    {
+	      if (optind < argc)
+		optarg = argv[optind++];
+	      else
+		{
+		  if (opterr)
+		    fprintf (stderr,
+			   _("%s: option `%s' requires an argument\n"),
+			   argv[0], argv[optind - 1]);
+		  nextchar += strlen (nextchar);
+		  optopt = pfound->val;
+		  return optstring[0] == ':' ? ':' : '?';
+		}
+	    }
+	  nextchar += strlen (nextchar);
+	  if (longind != NULL)
+	    *longind = option_index;
+	  if (pfound->flag)
+	    {
+	      *(pfound->flag) = pfound->val;
+	      return 0;
+	    }
+	  return pfound->val;
+	}
+
+      /* Can't find it as a long option.  If this is not getopt_long_only,
+	 or the option starts with '--' or is not a valid short
+	 option, then it's an error.
+	 Otherwise interpret it as a short option.  */
+      if (!long_only || argv[optind][1] == '-'
+	  || my_index (optstring, *nextchar) == NULL)
+	{
+	  if (opterr)
+	    {
+	      if (argv[optind][1] == '-')
+		/* --option */
+		fprintf (stderr, _("%s: unrecognized option `--%s'\n"),
+			 argv[0], nextchar);
+	      else
+		/* +option or -option */
+		fprintf (stderr, _("%s: unrecognized option `%c%s'\n"),
+			 argv[0], argv[optind][0], nextchar);
+	    }
+	  nextchar = (char *) "";
+	  optind++;
+	  optopt = 0;
+	  return '?';
+	}
+    }
+
+  /* Look at and handle the next short option-character.  */
+
+  {
+    char c = *nextchar++;
+    char *temp = my_index (optstring, c);
+
+    /* Increment `optind' when we start to process its last character.  */
+    if (*nextchar == '\0')
+      ++optind;
+
+    if (temp == NULL || c == ':')
+      {
+	if (opterr)
+	  {
+	    if (posixly_correct)
+	      /* 1003.2 specifies the format of this message.  */
+	      fprintf (stderr, _("%s: illegal option -- %c\n"),
+		       argv[0], c);
+	    else
+	      fprintf (stderr, _("%s: invalid option -- %c\n"),
+		       argv[0], c);
+	  }
+	optopt = c;
+	return '?';
+      }
+    /* Convenience. Treat POSIX -W foo same as long option --foo */
+    if (temp[0] == 'W' && temp[1] == ';')
+      {
+	char *nameend;
+	const struct option *p;
+	const struct option *pfound = NULL;
+	int exact = 0;
+	int ambig = 0;
+	int indfound = 0;
+	int option_index;
+
+	/* This is an option that requires an argument.  */
+	if (*nextchar != '\0')
+	  {
+	    optarg = nextchar;
+	    /* If we end this ARGV-element by taking the rest as an arg,
+	       we must advance to the next element now.  */
+	    optind++;
+	  }
+	else if (optind == argc)
+	  {
+	    if (opterr)
+	      {
+		/* 1003.2 specifies the format of this message.  */
+		fprintf (stderr, _("%s: option requires an argument -- %c\n"),
+			 argv[0], c);
+	      }
+	    optopt = c;
+	    if (optstring[0] == ':')
+	      c = ':';
+	    else
+	      c = '?';
+	    return c;
+	  }
+	else
+	  /* We already incremented `optind' once;
+	     increment it again when taking next ARGV-elt as argument.  */
+	  optarg = argv[optind++];
+
+	/* optarg is now the argument, see if it's in the
+	   table of longopts.  */
+
+	for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++)
+	  /* Do nothing.  */ ;
+
+	/* Test all long options for either exact match
+	   or abbreviated matches.  */
+	for (p = longopts, option_index = 0; p->name; p++, option_index++)
+	  if (!strncmp (p->name, nextchar, nameend - nextchar))
+	    {
+	      if ((unsigned int) (nameend - nextchar) == strlen (p->name))
+		{
+		  /* Exact match found.  */
+		  pfound = p;
+		  indfound = option_index;
+		  exact = 1;
+		  break;
+		}
+	      else if (pfound == NULL)
+		{
+		  /* First nonexact match found.  */
+		  pfound = p;
+		  indfound = option_index;
+		}
+	      else
+		/* Second or later nonexact match found.  */
+		ambig = 1;
+	    }
+	if (ambig && !exact)
+	  {
+	    if (opterr)
+	      fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"),
+		       argv[0], argv[optind]);
+	    nextchar += strlen (nextchar);
+	    optind++;
+	    return '?';
+	  }
+	if (pfound != NULL)
+	  {
+	    option_index = indfound;
+	    if (*nameend)
+	      {
+		/* Don't test has_arg with >, because some C compilers don't
+		   allow it to be used on enums.  */
+		if (pfound->has_arg)
+		  optarg = nameend + 1;
+		else
+		  {
+		    if (opterr)
+		      fprintf (stderr, _("\
+%s: option `-W %s' doesn't allow an argument\n"),
+			       argv[0], pfound->name);
+
+		    nextchar += strlen (nextchar);
+		    return '?';
+		  }
+	      }
+	    else if (pfound->has_arg == 1)
+	      {
+		if (optind < argc)
+		  optarg = argv[optind++];
+		else
+		  {
+		    if (opterr)
+		      fprintf (stderr,
+			       _("%s: option `%s' requires an argument\n"),
+			       argv[0], argv[optind - 1]);
+		    nextchar += strlen (nextchar);
+		    return optstring[0] == ':' ? ':' : '?';
+		  }
+	      }
+	    nextchar += strlen (nextchar);
+	    if (longind != NULL)
+	      *longind = option_index;
+	    if (pfound->flag)
+	      {
+		*(pfound->flag) = pfound->val;
+		return 0;
+	      }
+	    return pfound->val;
+	  }
+	  nextchar = NULL;
+	  return 'W';	/* Let the application handle it.   */
+      }
+    if (temp[1] == ':')
+      {
+	if (temp[2] == ':')
+	  {
+	    /* This is an option that accepts an argument optionally.  */
+	    if (*nextchar != '\0')
+	      {
+		optarg = nextchar;
+		optind++;
+	      }
+	    else
+	      optarg = NULL;
+	    nextchar = NULL;
+	  }
+	else
+	  {
+	    /* This is an option that requires an argument.  */
+	    if (*nextchar != '\0')
+	      {
+		optarg = nextchar;
+		/* If we end this ARGV-element by taking the rest as an arg,
+		   we must advance to the next element now.  */
+		optind++;
+	      }
+	    else if (optind == argc)
+	      {
+		if (opterr)
+		  {
+		    /* 1003.2 specifies the format of this message.  */
+		    fprintf (stderr,
+			   _("%s: option requires an argument -- %c\n"),
+			   argv[0], c);
+		  }
+		optopt = c;
+		if (optstring[0] == ':')
+		  c = ':';
+		else
+		  c = '?';
+	      }
+	    else
+	      /* We already incremented `optind' once;
+		 increment it again when taking next ARGV-elt as argument.  */
+	      optarg = argv[optind++];
+	    nextchar = NULL;
+	  }
+      }
+    return c;
+  }
+}
+
+int
+getopt (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  return _getopt_internal (argc, argv, optstring,
+			   (const struct option *) 0,
+			   (int *) 0,
+			   0);
+}
+
+#endif	/* Not ELIDE_CODE.  */
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+   the above definition of `getopt'.  */
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+
+      c = getopt (argc, argv, "abc:d:0123456789");
+      if (c == -1)
+	break;
+
+      switch (c)
+	{
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+	  if (digit_optind != 0 && digit_optind != this_option_optind)
+	    printf ("digits occur in two different argv-elements.\n");
+	  digit_optind = this_option_optind;
+	  printf ("option %c\n", c);
+	  break;
+
+	case 'a':
+	  printf ("option a\n");
+	  break;
+
+	case 'b':
+	  printf ("option b\n");
+	  break;
+
+	case 'c':
+	  printf ("option c with value `%s'\n", optarg);
+	  break;
+
+	case '?':
+	  break;
+
+	default:
+	  printf ("?? getopt returned character code 0%o ??\n", c);
+	}
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+	printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */

Added: trunk/orca/packages/rrdtool-0.99.29.1/src/rrd.dsw
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/src/rrd.dsw	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/src/rrd.dsw	Sat Jul 13 18:46:01 2002
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "rrd"=".\rrd.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
Added: trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_format.h
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_format.h	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_format.h	Sat Jul 13 18:46:01 2002
@@ -0,0 +1,299 @@
+/*****************************************************************************
+ * RRDTOOL 0.99.29 Copyright Tobias Oetiker, 1997, 1998, 1999
+ *****************************************************************************
+ * rrd_format.h  RRD Database Format header
+ *****************************************************************************/
+
+#ifndef _RRD_FORMAT_H
+#define _RRD_FORMAT_H
+
+/*****************************************************************************
+ * put this in your /usr/lib/magic file (/etc/magic on HPUX)
+ *
+ *  # rrd database format
+ *  0       string          RRD\0           rrd file
+ *  >5      string          >\0             version '%s'
+ *
+ *****************************************************************************/
+
+#define RRD_COOKIE    "RRD"
+#define RRD_VERSION   "0001"
+#define FLOAT_COOKIE  8.642135E130
+
+#if defined(WIN32) || defined(_HPUX_SOURCE)
+#define DNAN          ((double)fmod(0.0,0.0))    
+#else
+
+#define DNAN          ((double)(0.0/0.0))     /* we use a DNAN to
+					       * represent the UNKNOWN
+					       * */
+#endif
+
+typedef double       rrd_value_t;         /* the data storage type is
+					   * double */
+
+typedef union unival { 
+    unsigned long u_cnt; 
+    rrd_value_t   u_val;
+} unival;
+
+
+/****************************************************************************
+ * The RRD Database Structure
+ * ---------------------------
+ * 
+ * In oder to properly describe the database structure lets define a few
+ * new words:
+ *
+ * ds - Data Source (ds) providing input to the database. A Data Source (ds)
+ *       can be a traffic counter, a temperature, the number of users logged
+ *       into a system. The rrd database format can handle the input of
+ *       several Data Sources (ds) in a singe database.
+ *  
+ * dst - Data Source Type (dst). The Data Source Type (dst) defines the rules
+ *       applied to Build Primary Data Points from the input provided by the
+ *       data sources (ds).
+ *
+ * pdp - Primary Data Point (pdp). After the database has accepted the
+ *       input from the data sources (ds). It starts building Primary
+ *       Data Points (pdp) from the data. Primary Data Points (pdp)
+ *       are evenly spaced along the time axis (pdp_step). The values
+ *       of the Primary Data Points are calculated from the values of
+ *       the data source (ds) and the exact time these values were
+ *       provided by the data source (ds).
+ *
+ * pdp_st - PDP Start (pdp_st). The moments (pdp_st) in time where
+ *       these steps occur are defined by the moments where the
+ *       number of seconds since 1970-jan-1 modulo pdp_step equals
+ *       zero (pdp_st). 
+ *
+ * cf -  Consolidation Function (cf). An arbitrary Consolidation Function (cf)
+ *       (averaging, min, max) is applied to the primary data points (pdp) to
+ *       calculate the consolidated data point.
+ *
+ * cdp - Consolidated Data Point (cdp) is the long term storage format for data
+ *       in the rrd database. Consolidated Data Points represent one or
+ *       several primary data points collected along the time axis. The
+ *       Consolidated Data Points (cdp) are stored in Round Robin Archives
+ *       (rra).
+ *
+ * rra - Round Robin Archive (rra). This is the place where the
+ *       consolidated data points (cdp) get stored. The data is
+ *       organized in rows (row) and columns (col). The Round Robin
+ *       Archive got its name from the method data is stored in
+ *       there. An RRD database can contain several Round Robin
+ *       Archives. Each Round Robin Archive can have a different row
+ *       spacing along the time axis (pdp_cnt) and a different
+ *       consolidation function (cf) used to build its consolidated
+ *       data points (cdp).  
+ * 
+ * rra_st - RRA Start (rra_st). The moments (rra_st) in time where
+ *       Consolidated Data Points (cdp) are added to an rra are
+ *       defined by the moments where the number of seconds since
+ *       1970-jan-1 modulo pdp_cnt*pdp_step equals zero (rra_st).
+ *
+ * row - Row (row). A row represent all consolidated data points (cdp)
+ *       in a round robin archive who are of the same age.
+ *       
+ * col - Column (col). A column (col) represent all consolidated
+ *       data points (cdp) in a round robin archive (rra) who
+ *       originated from the same data source (ds).
+ *
+ */
+
+/****************************************************************************
+ * POS 1: stat_head_t                           static header of the database
+ ****************************************************************************/
+
+typedef struct stat_head_t {
+
+    /* Data Base Identification Section ***/
+    char             cookie[4];          /* RRD */
+    char             version[5];         /* version of the format */
+    double           float_cookie;       /* is it the correct double
+				  	  * representation ?  */
+
+    /* Data Base Structure Definition *****/
+    unsigned long    ds_cnt;             /* how many different ds provide
+					  * input to the rrd */
+    unsigned long    rra_cnt;            /* how many rras will be maintained
+					  * in the rrd */
+    unsigned long    pdp_step;           /* pdp interval in seconds */
+
+    unival           par[10];            /* global parameters ... unused
+					    at the moment */
+} stat_head_t;
+
+
+/****************************************************************************
+ * POS 2: ds_def_t  (* ds_cnt)                        Data Source definitions
+ ****************************************************************************/
+
+enum dst_en          { DST_COUNTER=0,     /* data source types available */
+                       DST_ABSOLUTE, 
+                       DST_GAUGE,
+                       DST_DERIVE};
+
+enum ds_param_en {   DS_mrhb_cnt=0,       /* minimum required heartbeat. A
+					   * data source must provide input at
+					   * least every ds_mrhb seconds,
+					   * otherwise it is regarded dead and
+					   * will be set to UNKNOWN */             
+		     DS_min_val,	  /* the processed input of a ds must */
+                     DS_max_val };        /* be between max_val and min_val
+					   * both can be set to UNKNOWN if you
+					   * do not care. Data outside the limits
+ 					   * set to UNKNOWN */
+#define DS_NAM_FMT    "%19[a-zA-Z0-9_]"
+#define DS_NAM_SIZE   20
+
+#define DST_FMT    "%19[A-Z]"
+#define DST_SIZE   20
+
+typedef struct ds_def_t {
+    char             ds_nam[DS_NAM_SIZE]; /* Name of the data source (null terminated)*/
+    char             dst[DST_SIZE];       /* Type of data source (null terminated)*/
+    unival           par[10];             /* index of this array see ds_param_en */
+} ds_def_t;
+
+/****************************************************************************
+ * POS 3: rra_def_t ( *  rra_cnt)         one for each store to be maintained
+ ****************************************************************************/
+enum cf_en           { CF_AVERAGE=0,     /* data consolidation functions */ 
+                       CF_MINIMUM, 
+                       CF_MAXIMUM,
+                       CF_LAST};
+
+enum rra_par_en {   RRA_cdp_xff_val=0};   /* what part of the consolidated 
+					    datapoint must be known, to produce a
+					    valid entry in the rra */
+		   	
+#define CF_NAM_FMT    "%19[A-Z]"
+#define CF_NAM_SIZE   20
+
+typedef struct rra_def_t {
+    char             cf_nam[CF_NAM_SIZE];/* consolidation function (null term) */
+    unsigned long    row_cnt;            /* number of entries in the store */
+    unsigned long    pdp_cnt;            /* how many primary data points are
+					  * required for a consolidated data
+					  * point?*/
+    unival           par[10];            /* index see rra_param_en */
+
+} rra_def_t;
+
+
+/****************************************************************************
+ ****************************************************************************
+ ****************************************************************************
+ * LIVE PART OF THE HEADER. THIS WILL BE WRITTEN ON EVERY UPDATE         *
+ ****************************************************************************
+ ****************************************************************************
+ ****************************************************************************/
+/****************************************************************************
+ * POS 4: live_head_t                    
+ ****************************************************************************/
+
+typedef struct live_head_t {
+    time_t           last_up;            /* when was rrd last updated */
+} live_head_t;
+
+
+/****************************************************************************
+ * POS 5: pdp_prep_t  (* ds_cnt)                     here we prepare the pdps 
+ ****************************************************************************/
+#define LAST_DS_LEN 30 /* DO NOT CHANGE THIS ... */
+
+enum pdp_par_en {   PDP_unkn_sec_cnt=0,  /* how many seconds of the current
+					  * pdp value is unknown data? */
+
+		    PDP_val};	         /* current value of the pdp.
+					    this depends on dst */
+
+typedef struct pdp_prep_t{    
+    char last_ds[LAST_DS_LEN];           /* the last reading from the data
+					  * source.  this is stored in ASCII
+					  * to cater for very large counters
+					  * we might encounter in connection
+					  * with SNMP. */
+    unival          scratch[10];         /* contents according to pdp_par_en */
+} pdp_prep_t;
+
+/* data is passed from pdp to cdp when seconds since epoch modulo pdp_step == 0
+   obviously the updates do not occur at these times only. Especially does the
+   format allow for updates to occur at different times for each data source.
+   The rules which makes this work is as follows:
+
+   * DS updates may only occur at ever increasing points in time
+   * When any DS update arrives after a cdp update time, the *previous*
+     update cycle gets executed. All pdps are transfered to cdps and the
+     cdps feed the rras where necessary. Only then the new DS value
+     is loaded into the PDP.                                                   */
+
+
+/****************************************************************************
+ * POS 6: cdp_prep_t (* rra_cnt * ds_cnt )      data prep area for cdp values
+ ****************************************************************************/
+enum cdp_par_en {  CDP_val=0,          /* the base_interval is always an
+					  * average */
+		   CDP_unkn_pdp_cnt };       /* how many unknown pdp were
+               				  * integrated. This and the cdp_xff
+					    will decide if this is going to
+					    be a UNKNOWN or a valid value */
+
+typedef struct cdp_prep_t{
+    unival         scratch[10];          /* contents according to cdp_par_en *
+                                          * init state should be NAN */
+
+} cdp_prep_t;
+
+/****************************************************************************
+ * POS 7: rra_ptr_t (* rra_cnt)       pointers to the current row in each rra
+ ****************************************************************************/
+
+typedef struct rra_ptr_t {
+    unsigned long    cur_row;            /* current row in the rra*/
+} rra_ptr_t;
+
+
+/****************************************************************************
+ ****************************************************************************
+ * One single struct to hold all the others. For convenience.
+ ****************************************************************************
+ ****************************************************************************/
+typedef struct rrd_t {
+    stat_head_t      *stat_head;          /* the static header */
+    ds_def_t         *ds_def;             /* list of data source definitions */
+    rra_def_t        *rra_def;            /* list of round robin archive def */
+    live_head_t      *live_head;
+    pdp_prep_t       *pdp_prep;           /* pdp data prep area */  
+    cdp_prep_t       *cdp_prep;           /* cdp prep area */
+    rra_ptr_t        *rra_ptr;            /* list of rra pointers */
+} rrd_t;
+
+/****************************************************************************
+ ****************************************************************************
+ * AFTER the header section we have the DATA STORAGE AREA it is made up from
+ * Consolidated Data Points organized in Round Robin Archives.
+ ****************************************************************************
+ ****************************************************************************
+ 
+ *RRA 0
+ (0,0) .................... ( ds_cnt -1 , 0)
+ .
+ . 
+ .
+ (0, row_cnt -1) ... (ds_cnt -1, row_cnt -1)
+
+ *RRA 1
+ *RRA 2
+
+ *RRA rra_cnt -1
+ 
+ ****************************************************************************/
+
+
+#endif
+
+
+
+

Added: trunk/orca/packages/rrdtool-0.99.29.1/src/getopt.h
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/src/getopt.h	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/src/getopt.h	Sat Jul 13 18:46:02 2002
@@ -0,0 +1,133 @@
+/* Declarations for getopt.
+   Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc.
+
+   This file is part of the GNU C Library.  Its master source is NOT part of
+   the C library, however.  The master source lives in /gd/gnu/lib.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns -1, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+   for unrecognized options.  */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized.  */
+
+extern int optopt;
+
+/* Describe the long-named options requested by the application.
+   The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+   of `struct option' terminated by an element containing a name which is
+   zero.
+
+   The field `has_arg' is:
+   no_argument		(or 0) if the option does not take an argument,
+   required_argument	(or 1) if the option requires an argument,
+   optional_argument 	(or 2) if the option takes an optional argument.
+
+   If the field `flag' is not NULL, it points to a variable that is set
+   to the value given in the field `val' when the option is found, but
+   left unchanged if the option is not found.
+
+   To have a long-named option do something other than set an `int' to
+   a compiled-in constant, such as set a value from `optarg', set the
+   option's `flag' field to zero and its `val' field to a nonzero
+   value (the equivalent single-letter option character, if there is
+   one).  For long options that have a zero `flag' field, `getopt'
+   returns the contents of the `val' field.  */
+
+struct option
+{
+#if defined (__STDC__) && __STDC__
+  const char *name;
+#else
+  char *name;
+#endif
+  /* has_arg can't be an enum because some compilers complain about
+     type mismatches in all the code that assumes it is an int.  */
+  int has_arg;
+  int *flag;
+  int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'.  */
+
+#define	no_argument		0
+#define required_argument	1
+#define optional_argument	2
+
+#if defined (__STDC__) && __STDC__
+#ifdef __GNU_LIBRARY__
+/* Many other libraries have conflicting prototypes for getopt, with
+   differences in the consts, in stdlib.h.  To avoid compilation
+   errors, only prototype getopt for the GNU C library.  */
+extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+#endif /* __GNU_LIBRARY__ */
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+		        const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+			     const char *shortopts,
+		             const struct option *longopts, int *longind);
+
+/* Internal only.  Users should not call this directly.  */
+extern int _getopt_internal (int argc, char *const *argv,
+			     const char *shortopts,
+		             const struct option *longopts, int *longind,
+			     int long_only);
+#else /* not __STDC__ */
+extern int getopt ();
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+#endif /* __STDC__ */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */

Added: trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_open.c
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_open.c	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_open.c	Sat Jul 13 18:46:02 2002
@@ -0,0 +1,89 @@
+/*****************************************************************************
+ * RRDTOOL 0.99.29 Copyright Tobias Oetiker, 1997, 1998, 1999
+ *****************************************************************************
+ * rrd_open.c  Open an RRD File
+ *****************************************************************************
+ * $Id: rrd_open.c,v 1.6 1998/03/08 12:35:11 oetiker Exp oetiker $
+ * $Log: rrd_open.c,v $
+ *****************************************************************************/
+
+#include "rrd_tool.h"
+
+/* open a database file, return its header and a open filehandle */
+/* positioned to the first cdp in the first rra */
+
+int
+rrd_open(char *file_name, FILE **in_file, rrd_t *rrd, int rdwr)    
+{
+
+    char *mode = NULL;
+    if (rdwr == RRD_READONLY) {
+	mode = "rb";
+    } else {
+	mode = "rb+";
+    }
+    
+    if ((*in_file = fopen(file_name,mode)) == NULL ){
+	rrd_set_error("rrdopen can't open '%s'",file_name);
+	return (-1);
+    }
+    
+#define MYFREAD(MYVAR,MYVART,MYCNT) \
+    if ((MYVAR = malloc(sizeof(MYVART) * MYCNT)) == NULL) {\
+	rrd_set_error("" #MYVAR " malloc"); \
+    return (-1); } \
+    fread(MYVAR,sizeof(MYVART),MYCNT, *in_file); 
+
+
+    MYFREAD(rrd->stat_head, stat_head_t,  1)
+    
+	/* lets do some test if we are on track ... */
+	if (strncmp(rrd->stat_head->cookie,RRD_COOKIE,4) != 0){
+	    rrd_set_error("not an RRD file");
+	    free(rrd->stat_head);
+	    return(-1);}
+
+	if (strncmp(rrd->stat_head->version,RRD_VERSION,5) != 0){
+	    rrd_set_error("cant handle RRD file version %s",
+			rrd->stat_head->version);
+	    free(rrd->stat_head);
+	    return(-1);}
+
+	if (rrd->stat_head->float_cookie != FLOAT_COOKIE){
+	    rrd_set_error("This RRD created on other architecture");
+	    free(rrd->stat_head);
+	    return(-1);}
+
+    MYFREAD(rrd->ds_def,    ds_def_t,     rrd->stat_head->ds_cnt)
+    MYFREAD(rrd->rra_def,   rra_def_t,    rrd->stat_head->rra_cnt)
+    MYFREAD(rrd->live_head,   live_head_t,  1)
+    MYFREAD(rrd->pdp_prep,  pdp_prep_t,   rrd->stat_head->ds_cnt)
+    MYFREAD(rrd->cdp_prep,  cdp_prep_t,   (rrd->stat_head->rra_cnt
+	                                     * rrd->stat_head->ds_cnt))
+    MYFREAD(rrd->rra_ptr,   rra_ptr_t,    rrd->stat_head->rra_cnt)
+#undef MYFREAD
+
+    return(0);
+}
+
+void rrd_init(rrd_t *rrd)
+{
+    rrd->stat_head = NULL;
+    rrd->ds_def = NULL;
+    rrd->rra_def = NULL;
+    rrd->live_head = NULL;
+    rrd->rra_ptr = NULL;
+    rrd->pdp_prep = NULL;
+    rrd->cdp_prep = NULL;
+}
+
+void rrd_free(rrd_t *rrd)
+{
+    free(rrd->stat_head);
+    free(rrd->ds_def);
+    free(rrd->rra_def);
+    free(rrd->live_head);
+    free(rrd->rra_ptr);
+    free(rrd->pdp_prep);
+    free(rrd->cdp_prep);
+}

Added: trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_graph.c
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_graph.c	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_graph.c	Sat Jul 13 18:46:03 2002
@@ -0,0 +1,2719 @@
+/****************************************************************************
+ * RRDTOOL 0.99.29 Copyright Tobias Oetiker, 1997,1998, 1999
+ ****************************************************************************
+ * rrd__graph.c  make creates ne rrds
+ ****************************************************************************/
+
+#include "rrd_tool.h"
+#include <gd.h>
+#include <gdfonts.h>
+#include <gdfontmb.h>
+
+/* #define DEBUG */
+
+#ifdef DEBUG
+# define DPRINT(x)    (void)(printf x, printf("\n"))
+#else
+# define DPRINT(x)
+#endif
+
+enum tmt_en {TMT_SECOND=0,TMT_MINUTE,TMT_HOUR,TMT_DAY,
+	     TMT_WEEK,TMT_MONTH,TMT_YEAR};
+
+enum grc_en {GRC_CANVAS=0,GRC_BACK,GRC_SHADEA,GRC_SHADEB,
+	     GRC_GRID,GRC_MGRID,GRC_FONT,GRC_FRAME,GRC_ARROW,__GRC_END__};
+
+enum gf_en {GF_PRINT=0,GF_GPRINT,GF_COMMENT,GF_HRULE,GF_VRULE,GF_LINE1,
+	    GF_LINE2,GF_LINE3,GF_AREA,GF_STACK, GF_DEF, GF_CDEF };
+
+enum op_en {OP_NUMBER=0,OP_VARIABLE,OP_ADD,OP_SUB,OP_MUL,OP_DIV,OP_SIN,
+	    OP_COS,OP_LOG,OP_EXP,OP_LT,OP_LE,OP_GT,OP_GE,OP_EQ,OP_IF,
+	    OP_UN,OP_END};
+
+typedef struct rpnp_t {
+    enum op_en   op;
+    double val; /* value for a OP_NUMBER */
+    long ptr; /* pointer into the gdes array for OP_VAR */
+    double *data; /* pointer to the current value from OP_VAR DAS*/
+    long ds_cnt;   /* data source count for data pointer */
+    long step; /* time step for OP_VAR das */
+} rpnp_t;
+ 
+
+typedef struct col_trip_t {
+    int red; /* red = -1 is no color */
+    int green;
+    int blue;
+    int i; /* color index assigned in gif image i=-1 is unasigned*/
+} col_trip_t;
+
+
+typedef struct xlab_t {
+    long         minsec;       /* minimum sec per pix */
+    enum tmt_en  gridtm;       /* grid interval in what ?*/
+    long         gridst;       /* how many whats per grid*/
+    enum tmt_en  mgridtm;      /* label interval in what ?*/
+    long         mgridst;      /* how many whats per label*/
+    enum tmt_en  labtm;        /* label interval in what ?*/
+    long         labst;        /* how many whats per label*/
+    long         precis;       /* label precision -> label placement*/
+    char         *stst;        /* strftime string*/
+} xlab_t;
+
+xlab_t xlab[] = {
+    {0,        TMT_SECOND,30, TMT_MINUTE,5,  TMT_MINUTE,5,         0,"%H:%M"},
+    {2,        TMT_MINUTE,1,  TMT_MINUTE,5,  TMT_MINUTE,5,         0,"%H:%M"},
+    {5,        TMT_MINUTE,2,  TMT_MINUTE,10, TMT_MINUTE,10,        0,"%H:%M"},
+    {10,       TMT_MINUTE,5,  TMT_MINUTE,20, TMT_MINUTE,20,        0,"%H:%M"},
+    {30,       TMT_MINUTE,10, TMT_HOUR,1,    TMT_HOUR,1,           0,"%H:%M"},
+    {60,       TMT_MINUTE,30, TMT_HOUR,2,    TMT_HOUR,2,           0,"%H:%M"},
+    {180,      TMT_HOUR,1,    TMT_HOUR,6,    TMT_HOUR,6,           0,"%H:%M"},
+    /*{300,      TMT_HOUR,3,    TMT_HOUR,12,   TMT_HOUR,12,    12*3600,"%a %p"},  this looks silly*/
+    {600,      TMT_HOUR,6,    TMT_DAY,1,     TMT_DAY,1,      24*3600,"%a"},
+    {1800,     TMT_HOUR,12,   TMT_DAY,1,     TMT_DAY,2,      24*3600,"%a"},
+    {3600,     TMT_DAY,1,     TMT_WEEK,1,     TMT_WEEK,1,    7*24*3600,"Week %W"},
+    {3*3600,   TMT_WEEK,1,      TMT_MONTH,1,     TMT_WEEK,2,    7*24*3600,"Week %W"},
+    {6*3600,   TMT_MONTH,1,   TMT_MONTH,1,   TMT_MONTH,1, 30*24*3600,"%b"},
+    {48*3600,  TMT_MONTH,1,   TMT_MONTH,3,   TMT_MONTH,3, 30*24*3600,"%b"},
+    {10*24*3600, TMT_YEAR,1,  TMT_YEAR,1,    TMT_YEAR,1, 365*24*3600,"%y"},
+    {-1,TMT_MONTH,0,TMT_MONTH,0,TMT_MONTH,0,0,""}
+};
+
+/* sensible logarithmic y label intervals ...
+   the first element of each row defines the possible starting points on the
+   y axis ... the other specify the */
+
+double yloglab[][12]= {{ 1e9, 1,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0 },
+		       {  1e3, 1,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0 },
+		       {  1e1, 1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
+		       /* {  1e1, 1,  5,  0,  0,  0,  0,  0,  0,  0,  0,  0 }, */
+		       {  1e1, 1,  2.5,  5,  7.5,  0,  0,  0,  0,  0,  0,  0 },
+		       {  1e1, 1,  2,  4,  6,  8,  0,  0,  0,  0,  0,  0 },
+		       {  1e1, 1,  2,  3,  4,  5,  6,  7,  8,  9,  0,  0 },
+		       {  0,   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 }};
+
+/* sensible y label intervals ...*/
+
+typedef struct ylab_t {
+    double   grid;    /* grid spacing */
+    int      lfac[4]; /* associated label spacing*/
+} ylab_t;
+
+ylab_t ylab[]= {
+    {0.1, {1,2, 5,10}},
+    {0.2, {1,5,10,20}},
+    {0.5, {1,2, 4,10}},
+    {1.0,   {1,2, 5,10}},
+    {2.0,   {1,5,10,20}},
+    {5.0,   {1,2, 4,10}},
+    {10.0,  {1,2, 5,10}},
+    {20.0,  {1,5,10,20}},
+    {50.0,  {1,2, 4,10}},
+    {100.0, {1,2, 5,10}},
+    {200.0, {1,5,10,20}},
+    {500.0, {1,2, 4,10}},
+    {0.0,   {0,0,0,0}}};
+
+
+
+col_trip_t graph_col[] = { /* default colors */
+    {255,255,255,-1},   /* canvas */
+    {245,245,245,-1},   /* background */
+    {200,200,200,-1},   /* shade A    */
+    {150,150,150,-1},   /* shade B    */
+    {140,140,140,-1},      /* grid */
+    {130,30,30,-1},      /* major grid */
+    {0,0,0,-1},         /* font */ 	
+    {0,0,0,-1},         /* frame */
+    {255,0,0,-1}	/*arrow*/
+};
+
+/* this structure describes the elements which can make up a graph.
+   because they are quite diverse, not all elements will use all the
+   possible parts of the structure. */
+
+#define FMT_LEG_LEN 120
+
+typedef  struct graph_desc_t {
+    enum gf_en     gf;         /* graphing function */
+    char           vname[30];  /* name of the variable */
+    long           vidx;       /* gdes reference */
+    char           rrd[255];   /* name of the rrd_file containing data */
+    char           ds_nam[DS_NAM_SIZE]; /* data source name */
+    long           ds;         /* data source number */
+    enum cf_en     cf;         /* consolidation function */
+    col_trip_t     col;        /* graph color */
+    char           format[FMT_LEG_LEN+5]; /* format for PRINT AND GPRINT */
+    char           legend[FMT_LEG_LEN+5]; /* legend*/
+    gdPoint        legloc;     /* location of legend */    
+    double         yrule;      /* value for y rule line */
+    time_t         xrule;      /* value for x rule line */
+    rpnp_t         *rpnp;     /* instructions for CDEF function */ 
+
+    /* description of data fetched for the graph element */
+    time_t         start,end; /* first and last data element */
+    unsigned long  step;      /* time between samples */
+    unsigned long  ds_cnt; /* how many data sources are there in the fetch */
+    long           data_first; /* first pointer to this data */
+    char           **ds_namv; /* name of datasources  in the fetch. */
+    rrd_value_t    *data; /* the raw data drawn from the rrd */
+    rrd_value_t    *p_data; /* processed data, xsize elments */
+
+} graph_desc_t;
+
+
+typedef struct image_desc_t {
+
+    /* configuration of graph */
+
+    char           graphfile[255]; /* filename for graphic */
+    long           xsize,ysize;    /* graph area size in pixels */
+    col_trip_t     graph_col[__GRC_END__]; /* real colors for the graph */    
+    char           ylegend[200];   /* legend along the yaxis */
+    char           title[200];     /* title for graph */
+    xlab_t         xlab_user;      /* user defined labeling for xaxis */
+    char           xlab_form[200]; /* format for the label on the xaxis */
+
+    double         ygridstep;      /* user defined step for y grid */
+    int            ylabfact;       /* every how many y grid shall a label be written ? */
+
+    time_t         start,end;      /* what time does the graph cover */
+    rrd_value_t    minval,maxval;  /* extreme values in the data */
+    int            rigid;          /* do not expand range even with 
+				      values outside */
+    int            logarithmic;    /* scale the yaxis logarithmic */
+
+    /* status information */
+
+    long           xorigin,yorigin;/* where is (0,0) of the graph */
+    long           xgif,ygif;      /* total size of the gif */
+    int            interlaced;     /* will the graph be interlaced? */
+    double         magfact;        /* numerical magnitude*/
+    long         base;            /* 1000 or 1024 depending on what we graph */
+    char           symbol;         /* magnitude symbol for y-axis */
+
+    /* data elements */
+
+    long  gdes_c;                  /* number of graphics elements */
+    graph_desc_t   *gdes;          /* points to an array of graph elements */
+
+} image_desc_t;
+
+
+
+
+/* translate time values into x coordinates */    
+/*#define xtr(x) (int)((double)im->xorigin \
+		+ ((double) im->xsize / (double)(im->end - im->start) ) \
+		* ((double)(x) - im->start)+0.5) */
+/* initialize with xtr(im,0); */
+int
+xtr(image_desc_t *im,time_t time){
+    static double pixie;
+    if (time==0){
+	pixie = (double) im->xsize / (double)(im->end - im->start);
+	return im->xorigin;
+    }
+    return (int)((double)im->xorigin 
+		 + pixie * ( time - im->start ) );
+}
+
+/* translate data values into y coordinates */
+
+/* #define ytr(x) (int)((double)im->yorigin \
+		- ((double) im->ysize / (im->maxval - im->minval) ) \
+		* ((double)(x) - im->minval)+0.5) */
+int
+ytr(image_desc_t *im, double value){
+    static double pixie;
+    double yval;
+    if (isnan(value)){
+      if(!im->logarithmic)
+	pixie = (double) im->ysize / (im->maxval - im->minval);
+      else 
+	pixie = (double) im->ysize / (log10(im->maxval) - log10(im->minval));
+      yval = im->yorigin;
+    } else if(!im->logarithmic) {
+      yval = im->yorigin - pixie * (value - im->minval) + 0.5;
+    } else {
+      if (value < im->minval) {
+	yval = im->yorigin;
+      } else {
+	yval = im->yorigin - pixie * (log10(value) - log10(im->minval)) + 0.5;
+      }
+    }
+    /* make sure we don't return anything too unreasonable. GD lib can
+       get terribly slow when drawing lines outside its scope. This is 
+       especially problematic in connection with the rigid option */
+    if (! im->rigid) {
+      return (int)yval;
+    } else if ((int)yval > im->yorigin) {
+      return im->yorigin+2;
+    } else if ((int) yval < im->yorigin - im->ysize){
+      return im->yorigin - im->ysize - 2;
+    } else {
+      return (int)yval;
+    } 
+}
+
+   
+    
+
+
+/* conversion function for symbolic entry names */
+
+#define conv_if(VV,VVV) \
+   if (strcmp(#VV, string) == 0) return VVV ;
+
+enum gf_en gf_conv(char *string){
+    
+    conv_if(PRINT,GF_PRINT)
+    conv_if(GPRINT,GF_GPRINT)
+    conv_if(COMMENT,GF_COMMENT)
+    conv_if(HRULE,GF_HRULE)
+    conv_if(VRULE,GF_VRULE)
+    conv_if(LINE1,GF_LINE1)
+    conv_if(LINE2,GF_LINE2)
+    conv_if(LINE3,GF_LINE3)
+    conv_if(AREA,GF_AREA)
+    conv_if(STACK,GF_STACK)
+    conv_if(DEF,GF_DEF)
+    conv_if(CDEF,GF_CDEF)
+    
+    return (-1);
+}
+
+enum tmt_en tmt_conv(char *string){
+
+    conv_if(SECOND,TMT_SECOND)
+    conv_if(MINUTE,TMT_MINUTE)
+    conv_if(HOUR,TMT_HOUR)
+    conv_if(DAY,TMT_DAY)
+    conv_if(WEEK,TMT_WEEK)
+    conv_if(MONTH,TMT_MONTH)
+    conv_if(YEAR,TMT_YEAR)
+    return (-1);
+}
+
+enum grc_en grc_conv(char *string){
+
+    conv_if(BACK,GRC_BACK)
+    conv_if(CANVAS,GRC_CANVAS)
+    conv_if(SHADEA,GRC_SHADEA)
+    conv_if(SHADEB,GRC_SHADEB)
+    conv_if(GRID,GRC_GRID)
+    conv_if(MGRID,GRC_MGRID)
+    conv_if(FONT,GRC_FONT)
+    conv_if(FRAME,GRC_FRAME)
+    conv_if(ARROW,GRC_ARROW)
+
+    return -1;	
+}
+
+#undef conv_if
+
+
+
+int
+im_free(image_desc_t *im)
+{
+    long i,ii;
+    if (im == NULL) return 0;
+    for(i=0;i<im->gdes_c;i++){
+      if (im->gdes[i].data_first){
+	/* careful here, because a single pointer can occur several times */
+	  free (im->gdes[i].data);
+	  if (im->gdes[i].ds_namv){
+	      for (ii=0;ii<im->gdes[i].ds_cnt;ii++)
+		  free(im->gdes[i].ds_namv[ii]);
+	      free(im->gdes[i].ds_namv);
+	  }
+      }
+      free (im->gdes[i].p_data);
+      free (im->gdes[i].rpnp);
+    }
+    free(im->gdes);
+    return 0;
+}
+
+/* find SI magnitude symbol for the numbers on the y-axis*/
+void 
+si_unit(
+    image_desc_t *im   /* image description */
+)
+{
+	
+    char symbol[] = {'a', /* 10e-18 Ato */ 
+		      'f', /* 10e-15 Femto */
+		      'p', /* 10e-12 Pico */
+		      'n', /* 10e-9  Nano */
+		      'µ', /* 10e-6  Micro */
+		      'm', /* 10e-3  Milli */
+		      ' ',  /* Base */
+		      'k', /* 10e3   Kilo */
+		      'M', /* 10e6   Mega */
+		      'G', /* 10e9   Giga */
+		      'T', /* 10e12  Terra */
+		      'P', /* 10e15  Peta */
+		      'E'};/* 10e18  Exa */
+
+    int   symbcenter = 6;
+    double digits;  
+    
+    
+    digits = floor( log( max( fabs(im->minval),fabs(im->maxval)))/log(im->base)); 
+    im->magfact = pow(im->base , digits);
+#ifdef DEBUG
+    printf("digits %6.3f  im->magfact %6.3f\n",digits,im->magfact);
+#endif
+    if ( ((digits+symbcenter) < sizeof(symbol)) &&
+		    ((digits+symbcenter) >= 0) )
+        im->symbol = symbol[(int)digits+symbcenter];
+    else
+	im->symbol = ' ';
+ }
+
+/*  move min and max values around to become sensible */
+
+void 
+expand_range(image_desc_t *im)
+{
+    double sensiblevalues[] ={1000.0,900.0,800.0,750.0,700.0,
+			      600.0,500.0,400.0,300.0,250.0,
+			      200.0,125.0,100.0,90.0,80.0,
+			      75.0,70.0,60.0,50.0,40.0,30.0,
+			      25.0,20.0,10.0,9.0,8.0,
+			      7.0,6.0,5.0,4.0,3.5,3.0,
+			      2.5,2.0,1.8,1.5,1.2,1.0,
+			      0.8,0.7,0.6,0.5,0.4,0.3,0.2,0.1,0.0,-1};
+    
+    double scaled_min,scaled_max;  
+    int i;
+    
+
+    scaled_min = im->minval / im->magfact;
+    scaled_max = im->maxval / im->magfact;
+   
+    #ifdef DEBUG
+    printf("Min: %6.2f Max: %6.2f MagFactor: %6.2f\n",
+	   im->minval,im->maxval,im->magfact);
+    #endif
+    
+    for (i=1; sensiblevalues[i] > 0; i++){
+	if (sensiblevalues[i-1]>=scaled_min &&
+	    sensiblevalues[i]<=scaled_min)	
+	    im->minval = sensiblevalues[i]*(im->magfact);
+	
+	if (-sensiblevalues[i-1]<=scaled_min &&
+	    -sensiblevalues[i]>=scaled_min)
+	    im->minval = -sensiblevalues[i-1]*(im->magfact);
+	
+	if (sensiblevalues[i-1] >= scaled_max &&
+	    sensiblevalues[i] <= scaled_max)
+	    im->maxval = sensiblevalues[i-1]*(im->magfact);
+	
+	if (-sensiblevalues[i-1]<=scaled_max &&
+	    -sensiblevalues[i] >=scaled_max)
+	    im->maxval = -sensiblevalues[i]*(im->magfact);
+    }
+#ifdef DEBUG
+    printf("SCALED Min: %6.2f Max: %6.2f Factor: %6.2f\n",
+	   im->minval,im->maxval,im->magfact);
+#endif
+}
+
+    
+
+void
+reduce_data(
+    enum cf_en     cf,         /* which consolidation function ?*/
+    unsigned long  cur_step,   /* step the data currently is in */
+    time_t         *start,
+    time_t         *end,       /* which time frame do you want ?
+				* will be changed to represent reality */
+    unsigned long  *step,      /* step the data currently is in */
+    unsigned long  *ds_cnt,    /* number of data sources in file */
+    rrd_value_t    **data)     /* two dimensional array containing the data */
+{
+    int i,reduce_factor = ceil((double)*step / cur_step);
+    unsigned long src_row,trg_row,col,row_cnt,start_offset,rowadjust;
+    row_cnt = (*end-*start)/cur_step;
+
+    *step = cur_step*reduce_factor;
+    /* adjust the start time so that it is a multiple of the new steptime */
+    
+    start_offset = *start % *step;
+    if (start_offset > 0) {
+      start_offset = *step - start_offset;
+      *start = *start + start_offset - *step;
+      /* we don't have any data for the first row, so fill it with
+       *UNKNOWN* */
+      for (col=0;col<*ds_cnt;col++)
+	(*data)[col] = DNAN;
+    }
+    
+    
+    rowadjust = start_offset / cur_step;
+    
+    trg_row=0;
+        
+    for (src_row = rowadjust; src_row <= row_cnt-reduce_factor; src_row+=reduce_factor) {
+	for (col=0;col<*ds_cnt;col++){
+	    double newval=0;
+	    unsigned long validval=0;
+	    for (i=0;i<reduce_factor && src_row<row_cnt;i += reduce_factor) {		
+		unsigned long ptr = (src_row+i)* *ds_cnt+col;
+		if (isnan((*data)[ptr])) continue; /* we can't help with NAN */
+		validval++;
+		switch (cf) {
+		case CF_AVERAGE:
+		    newval += (*data)[ptr];
+		    break;
+		case CF_MINIMUM:
+		    newval = min (newval,(*data)[ptr]);
+		    break;
+		case CF_MAXIMUM:
+		    newval = max (newval,(*data)[ptr]);
+		    break;
+		case CF_LAST:
+		    newval = (*data)[ptr];
+		    break;
+		}
+	    }
+	    if (validval == 0){newval = DNAN;} else{
+		switch (cf) {
+		case CF_AVERAGE:		
+		    newval /= validval;
+		    break;
+		case CF_MINIMUM:
+		case CF_MAXIMUM:
+		case CF_LAST:
+		    break;
+		}
+	    }
+	    (*data)[(trg_row)* *ds_cnt+col] = newval;
+	}
+	trg_row++;
+    }
+    *end = *start+ *step *trg_row;
+    for (col=0;col<*ds_cnt;col++){
+      (*data)[(trg_row)* *ds_cnt+col] = DNAN;
+    }
+}
+
+
+/* get the data required for the graphs from the 
+   relevant rrds ... */
+
+int
+data_fetch( image_desc_t *im )
+{
+    int       i,ii;
+    int skip;
+    /* pull the data from the log files ... */
+    for (i=0;i<im->gdes_c;i++){
+	/* only GF_DEF elements fetch data */
+	if (im->gdes[i].gf != GF_DEF) 
+	    continue;
+
+	skip=0;
+	/* do we have it already ?*/
+	for (ii=0;ii<i;ii++){
+	    if (im->gdes[ii].gf != GF_DEF) 
+		continue;
+	    if((strcmp(im->gdes[i].rrd,im->gdes[ii].rrd) == 0)
+		&& (im->gdes[i].cf == im->gdes[ii].cf)){
+		/* OK the data it is here already ... 
+		 * we just copy the header portion */
+		im->gdes[i].start = im->gdes[ii].start;
+		im->gdes[i].end = im->gdes[ii].end;
+		im->gdes[i].step = im->gdes[ii].step;
+		im->gdes[i].ds_cnt = im->gdes[ii].ds_cnt;
+		im->gdes[i].ds_namv = im->gdes[ii].ds_namv;		
+		im->gdes[i].data = im->gdes[ii].data;
+		im->gdes[i].data_first = 0;
+		skip=1;
+	    }
+	    if (skip) 
+		break;
+	}
+	if (! skip) {
+	    unsigned long  ft_step = im->gdes[i].step ;
+	    
+	    if((rrd_fetch_fn(im->gdes[i].rrd,
+			     im->gdes[i].cf,
+			     &im->gdes[i].start,
+			     &im->gdes[i].end,
+			     &ft_step,
+			     &im->gdes[i].ds_cnt,
+			     &im->gdes[i].ds_namv,
+			     &im->gdes[i].data)) == -1){		
+		return -1;
+	    }
+	    im->gdes[i].data_first = 1;	    
+	
+	    if (ft_step < im->gdes[i].step) {
+		reduce_data(im->gdes[i].cf,
+			    ft_step,
+			    &im->gdes[i].start,
+			    &im->gdes[i].end,
+			    &im->gdes[i].step,
+			    &im->gdes[i].ds_cnt,
+			    &im->gdes[i].data);
+	    } else {
+		im->gdes[i].step = ft_step;
+	    }
+	}
+	
+        /* lets see if the required data source is realy there */
+	for(ii=0;ii<im->gdes[i].ds_cnt;ii++){
+	    if(strcmp(im->gdes[i].ds_namv[ii],im->gdes[i].ds_nam) == 0){
+		im->gdes[i].ds=ii; }
+	}
+	if (im->gdes[i].ds== -1){
+	    rrd_set_error("No DS called '%s' in '%s'",
+			  im->gdes[i].ds_nam,im->gdes[i].rrd);
+	    return -1; 
+	}
+	
+    }
+    return 0;
+}
+
+/* evaluate the expressions in the CDEF functions */
+
+/*************************************************************
+ * CDEF stuff 
+ *************************************************************/
+
+/* find gdes containing var*/
+long
+find_var(image_desc_t *im, char *key){
+    long ii;
+    for(ii=0;ii<im->gdes_c-1;ii++){
+	if((im->gdes[ii].gf == GF_DEF 
+	    || im->gdes[ii].gf == GF_CDEF) 
+	   && (strcmp(im->gdes[ii].vname,key) == 0)){
+	    return ii; 
+	}	   
+    }	    	    
+    return -1;
+}
+
+/* find the largest common denominator for all the numbers
+   in the 0 terminated num array */
+long
+lcd(long *num){
+    long rest;
+    int i;
+    for (i=0;num[i+1]!=0;i++){
+	do { 
+	    rest=num[i] % num[i+1];
+	    num[i]=num[i+1]; num[i+1]=rest;
+	} while (rest!=0);
+	num[i+1] = num[i];
+    }
+/*    return i==0?num[i]:num[i-1]; */
+      return num[i];
+}
+
+
+/* convert string to rpnp */
+rpnp_t * 
+str2rpn(image_desc_t *im,char *expr){
+    int pos=0;
+    long steps=-1;    
+    rpnp_t  *rpnp;
+    char vname[30];
+
+    rpnp=NULL;
+
+    while(*expr){
+	if ((rpnp = (rpnp_t *) realloc(rpnp, (++steps + 2)* 
+				       sizeof(rpnp_t)))==NULL){
+	    return NULL;
+	}
+	
+	if(sscanf(expr,"%lf%n",&rpnp[steps].val,&pos) == 1){
+	    rpnp[steps].op = OP_NUMBER;
+	    expr+=pos;
+	} 
+	else if ((sscanf(expr,"%29[_A-Za-z0-9]%n",
+			 vname,&pos) == 1) 
+		 && ((rpnp[steps].ptr = find_var(im,vname)) != -1)){
+	    rpnp[steps].op = OP_VARIABLE;
+	    expr+=pos;
+	}	   
+
+#define match_op(VV,VVV) \
+        else if (strncmp(expr, #VVV, strlen(#VVV))==0){ \
+	    rpnp[steps].op = VV; \
+	    expr+=strlen(#VVV); \
+	}
+
+	match_op(OP_ADD,+)
+	match_op(OP_SUB,-)
+	match_op(OP_MUL,*)
+	match_op(OP_DIV,/)
+	match_op(OP_SIN,SIN)
+	match_op(OP_COS,COS)
+	match_op(OP_LOG,LOG)
+	match_op(OP_EXP,EXP)
+	match_op(OP_LT,LT)
+	match_op(OP_LE,LE)
+	match_op(OP_GT,GT)
+	match_op(OP_GE,GE)
+	match_op(OP_EQ,EQ)
+	match_op(OP_IF,IF)
+	match_op(OP_UN,UN)
+	
+#undef match_op
+
+	else {
+	    free(rpnp);
+	    return NULL;
+	}
+	if (*expr == 0)
+	  break;
+	if (*expr == ',')
+	    expr++;
+	else {
+	    free(rpnp);
+	    return NULL;
+	}  
+    }
+    rpnp[steps+1].op = OP_END;
+    return rpnp;
+}
+
+
+#define dc_stacksize 30
+
+/* run the rpn calculator on all the CDEF arguments */
+
+int
+data_calc( image_desc_t *im){
+
+    int       gdi,rpi;
+    int       dataidx;
+    long      *steparray;
+    int       stepcnt;
+    time_t    now;
+
+    for (gdi=0;gdi<im->gdes_c;gdi++){
+	/* only GF_CDEF elements are of interest */
+	if (im->gdes[gdi].gf != GF_CDEF) 
+	    continue;
+	im->gdes[gdi].ds_cnt = 1;
+	im->gdes[gdi].ds = 0;
+	im->gdes[gdi].data_first = 1;
+	im->gdes[gdi].start = 0;
+	im->gdes[gdi].end = 0;
+	steparray=NULL;
+	stepcnt = 0;
+	dataidx=-1;
+
+	/* find the variables in the expression. And calc the lowest
+           common denominator of all step sizes of the data sources involved.
+	   this will be the step size for the cdef created data source*/
+
+	for(rpi=0;im->gdes[gdi].rpnp[rpi].op != OP_END;rpi++){
+	    if(im->gdes[gdi].rpnp[rpi].op == OP_VARIABLE){
+		long ptr = im->gdes[gdi].rpnp[rpi].ptr;
+		if ((steparray = realloc(steparray, (++stepcnt+1)*sizeof(double)))==NULL){
+		  rrd_set_error("realloc steparray");
+		  return -1;
+		};
+	
+
+		steparray[stepcnt-1] = im->gdes[ptr].step;
+
+		/* adjust start and end of cdef (gdi) so that it runs from
+		   the latest start point to the earliest endpoint of any of the
+		   rras involved (ptr) */
+
+		if(im->gdes[gdi].start < im->gdes[ptr].start)
+		    im->gdes[gdi].start = im->gdes[ptr].start;
+
+		if(im->gdes[gdi].end == 0 
+		   || im->gdes[gdi].end > im->gdes[ptr].end)
+		    im->gdes[gdi].end = im->gdes[ptr].end;
+		
+		/* store pointer to the first element of the rra providing
+		   data for variable, further save step size and data source count
+		   of this rra*/ 
+		im->gdes[gdi].rpnp[rpi].data = 
+		    im->gdes[ptr].data + im->gdes[ptr].ds;
+		im->gdes[gdi].rpnp[rpi].step = im->gdes[ptr].step;
+		im->gdes[gdi].rpnp[rpi].ds_cnt = im->gdes[ptr].ds_cnt;
+	    }
+
+	}
+	if(steparray == NULL){
+	    rrd_set_error("rpn expressions without variables are not supported");
+	    return -1;    
+	}
+	steparray[stepcnt]=0;
+	/* now find the step for the result of the cdef. so that we land on
+	   each step in all of the variables rras */
+
+	im->gdes[gdi].step = lcd(steparray);
+	
+	
+	free(steparray);
+
+	if((im->gdes[gdi].data = malloc(((im->gdes[gdi].end
+				     -im->gdes[gdi].start) 
+				    / im->gdes[gdi].step +1)
+				    * sizeof(double)))==NULL){
+	    rrd_set_error("malloc im->gdes[gdi].data");
+	    return -1;
+	}
+	
+	/* step through the new cdef results array and calculate the values */
+	for (now = im->gdes[gdi].start;
+	     now<=im->gdes[gdi].end;
+	     now += im->gdes[gdi].step){
+	    double    stack[dc_stacksize];
+	    int       stptr=-1;
+	    /* process each op from the rpn in turn */
+	    for (rpi=0;im->gdes[gdi].rpnp[rpi].op != OP_END;rpi++){
+		switch (im->gdes[gdi].rpnp[rpi].op){
+		case OP_NUMBER:
+		    if(stptr>=dc_stacksize){
+			rrd_set_error("RPN stack overflow");
+			return -1;
+		    }
+		    stack[++stptr] = im->gdes[gdi].rpnp[rpi].val;
+		    break;
+		case OP_VARIABLE:
+		    if(stptr>=dc_stacksize){
+			rrd_set_error("RPN stack overflow");
+			return -1;
+		    }
+                    /* make sure we pull the correct value from the *.data array */
+		    /* adjust the pointer into the array acordingly. */
+		    if(now >  im->gdes[gdi].start &&
+		       now % im->gdes[gdi].rpnp[rpi].step == 0){
+			im->gdes[gdi].rpnp[rpi].data +=
+			    im->gdes[gdi].rpnp[rpi].ds_cnt;
+		    }
+		    stack[++stptr] =  *im->gdes[gdi].rpnp[rpi].data;
+		    break;
+		case OP_ADD:
+		    if(stptr<1){
+			rrd_set_error("RPN stack underflow");
+			return -1;
+		    }
+		    stack[stptr-1] = stack[stptr-1] + stack[stptr];
+		    stptr--;
+		    break;
+		case OP_SUB:
+		    if(stptr<1){
+			rrd_set_error("RPN stack underflow");
+			return -1;
+		    }
+		    stack[stptr-1] = stack[stptr-1] - stack[stptr];
+		    stptr--;
+		    break;
+		case OP_MUL:
+		    if(stptr<1){
+			rrd_set_error("RPN stack underflow");
+			return -1;
+		    }
+		    stack[stptr-1] = stack[stptr-1] * stack[stptr];
+		    stptr--;
+		    break;
+		case OP_DIV:
+		    if(stptr<1){
+			rrd_set_error("RPN stack underflow");
+			return -1;
+		    }
+		    stack[stptr-1] = stack[stptr-1] / stack[stptr];
+		    stptr--;
+		    break;
+		case OP_SIN:
+		    if(stptr<0){
+			rrd_set_error("RPN stack underflow");
+			return -1;
+		    }
+		    stack[stptr] = sin(stack[stptr]);
+		    break;
+		case OP_COS:
+		    if(stptr<0){
+			rrd_set_error("RPN stack underflow");
+			return -1;
+		    }
+		    stack[stptr] = cos(stack[stptr]);
+		    break;
+		case OP_LOG:
+		    if(stptr<0){
+			rrd_set_error("RPN stack underflow");
+			return -1;
+		    }
+		    stack[stptr] = log(stack[stptr]);
+		    break;
+		case OP_EXP:
+		    if(stptr<0){
+			rrd_set_error("RPN stack underflow");
+			return -1;
+		    }
+		    stack[stptr] = exp(stack[stptr]);
+		    break;
+		case OP_LT:
+		    if(stptr<1){
+			rrd_set_error("RPN stack underflow");
+			return -1;
+		    }
+		    stack[stptr-1] = stack[stptr-1] < stack[stptr] ? 1.0 : 0.0;
+		    stptr--;
+		    break;
+		case OP_LE:
+		    if(stptr<1){
+			rrd_set_error("RPN stack underflow");
+			return -1;
+		    }
+		    stack[stptr-1] = stack[stptr-1] <= stack[stptr] ? 1.0 : 0.0;
+		    stptr--;
+		    break;
+		case OP_GT:
+		    if(stptr<1){
+			rrd_set_error("RPN stack underflow");
+			return -1;
+		    }
+		    stack[stptr-1] = stack[stptr-1] > stack[stptr] ? 1.0 : 0.0;
+		    stptr--;
+		    break;
+		case OP_GE:
+		    if(stptr<1){
+			rrd_set_error("RPN stack underflow");
+			return -1;
+		    }
+		    stack[stptr-1] = stack[stptr-1] >= stack[stptr] ? 1.0 : 0.0;
+		    stptr--;
+		    break;
+		case OP_EQ:
+		    if(stptr<1){
+			rrd_set_error("RPN stack underflow");
+			return -1;
+		    }
+		    stack[stptr-1] = stack[stptr-1] == stack[stptr] ? 1.0 : 0.0;
+		    stptr--;
+		    break;
+		case OP_IF:
+		    if(stptr<2){
+			rrd_set_error("RPN stack underflow");
+			return -1;
+		    }
+		    stack[stptr-2] = stack[stptr-2] != 0.0 ? stack[stptr-1] : stack[stptr];
+		    stptr--;
+		    stptr--;
+		    break;
+		case OP_UN:
+		    if(stptr<0){
+			rrd_set_error("RPN stack underflow");
+			return -1;
+		    }
+		    stack[stptr] = isnan(stack[stptr]) ? 1.0 : 0.0;
+		    break;
+		case OP_END:
+		    break;
+		}
+	    }
+	    if(stptr!=0){
+		rrd_set_error("RPN final stack size != 1");
+		return -1;
+	    }
+	    im->gdes[gdi].data[++dataidx] = stack[0];
+	}
+    }
+    return 0;
+}
+#undef dc_stacksize
+
+/* massage data so, that we get one value for each x coordinate in the graph */
+int
+data_proc( image_desc_t *im ){
+    long i,ii;
+    double pixstep = (double)(im->end-im->start)
+	/(double)im->xsize; /* how much time 
+			       passes in one pixel */
+    double paintval;
+    double minval=DNAN,maxval=DNAN;
+    
+    unsigned long gr_time;    
+
+    /* memory for the processed data */
+    for(i=0;i<im->gdes_c;i++){
+      if((im->gdes[i].gf==GF_LINE1) ||
+	 (im->gdes[i].gf==GF_LINE2) ||
+	 (im->gdes[i].gf==GF_LINE3) ||
+	 (im->gdes[i].gf==GF_AREA) ||
+	 (im->gdes[i].gf==GF_STACK)){
+	if((im->gdes[i].p_data = malloc((im->xsize +1)
+					* sizeof(rrd_value_t)))==NULL){
+	  rrd_set_error("malloc data_proc");
+	  return -1;
+	}
+      }
+    }
+    
+    for(i=0;i<im->xsize;i++){
+	long vidx;
+	gr_time = im->start+pixstep*i; /* time of the 
+					  current step */
+	paintval=0.0;
+	
+	for(ii=0;ii<im->gdes_c;ii++){
+	    switch(im->gdes[ii].gf){
+	    case GF_LINE1:
+	    case GF_LINE2:
+	    case GF_LINE3:
+	    case GF_AREA:
+		paintval = 0.0;
+	    case GF_STACK:
+		vidx = im->gdes[ii].vidx;
+		paintval +=
+		    im->gdes[vidx].data[
+			(unsigned long)(
+			    (double)(gr_time 
+				 - im->gdes[vidx].start + im->gdes[vidx].step
+				)
+			    / (double)im->gdes[vidx].step
+			    )
+			
+			*im->gdes[vidx].ds_cnt
+			+im->gdes[vidx].ds];
+
+		im->gdes[ii].p_data[i] = paintval;
+		
+		if (! isnan(paintval)){
+		  if (isnan(minval) || paintval <  minval)
+		    minval = paintval;
+		  if (isnan(maxval) || paintval >  maxval)
+		    maxval = paintval;
+		}
+		break;
+	    case GF_PRINT:
+	    case GF_GPRINT:
+	    case GF_COMMENT:
+	    case GF_HRULE:
+	    case GF_VRULE:
+	    case GF_DEF:	       
+	    case GF_CDEF:
+		break;
+	    }
+	}
+    }
+
+    /* if min or max have not been asigned a value this is because
+       there was no data in the graph ... this is not good ...
+       lets set these to dummy values then ... */
+
+    if (isnan(minval)) minval = 0.0;
+    if (isnan(maxval)) maxval = 1.0;
+    
+    /* adjust min and max values */
+    if (isnan(im->minval) 
+	|| ((!im->logarithmic && !im->rigid) /* don't adjust low-end with log scale */
+	    && im->minval > minval))
+	im->minval = minval;
+    if (isnan(im->maxval) 
+	|| (!im->rigid 
+	    && im->maxval < maxval)){
+	if (im->logarithmic)
+	    im->maxval = maxval * 1.1;
+	else
+	    im->maxval = maxval;
+    }
+    /* make sure min and max are not equal */
+    if (im->minval == im->maxval) {
+      im->maxval *= 1.01; 
+      if (! im->logarithmic) {
+	im->minval *= 0.99;
+      }
+      
+      /* make sure min and max are not both zero */
+      if (im->maxval == 0.0) {
+	    im->maxval = 1.0;
+      }
+        
+    }
+    return 0;
+}
+
+
+
+/* identify the point where the first gridline, label ... gets placed */
+
+time_t
+find_first_time(
+    time_t   start, /* what is the initial time */
+    enum tmt_en baseint,  /* what is the basic interval */
+    long     basestep /* how many if these do we jump a time */
+    )
+{
+    struct tm *tm;
+    tm = localtime(&start);
+    switch(baseint){
+    case TMT_SECOND:
+	tm->tm_sec -= tm->tm_sec % basestep; break;
+    case TMT_MINUTE: 
+	tm->tm_sec=0;
+	tm->tm_min -= tm->tm_min % basestep; 
+	break;
+    case TMT_HOUR:
+	tm->tm_sec=0;
+	tm->tm_min = 0;
+	tm->tm_hour -= tm->tm_hour % basestep; break;
+    case TMT_DAY:
+	/* we do NOT look at the basestep for this ... */
+	tm->tm_sec=0;
+	tm->tm_min = 0;
+	tm->tm_hour = 0; break;
+    case TMT_WEEK:
+	/* we do NOT look at the basestep for this ... */
+	tm->tm_sec=0;
+	tm->tm_min = 0;
+	tm->tm_hour = 0;
+	tm->tm_mday -= tm->tm_wday -1 ; break;	/* -1 because we want the monday */
+	if (tm->tm_wday==0) tm->tm_mday -= 7; /* we want the *previous* monday */
+    case TMT_MONTH:
+	tm->tm_sec=0;
+	tm->tm_min = 0;
+	tm->tm_hour = 0;
+	tm->tm_mday = 1;
+	tm->tm_mon -= tm->tm_mon % basestep; break;
+
+    case TMT_YEAR:
+	tm->tm_sec=0;
+	tm->tm_min = 0;
+	tm->tm_hour = 0;
+	tm->tm_mday = 1;
+	tm->tm_mon = 0;
+	tm->tm_year -= (tm->tm_year+1900) % basestep;
+	
+    }
+    return mktime(tm);
+}
+/* identify the point where the next gridline, label ... gets placed */
+time_t 
+find_next_time(
+    time_t   current, /* what is the initial time */
+    enum tmt_en baseint,  /* what is the basic interval */
+    long     basestep /* how many if these do we jump a time */
+    )
+{
+    struct tm *tm;
+    time_t madetime;
+    tm = localtime(&current);
+    do {
+	switch(baseint){
+	case TMT_SECOND:
+	    tm->tm_sec += basestep; break;
+	case TMT_MINUTE: 
+	    tm->tm_min += basestep; break;
+	case TMT_HOUR:
+	    tm->tm_hour += basestep; break;
+	case TMT_DAY:
+	    tm->tm_mday += basestep; break;
+	case TMT_WEEK:
+	    tm->tm_mday += 7*basestep; break;
+	case TMT_MONTH:
+	    tm->tm_mon += basestep; break;
+	case TMT_YEAR:
+	    tm->tm_year += basestep;	
+	}
+	madetime = mktime(tm);
+    } while (madetime == -1); /* this is necessary to skip impssible times
+				 like the daylight saving time skips */
+    return madetime;
+	  
+}
+
+/* create a grid on the graph. it determines what to do
+   from the values of xsize, start and end */
+/* the xaxis labels are determined from the number of seconds per pixel
+   in the requested graph */
+
+
+void gator( gdImagePtr gif, int x, int y){ 
+
+    int li[]={0,0,1, 0,4,5, 0,8,9, 0,12,14, 0,17,17, 0,21,21, 
+	      0,24,24, 0,34,34, 0,40,42, 0,45,45, 0,48,49, 0,52,54, 
+	      0,61,61, 0,64,66, 0,68,70, 0,72,74, 0,76,76, 0,78,78, 
+	      0,80,82, 0,84,85, 
+	      1,0,0, 1,2,2, 1,4,4, 1,6,6, 1,8,8, 1,10,10, 
+	      1,13,13, 1,16,16, 1,18,18, 1,20,20, 1,22,22, 1,24,24, 
+	      1,34,34, 1,41,41, 1,44,44, 1,46,46, 1,48,48, 1,50,50, 
+	      1,53,53, 1,60,60, 1,62,62, 1,64,64, 1,69,69, 1,73,73, 
+	      1,76,76, 1,78,78, 1,80,80, 1,84,84, 1,86,86, 
+	      2,0,1, 2,4,5, 2,8,8, 2,10,10, 2,13,13, 2,16,16, 
+	      2,18,18, 2,20,20, 2,22,22, 2,24,24, 2,33,33, 2,41,41, 
+	      2,44,44, 2,46,46, 2,48,49, 2,53,53, 2,60,60, 2,62,62, 
+	      2,64,65, 2,69,69, 2,73,73, 2,76,77, 2,80,81, 2,84,85, 	      
+	      3,0,0, 3,2,2, 3,4,4, 3,6,6, 3,8,8, 3,10,10, 
+	      3,13,13, 3,16,16, 3,18,18, 3,20,20, 3,22,22, 3,24,24, 
+	      3,32,32, 3,41,41, 3,44,44, 3,46,46, 3,48,48, 3,50,50, 
+	      3,53,53, 3,60,60, 3,62,62, 3,64,64, 3,69,69, 3,73,73, 
+	      3,76,76, 3,78,78, 3,80,80, 3,84,84, 3,86,86, 
+	      4,0,0, 4,2,2, 4,4,4, 4,6,6, 4,8,9, 4,13,13, 
+	      4,17,17, 4,21,21, 4,24,26, 4,32,32, 4,41,41, 4,45,45, 
+	      4,48,49, 4,52,54, 4,61,61, 4,64,66, 4,69,69, 4,72,74, 
+	      4,76,76, 4,78,78, 4,80,82, 4,84,84}; 
+    int i,ii; 
+    for(i=0; i<DIM(li); i=i+3)
+	for(ii=y+li[i+1]; ii<=y+li[i+2];ii++)
+	  gdImageSetPixel(gif,x-li[i],ii,graph_col[GRC_GRID].i); 
+}
+
+/* calculate values required for PRINT and GPRINT functions */
+
+int
+print_calc(image_desc_t *im, char ***prdata) 
+{
+    long i,ii,validsteps;
+    double printval;
+    int graphelement = 0;
+    long vidx;
+    int max_ii;	
+    int prlines = 1;
+    for(i=0;i<im->gdes_c;i++){
+	switch(im->gdes[i].gf){
+	case GF_PRINT:
+	    prlines++;
+	    if((*prdata = realloc(*prdata,prlines*sizeof(char *)))==NULL){
+		rrd_set_error("realloc prdata");
+		return 0;
+	    }
+	case GF_GPRINT:
+	    vidx = im->gdes[i].vidx;
+	    max_ii =((im->gdes[vidx].end 
+		      - im->gdes[vidx].start)
+		     /im->gdes[vidx].step
+		     *im->gdes[vidx].ds_cnt);
+	    printval = DNAN;
+	    validsteps = 0;
+	    for(ii=im->gdes[vidx].ds;
+		ii < max_ii;
+		ii+=im->gdes[vidx].ds_cnt){
+		 if (isnan(im->gdes[vidx].data[ii]))
+		     continue;
+		 if (isnan(printval)){
+		     printval = im->gdes[vidx].data[ii];
+		     validsteps++;
+		    continue;
+		}
+		
+		switch (im->gdes[i].cf){
+		case CF_AVERAGE:
+		    validsteps++;
+		    printval += im->gdes[vidx].data[ii];
+		    break;
+		case CF_MINIMUM:
+		    printval = min( printval, im->gdes[vidx].data[ii]);
+		    break;
+		case CF_MAXIMUM:
+		    printval = max( printval, im->gdes[vidx].data[ii]);
+		    break;
+		case CF_LAST:
+		    printval = im->gdes[vidx].data[ii];
+		}
+	    }
+	    if (im->gdes[i].cf ==  CF_AVERAGE)
+	      if (validsteps > 1) {
+		printval = (printval / validsteps);
+	      }
+	    if (im->gdes[i].gf == GF_PRINT){
+		(*prdata)[prlines-2] = malloc((strlen(im->gdes[i].format)+100)*sizeof(char));
+		sprintf((*prdata)[prlines-2],im->gdes[i].format,printval);
+		(*prdata)[prlines-1] = NULL;
+	    } else {
+		/* GF_GPRINT */
+		sprintf(im->gdes[i].legend,im->gdes[i].format,printval);
+		graphelement = 1;
+	    }
+	    break;
+        case GF_COMMENT:
+	case GF_LINE1:
+	case GF_LINE2:
+	case GF_LINE3:
+	case GF_AREA:
+	case GF_STACK:
+	case GF_HRULE:
+	case GF_VRULE:
+	case GF_DEF:
+	case GF_CDEF:	    
+	    graphelement = 1;
+	    break;
+	}
+    }
+    return graphelement;
+}
+
+
+/* place legends with color spots */
+void
+leg_place(image_desc_t *im)
+{
+    
+    /* graph labels */
+    int   interleg = gdFontSmall->w*2;
+    int   box = gdFontSmall->h*1.2;
+    int   border = gdFontSmall->w*2;
+    int   fill=0, fill_last;
+    int   leg_c = 0;
+    int   leg_x = border, leg_y = im->ygif;
+    int   leg_cc;
+    int   glue = 0;
+    int   i,ii, mark = 0;
+    char  prt_fctn; /*special printfunctions */
+
+    for(i=0;i<im->gdes_c;i++){
+	fill_last = fill;
+
+	leg_cc = strlen(im->gdes[i].legend);
+	
+	/* is there a controle code ant the end of the legend string ? */ 
+	if (leg_cc >= 2 && im->gdes[i].legend[leg_cc-2] == '\\') {
+	    prt_fctn = im->gdes[i].legend[leg_cc-1];
+	    im->gdes[i].legend[leg_cc-2] = '\0';
+	    leg_cc -= 2;
+	} else {
+	    prt_fctn = '\0';
+	}
+
+	if (leg_cc != 0 ){	    
+	    if (fill > 0) 
+		fill += interleg;
+	    if (im->gdes[i].gf != GF_GPRINT && 
+		im->gdes[i].gf != GF_COMMENT) 
+		fill += box; 	   
+	    fill += leg_cc * gdFontSmall->w;
+	    leg_c++;
+	}
+	    
+	if (prt_fctn == '\0') {
+	    if (i == im->gdes_c -1 ) prt_fctn ='l';
+	    
+	    /* is it time to place the legends ? */
+	    if (fill > im->xgif - 2*border){
+		if (leg_c > 1) {
+		    /* go back one */
+		    i--; 
+		    fill = fill_last;
+		    leg_c--;
+		    prt_fctn = 'j';
+		} else {
+		    prt_fctn = 'l';
+		}
+		
+	    }
+	}
+
+
+	if (prt_fctn != '\0'){
+	    leg_x = border;
+	    if (leg_c >= 2 && prt_fctn == 'j') {
+		glue = (im->xgif - fill - 2* border) / (leg_c-1);
+		/* if (glue > 2 * gdFontSmall->w) glue = 0; */
+	    } else {
+		glue = 0;
+	    }
+	    if (prt_fctn =='c') leg_x =  (im->xgif - fill) / 2.0;
+	    if (prt_fctn =='r') leg_x =  im->xgif - fill - border;
+
+	    for(ii=mark;ii<=i;ii++){
+		if(im->gdes[ii].legend[0]=='\0')
+		    continue;
+		im->gdes[ii].legloc.x = leg_x;
+		im->gdes[ii].legloc.y = leg_y;
+		leg_x =  leg_x 
+		    + strlen(im->gdes[ii].legend)*gdFontSmall->w 
+		    + interleg 
+		    + glue;
+		if (im->gdes[ii].gf != GF_GPRINT && 
+		    im->gdes[ii].gf != GF_COMMENT) 
+		    leg_x += box; 	   
+	    }	    
+	    leg_y = leg_y + gdFontSmall->h*1.2;
+	    if (prt_fctn == 's') leg_y += gdFontSmall->h *0.5;
+	    fill = 0;
+	    leg_c = 0;
+	    mark = ii;
+	}	   
+    }
+    im->ygif = leg_y+(border+3);
+}
+
+
+
+int
+horizontal_grid(gdImagePtr gif, image_desc_t   *im)
+{
+    double   range;
+    double   scaledrange;
+    int      pixel,i;
+    int      sgrid,egrid;
+    double   gridstep;
+    double   scaledstep;
+    char     graph_label[100];
+    gdPoint  polyPoints[4];
+    int      labfact,gridind;
+    int      styleMinor[2],styleMajor[2];
+    
+    labfact=2;
+    gridind=-1;
+    range =  im->maxval - im->minval;
+    scaledrange = range / im->magfact;
+
+	/* does the scale of this graph make it impossible to put lines
+	   on it? If so, give up. */
+	if (isnan(scaledrange)) {
+		return 0;
+	}
+
+    styleMinor[0] = graph_col[GRC_GRID].i;
+    styleMinor[1] = gdTransparent;
+
+    styleMajor[0] = graph_col[GRC_MGRID].i;
+    styleMajor[1] = gdTransparent;
+
+    /* find grid spaceing */
+    pixel=1;
+    if(isnan(im->ygridstep)){
+	for(i=0;ylab[i].grid > 0;i++){
+	    pixel = im->ysize / (scaledrange / ylab[i].grid);
+	    if (gridind == -1 && pixel > 5) {
+		gridind = i;
+		break;
+	    }
+	}
+	
+	for(i=0; i<4;i++) {
+	    if (pixel * ylab[gridind].lfac[i] >=  2 * gdFontSmall->h) {
+		labfact =  ylab[gridind].lfac[i];
+		break;
+	    }		          
+	} 
+	
+	gridstep = ylab[gridind].grid * im->magfact;
+    } else {
+	gridstep = im->ygridstep;
+	labfact = im->ylabfact;
+    }
+    
+    polyPoints[0].x=im->xorigin;
+    polyPoints[1].x=im->xorigin+im->xsize;
+    sgrid = (int)( im->minval / gridstep - 1);
+    egrid = (int)( im->maxval / gridstep + 1);
+    scaledstep = gridstep/im->magfact;
+    for (i = sgrid; i <= egrid; i++){
+	polyPoints[0].y=ytr(im,gridstep*i);
+	if ( polyPoints[0].y >= im->yorigin-im->ysize
+	     && polyPoints[0].y <= im->yorigin) {
+	    if(i % labfact == 0){		
+		if (i==0 || im->symbol == ' ') {
+		    if(scaledstep < 1){
+			sprintf(graph_label,"%4.1f",scaledstep*i);
+		    } else {
+			sprintf(graph_label,"%4.0f",scaledstep*i);
+		    }
+		}else {
+		    if(scaledstep < 1){
+			sprintf(graph_label,"%4.1f %c",scaledstep*i, im->symbol);
+		    } else {
+			sprintf(graph_label,"%4.0f %c",scaledstep*i, im->symbol);
+		    }
+		}
+
+		gdImageString(gif, gdFontSmall,
+                              (polyPoints[0].x - (strlen(graph_label) * 
+                                                  gdFontSmall->w)-7), 
+                              polyPoints[0].y - gdFontSmall->h/2+1,
+                              graph_label, graph_col[GRC_FONT].i);
+		
+		gdImageSetStyle(gif, styleMajor, 2);
+
+		gdImageLine(gif, polyPoints[0].x-2,polyPoints[0].y,
+			    polyPoints[0].x+2,polyPoints[0].y,graph_col[GRC_MGRID].i);
+		gdImageLine(gif, polyPoints[1].x-2,polyPoints[0].y,
+			    polyPoints[1].x+2,polyPoints[0].y,graph_col[GRC_MGRID].i);		    
+	    } else {		
+		gdImageSetStyle(gif, styleMinor, 2);
+		gdImageLine(gif, polyPoints[0].x-1,polyPoints[0].y,
+			    polyPoints[0].x+1,polyPoints[0].y,graph_col[GRC_GRID].i);
+		gdImageLine(gif, polyPoints[1].x-1,polyPoints[0].y,
+			    polyPoints[1].x+1,polyPoints[0].y,graph_col[GRC_GRID].i);		    
+	    }	    
+	    gdImageLine(gif, polyPoints[0].x,polyPoints[0].y,
+			polyPoints[1].x,polyPoints[0].y,gdStyled);
+	}	
+    } 
+/*    if(im->minval * im->maxval < 0){
+      polyPoints[0].y=ytr(0);
+      gdImageLine(gif, polyPoints[0].x,polyPoints[0].y,
+      polyPoints[1].x,polyPoints[0].y,graph_col[GRC_MGRID].i);
+      } */
+
+    return 1;
+}
+
+/* logaritmic horizontal grid */
+int
+horizontal_log_grid(gdImagePtr gif, image_desc_t   *im)
+{
+    double   pixpex;
+    int      ii,i;
+    int      minoridx=0, majoridx=0;
+    char     graph_label[100];
+    gdPoint  polyPoints[4];
+    int      styleMinor[2],styleMajor[2];
+    double   value, pixperstep, minstep;
+
+    /* find grid spaceing */
+    pixpex= (double)im->ysize / (log10(im->maxval) - log10(im->minval));
+
+	if (isnan(pixpex)) {
+		return 0;
+	}
+
+    for(i=0;yloglab[i][0] > 0;i++){
+	minstep = log10(yloglab[i][0]);
+	for(ii=1;yloglab[i][ii+1] > 0;ii++){
+	    if(yloglab[i][ii+2]==0){
+		minstep = log10(yloglab[i][ii+1])-log10(yloglab[i][ii]);
+		break;
+	    }
+	}
+	pixperstep = pixpex * minstep;
+	if(pixperstep > 5){minoridx = i;}
+	if(pixperstep > 2 * gdFontSmall->h){majoridx = i;}
+    }
+   
+    styleMinor[0] = graph_col[GRC_GRID].i;
+    styleMinor[1] = gdTransparent;
+
+    styleMajor[0] = graph_col[GRC_MGRID].i;
+    styleMajor[1] = gdTransparent;
+
+    polyPoints[0].x=im->xorigin;
+    polyPoints[1].x=im->xorigin+im->xsize;
+    /* paint minor grid */
+    for (value = pow(10, log10(im->minval) 
+			  - fmod(log10(im->minval),log10(yloglab[minoridx][0])));
+	 value  <= im->maxval;
+	 value *= yloglab[minoridx][0]){
+	if (value < im->minval) continue;
+	i=0;	
+	while(yloglab[minoridx][++i] > 0){	    
+	    polyPoints[0].y = ytr(im,value * yloglab[minoridx][i]);
+	    if (polyPoints[0].y <= im->yorigin - im->ysize) break;
+	    gdImageSetStyle(gif, styleMinor, 2);
+	    gdImageLine(gif, polyPoints[0].x-1,polyPoints[0].y,
+			polyPoints[0].x+1,polyPoints[0].y,graph_col[GRC_GRID].i);
+	    gdImageLine(gif, polyPoints[1].x-1,polyPoints[0].y,
+			polyPoints[1].x+1,polyPoints[0].y,graph_col[GRC_GRID].i);	    
+
+	    gdImageLine(gif, polyPoints[0].x,polyPoints[0].y,
+			polyPoints[1].x,polyPoints[0].y,gdStyled);
+	}
+    }
+
+    /* paint major grid and labels*/
+    for (value = pow(10, log10(im->minval) 
+			  - fmod(log10(im->minval),log10(yloglab[majoridx][0])));
+	 value <= im->maxval;
+	 value *= yloglab[majoridx][0]){
+	if (value < im->minval) continue;
+	i=0;	
+	while(yloglab[majoridx][++i] > 0){	    
+	    polyPoints[0].y = ytr(im,value * yloglab[majoridx][i]);	    
+	    if (polyPoints[0].y <= im->yorigin - im->ysize) break;
+	    gdImageSetStyle(gif, styleMajor, 2);
+	    gdImageLine(gif, polyPoints[0].x-2,polyPoints[0].y,
+			polyPoints[0].x+2,polyPoints[0].y,graph_col[GRC_MGRID].i);
+	    gdImageLine(gif, polyPoints[1].x-2,polyPoints[0].y,
+			polyPoints[1].x+2,polyPoints[0].y,graph_col[GRC_MGRID].i);		    
+	    
+	    gdImageLine(gif, polyPoints[0].x,polyPoints[0].y,
+			polyPoints[1].x,polyPoints[0].y,gdStyled);
+	    sprintf(graph_label,"%3.0e",value * yloglab[majoridx][i]);
+	    gdImageString(gif, gdFontSmall,
+			  (polyPoints[0].x - (strlen(graph_label) * 
+					      gdFontSmall->w)-7), 
+			  polyPoints[0].y - gdFontSmall->h/2+1,
+			  graph_label, graph_col[GRC_FONT].i);	
+	} 
+    }
+	return 1;
+}
+
+
+void
+vertical_grid(
+    gdImagePtr     gif,
+    image_desc_t   *im )
+{   
+    int xlab_sel;		/* which sort of label and grid ? */
+    time_t ti, tilab;
+    long factor;
+    char graph_label[100];
+    gdPoint polyPoints[4];	 /* points for filled graph and more*/
+
+    /* style for grid lines */
+    int     styleDotted[4];
+
+    
+    /* the type of time grid is determined by finding
+       the number of seconds per pixel in the graph */
+    
+    
+    if(im->xlab_user.minsec == -1){
+	factor=(im->end - im->start)/im->xsize;
+	xlab_sel=0;
+	while ( xlab[xlab_sel+1].minsec != -1 
+		&& xlab[xlab_sel+1].minsec <= factor){ xlab_sel++; }
+	im->xlab_user.gridtm = xlab[xlab_sel].gridtm;
+	im->xlab_user.gridst = xlab[xlab_sel].gridst;
+	im->xlab_user.mgridtm = xlab[xlab_sel].mgridtm;
+	im->xlab_user.mgridst = xlab[xlab_sel].mgridst;
+	im->xlab_user.labtm = xlab[xlab_sel].labtm;
+	im->xlab_user.labst = xlab[xlab_sel].labst;
+	im->xlab_user.precis = xlab[xlab_sel].precis;
+	im->xlab_user.stst = xlab[xlab_sel].stst;
+    }
+    
+    /* y coords are the same for every line ... */
+    polyPoints[0].y = im->yorigin;
+    polyPoints[1].y = im->yorigin-im->ysize;
+
+    /* paint the minor grid */
+    for(ti = find_first_time(im->start,
+			    im->xlab_user.gridtm,
+			    im->xlab_user.gridst);
+	ti < im->end; 
+	ti = find_next_time(ti,im->xlab_user.gridtm,im->xlab_user.gridst)
+	){
+	/* are we inside the graph ? */
+	if (ti < im->start || ti > im->end) continue;
+	polyPoints[0].x = xtr(im,ti);
+	styleDotted[0] = graph_col[GRC_GRID].i;
+	styleDotted[1] = gdTransparent;
+
+	gdImageSetStyle(gif, styleDotted, 2);
+
+	gdImageLine(gif, polyPoints[0].x,polyPoints[0].y,
+		    polyPoints[0].x,polyPoints[1].y,gdStyled);
+	gdImageLine(gif, polyPoints[0].x,polyPoints[0].y-1,
+		    polyPoints[0].x,polyPoints[0].y+1,graph_col[GRC_GRID].i);
+	gdImageLine(gif, polyPoints[0].x,polyPoints[1].y-1,
+		    polyPoints[0].x,polyPoints[1].y+1,graph_col[GRC_GRID].i);
+    }
+
+    /* paint the major grid */
+    for(ti = find_first_time(im->start,
+			    im->xlab_user.mgridtm,
+			    im->xlab_user.mgridst);
+	ti < im->end; 
+	ti = find_next_time(ti,im->xlab_user.mgridtm,im->xlab_user.mgridst)
+	){
+	/* are we inside the graph ? */
+	if (ti < im->start || ti > im->end) continue;
+	polyPoints[0].x = xtr(im,ti);
+	styleDotted[0] = graph_col[GRC_MGRID].i;
+	styleDotted[1] = gdTransparent;
+	gdImageSetStyle(gif, styleDotted, 2);
+
+	gdImageLine(gif, polyPoints[0].x,polyPoints[0].y,
+		    polyPoints[0].x,polyPoints[1].y,gdStyled);
+	gdImageLine(gif, polyPoints[0].x,polyPoints[0].y-2,
+		    polyPoints[0].x,polyPoints[0].y+2,graph_col[GRC_MGRID].i);
+	gdImageLine(gif, polyPoints[0].x,polyPoints[1].y-2,
+		    polyPoints[0].x,polyPoints[1].y+2,graph_col[GRC_MGRID].i);
+    }
+    /* paint the labels below the graph */
+    for(ti = find_first_time(im->start,
+			    im->xlab_user.labtm,
+			    im->xlab_user.labst);
+	ti <= im->end; 
+	ti = find_next_time(ti,im->xlab_user.labtm,im->xlab_user.labst)
+	){
+	int gr_pos,width;
+        tilab= ti + im->xlab_user.precis/2; /* correct time for the label */
+
+#if HAVE_STRFTIME
+	strftime(graph_label,99,im->xlab_user.stst,localtime(&tilab));
+#else
+# error "your libc has no strftime I guess we'll abort the exercise here."
+#endif
+	width=strlen(graph_label) *  gdFontSmall->w;
+	gr_pos=xtr(im,tilab) - width/2;
+	if (gr_pos  >= im->xorigin 
+	    && gr_pos + width <= im->xorigin+im->xsize) 
+	    gdImageString(gif, gdFontSmall,
+			  gr_pos,  polyPoints[0].y+4,
+			  graph_label, graph_col[GRC_FONT].i);
+    }
+
+}
+
+
+void 
+axis_paint(
+    image_desc_t   *im,
+    gdImagePtr     gif
+    )
+{   
+    /* draw x and y axis */
+    gdImageLine(gif, im->xorigin+im->xsize,im->yorigin,
+		im->xorigin+im->xsize,im->yorigin-im->ysize,
+		graph_col[GRC_GRID].i);
+    
+    gdImageLine(gif, im->xorigin,im->yorigin-im->ysize,
+		im->xorigin+im->xsize,im->yorigin-im->ysize,
+		graph_col[GRC_GRID].i);
+
+    gdImageLine(gif, im->xorigin-4,im->yorigin,
+		im->xorigin+im->xsize+4,im->yorigin,
+		graph_col[GRC_FONT].i);
+
+    gdImageLine(gif, im->xorigin,im->yorigin,
+		im->xorigin,im->yorigin-im->ysize,
+		graph_col[GRC_GRID].i);
+    
+    /* arrow for X axis direction */
+    gdImageLine(gif, im->xorigin+im->xsize+4, im->yorigin-3, im->xorigin+im->xsize+4, im->yorigin+3,graph_col[GRC_ARROW].i);
+    gdImageLine(gif, im->xorigin+im->xsize+4, im->yorigin-3, im->xorigin+im->xsize+9, im->yorigin,graph_col[GRC_ARROW].i);
+    gdImageLine(gif, im->xorigin+im->xsize+4, im->yorigin+3, im->xorigin+im->xsize+9, im->yorigin,graph_col[GRC_ARROW].i);
+
+    /*    gdImageLine(gif, im->xorigin+im->xsize-1, im->yorigin-3, im->xorigin+im->xsize-1, im->yorigin+3,graph_col[GRC_MGRID].i);
+    gdImageLine(gif, im->xorigin+im->xsize, im->yorigin-2, im->xorigin+im->xsize, im->yorigin+2,graph_col[GRC_MGRID].i);
+    gdImageLine(gif, im->xorigin+im->xsize+1, im->yorigin-2, im->xorigin+im->xsize+1, im->yorigin+2,graph_col[GRC_MGRID].i);
+    gdImageLine(gif, im->xorigin+im->xsize+2, im->yorigin-2, im->xorigin+im->xsize+2, im->yorigin+2,graph_col[GRC_MGRID].i);
+    gdImageLine(gif, im->xorigin+im->xsize+3, im->yorigin-1, im->xorigin+im->xsize+3, im->yorigin+1,graph_col[GRC_MGRID].i);
+    gdImageLine(gif, im->xorigin+im->xsize+4, im->yorigin-1, im->xorigin+im->xsize+4, im->yorigin+1,graph_col[GRC_MGRID].i);
+    gdImageLine(gif, im->xorigin+im->xsize+5, im->yorigin, im->xorigin+im->xsize+5, im->yorigin,graph_col[GRC_MGRID].i); */
+
+
+
+}
+
+void
+grid_paint(
+    image_desc_t   *im,
+    gdImagePtr     gif
+    )
+{   
+    long i;
+    int boxH=8, boxV=8;
+	int res;
+    gdPoint polyPoints[4];	 /* points for filled graph and more*/
+
+    /* draw 3d border */
+    gdImageLine(gif,0,0,im->xgif-1,0,graph_col[GRC_SHADEA].i);
+    gdImageLine(gif,1,1,im->xgif-2,1,graph_col[GRC_SHADEA].i);
+    gdImageLine(gif,0,0,0,im->ygif-1,graph_col[GRC_SHADEA].i);
+    gdImageLine(gif,1,1,1,im->ygif-2,graph_col[GRC_SHADEA].i);
+    gdImageLine(gif,im->xgif-1,0,im->xgif-1,im->ygif-1,graph_col[GRC_SHADEB].i);
+    gdImageLine(gif,0,im->ygif-1,im->xgif-1,im->ygif-1,graph_col[GRC_SHADEB].i);
+    gdImageLine(gif,im->xgif-2,1,im->xgif-2,im->ygif-2,graph_col[GRC_SHADEB].i);
+    gdImageLine(gif,1,im->ygif-2,im->xgif-2,im->ygif-2,graph_col[GRC_SHADEB].i);
+
+
+    vertical_grid(gif, im);
+    
+    /* dont draw horizontal grid if there is no min and max val */
+	if(im->logarithmic){
+		res = horizontal_log_grid(gif,im);
+	} else {
+		res = horizontal_grid(gif,im);
+	}
+    if (! res) {
+       char *nodata = "No Data found";
+       gdImageString(gif, gdFontMediumBold,
+		     im->xgif/2 
+		     - (strlen(nodata)*gdFontMediumBold->w)/2,
+		     (2*im->yorigin-im->ysize) / 2,
+		     nodata, graph_col[GRC_FONT].i);
+    }
+
+
+    /* yaxis description */
+    gdImageStringUp(gif, gdFontSmall,
+		    7,
+		    (im->yorigin - im->ysize/2
+		     +(strlen(im->ylegend)*gdFontSmall->w)/2 ),
+		    im->ylegend, graph_col[GRC_FONT].i);
+    
+
+    /* graph title */
+    gdImageString(gif, gdFontMediumBold,
+		    im->xgif/2 
+		    - (strlen(im->title)*gdFontMediumBold->w)/2,
+		  8,
+		    im->title, graph_col[GRC_FONT].i);
+    
+    /* graph labels */
+
+    for(i=0;i<im->gdes_c;i++){
+	if(im->gdes[i].legend[0] =='\0')
+	    continue;
+	
+	if(im->gdes[i].gf != GF_GPRINT && im->gdes[i].gf != GF_COMMENT){
+	    
+	    polyPoints[0].x = im->gdes[i].legloc.x;
+	    polyPoints[0].y = im->gdes[i].legloc.y+1;
+	    polyPoints[1].x = polyPoints[0].x+boxH;
+	    polyPoints[2].x = polyPoints[0].x+boxH;
+	    polyPoints[3].x = polyPoints[0].x;
+	    polyPoints[1].y = polyPoints[0].y;
+	    polyPoints[2].y = polyPoints[0].y+boxV;
+	    polyPoints[3].y = polyPoints[0].y+boxV;
+	    gdImageFilledPolygon(gif,polyPoints,4,im->gdes[i].col.i);
+	    gdImagePolygon(gif,polyPoints,4,graph_col[GRC_FRAME].i);
+	
+	    gdImageString(gif, gdFontSmall,
+			  polyPoints[0].x+boxH+6, 
+			  polyPoints[0].y-1,
+			  im->gdes[i].legend,
+			  graph_col[GRC_FONT].i);
+	} else {
+	    polyPoints[0].x = im->gdes[i].legloc.x;
+	    polyPoints[0].y = im->gdes[i].legloc.y;
+	    
+	    gdImageString(gif, gdFontSmall,
+			  polyPoints[0].x, 
+			  polyPoints[0].y,
+			  im->gdes[i].legend,
+			  graph_col[GRC_FONT].i);
+	}
+    }
+    
+    
+    gator(gif, (int) im->xgif-5, 5);
+
+}
+
+
+gdImagePtr
+MkLineBrush(image_desc_t *im,long cosel, enum gf_en typsel){
+  gdImagePtr brush;
+  int pen;
+  switch (typsel){
+  case GF_LINE1:
+    brush=gdImageCreate(1,1);
+    break;
+  case GF_LINE2:
+    brush=gdImageCreate(2,2);
+    break;
+  case GF_LINE3:
+    brush=gdImageCreate(3,3);
+    break;
+  default:
+    return NULL;
+  }
+
+  gdImageColorTransparent(brush, 
+			  gdImageColorAllocate(brush, 0, 0, 0));
+
+  pen = gdImageColorAllocate(brush, 
+			     im->gdes[cosel].col.red,
+			     im->gdes[cosel].col.green,
+			     im->gdes[cosel].col.blue);
+    
+  switch (typsel){
+  case GF_LINE1:
+    gdImageSetPixel(brush,0,0,pen);
+    break;
+  case GF_LINE2:
+    gdImageSetPixel(brush,0,0,pen);
+    gdImageSetPixel(brush,0,1,pen);
+    gdImageSetPixel(brush,1,0,pen);
+    gdImageSetPixel(brush,1,1,pen);
+    break;
+  case GF_LINE3:
+    gdImageSetPixel(brush,1,0,pen);
+    gdImageSetPixel(brush,0,1,pen);
+    gdImageSetPixel(brush,1,1,pen);
+    gdImageSetPixel(brush,2,1,pen);
+    gdImageSetPixel(brush,1,2,pen);
+    break;
+  default:
+    return NULL;
+  }
+  return brush;
+}
+
+/* draw that picture thing ... */
+int
+graph_paint(image_desc_t *im, char ***calcpr)
+{
+    int i,ii;
+    FILE  *fo;
+    
+    /* gif stuff */
+    gdImagePtr	gif,brush;
+
+    double areazero = 0.0;
+    enum gf_en  lastgf = GF_LINE1;    
+    gdPoint canvas[4], back[4];	 /* points for canvas*/
+
+    /* pull the data from the rrd files ... */
+    if(data_fetch(im)==-1)
+	return -1;
+
+    /* evaluate CDEF  operations ... */
+    if(data_calc(im)==-1)
+	return -1;
+
+    /* calculate and PRINT and GPRINT definitions. We have to do it at
+     * this point because it will affect the length of the legends
+     * if there are no graph elements we stop here ... 
+     */
+    if(print_calc(im,calcpr)==0)
+	return 0;
+
+    /* get actual drawing data and find min and max values*/
+    if(data_proc(im)==-1)
+	return -1;
+
+    if(!im->logarithmic){si_unit(im);}        /* identify si magnitude Kilo, Mega Giga ? */
+
+    if(!im->rigid && ! im->logarithmic)
+	expand_range(im);   /* make sure the upper and lower limit are
+			   sensible values */
+
+    /* init xtr and ytr */
+    /* determine the actual size of the gif to draw. The size given
+       on the cmdline is the graph area. But we need more as we have
+       draw labels and other things outside the graph area */
+
+
+    im->xorigin = 10 + 9 * gdFontSmall->w+gdFontSmall->h;
+    xtr(im,0); 
+
+    im->yorigin = 14 + im->ysize;
+    ytr(im,DNAN);
+
+    if(im->title[0] != '\0')
+	im->yorigin += (gdFontMediumBold->h+4);
+
+    im->xgif=20+im->xsize + im->xorigin;
+    im->ygif= im->yorigin+2*gdFontSmall->h;
+    
+    /* determine where to place the legends onto the graphics.
+       and set im->ygif to match space requirements for text */
+    leg_place(im);
+
+    gif=gdImageCreate(im->xgif,im->ygif);
+
+    gdImageInterlace(gif, im->interlaced);
+    
+    /* allocate colors for the screen elements */
+    for(i=0;i<DIM(graph_col);i++)
+	/* check for user override values */
+	if(im->graph_col[i].red != -1)
+	    graph_col[i].i = 
+		gdImageColorAllocate( gif,
+				      im->graph_col[i].red, 
+				      im->graph_col[i].green, 
+				      im->graph_col[i].blue);
+	else
+	    graph_col[i].i = 
+		gdImageColorAllocate( gif,
+				      graph_col[i].red, 
+				      graph_col[i].green, 
+				      graph_col[i].blue);
+	
+    
+    /* allocate colors for the graph */
+    for(i=0;i<im->gdes_c;i++)
+	/* only for elements which have a color defined */
+	if (im->gdes[i].col.red != -1)
+	    im->gdes[i].col.i = 
+		gdImageColorAllocate(gif,
+				     im->gdes[i].col.red,
+				     im->gdes[i].col.green,
+				     im->gdes[i].col.blue);
+    
+    
+    /* the actual graph is created by going through the individual
+       graph elements and then drawing them */
+    
+    back[0].x = 0;
+    back[0].y = 0;
+    back[1].x = back[0].x+im->xgif;
+    back[1].y = back[0].y;
+    back[2].x = back[1].x;
+    back[2].y = back[0].y+im->ygif;
+    back[3].x = back[0].x;
+    back[3].y = back[2].y;
+
+    gdImageFilledPolygon(gif,back,4,graph_col[GRC_BACK].i);
+
+    canvas[0].x = im->xorigin;
+    canvas[0].y = im->yorigin;
+    canvas[1].x = canvas[0].x+im->xsize;
+    canvas[1].y = canvas[0].y;
+    canvas[2].x = canvas[1].x;
+    canvas[2].y = canvas[0].y-im->ysize;
+    canvas[3].x = canvas[0].x;
+    canvas[3].y = canvas[2].y;
+
+    gdImageFilledPolygon(gif,canvas,4,graph_col[GRC_CANVAS].i);
+
+    if (im->minval > 0.0)
+	areazero = im->minval;
+    if (im->maxval < 0.0)
+	areazero = im->maxval;
+
+    axis_paint(im,gif);
+
+    for(i=0;i<im->gdes_c;i++){	
+        
+	switch(im->gdes[i].gf){
+	case GF_CDEF:
+	case GF_DEF:
+	case GF_PRINT:
+	case GF_GPRINT:
+	case GF_COMMENT:
+	case GF_HRULE:
+	case GF_VRULE:
+	  break;
+	case GF_LINE1:
+	case GF_LINE2:
+	case GF_LINE3:
+	case GF_AREA:
+	    
+	    lastgf = im->gdes[i].gf;	    
+	case GF_STACK:	    
+           if (im->gdes[i].col.i != -1){               
+	       /* GF_LINE and frined */
+	       if(lastgf == GF_LINE1 || lastgf == GF_LINE2 || lastgf == GF_LINE3 ){
+		   brush = MkLineBrush(im,i,lastgf);
+		   gdImageSetBrush(gif, brush);
+		   for(ii=1;ii<im->xsize;ii++){
+		       if (isnan(im->gdes[i].p_data[ii-1]) ||
+			   isnan(im->gdes[i].p_data[ii]))
+                            continue;
+                        gdImageLine(gif,
+                                    ii+im->xorigin-1,ytr(im,im->gdes[i].p_data[ii-1]),
+                                    ii+im->xorigin,ytr(im,im->gdes[i].p_data[ii]),
+                                    gdBrushed);
+                        
+                    }
+                    gdImageDestroy(brush);
+                }
+                else 
+                    /* GF_AREA STACK type*/
+                    if (im->gdes[i].gf == GF_STACK )
+                        for(ii=0;ii<im->xsize;ii++){
+                            if ((i>0 && isnan(im->gdes[i-1].p_data[ii])) ||
+                                isnan(im->gdes[i].p_data[ii]))
+                                continue;
+                            gdImageLine(gif,
+                                        ii+im->xorigin,ytr(im,im->gdes[i-1].p_data[ii]),
+                                        ii+im->xorigin,ytr(im,im->gdes[i].p_data[ii]),
+                                        im->gdes[i].col.i);
+                        }
+                
+                    else /* simple GF_AREA */
+                        for(ii=0;ii<im->xsize;ii++){
+                            if (isnan(im->gdes[i].p_data[ii]))
+                                continue;
+                            gdImageLine(gif,
+                                        ii+im->xorigin,ytr(im,areazero),
+                                        ii+im->xorigin,ytr(im,im->gdes[i].p_data[ii]),
+                                        im->gdes[i].col.i);
+                        }
+	   }
+	   
+	   break;
+	}
+    }
+    
+    grid_paint(im,gif);
+
+    /* the RULES are the last thing to paint ... */
+    for(i=0;i<im->gdes_c;i++){	
+        
+	switch(im->gdes[i].gf){
+	case GF_HRULE:
+	    if(im->gdes[i].yrule >= im->minval
+	       && im->gdes[i].yrule <= im->maxval)
+	      gdImageLine(gif,
+			  im->xorigin,ytr(im,im->gdes[i].yrule),
+			  im->xorigin+im->xsize,ytr(im,im->gdes[i].yrule),
+			  im->gdes[i].col.i); 
+	    break;
+	case GF_VRULE:
+	  if(im->gdes[i].xrule >= im->start
+	     && im->gdes[i].xrule <= im->end)
+	    gdImageLine(gif,
+			xtr(im,im->gdes[i].xrule),im->yorigin,
+			xtr(im,im->gdes[i].xrule),im->yorigin-im->ysize,
+			im->gdes[i].col.i); 
+	  break;
+	default:
+	    break;
+	}
+    }
+
+    if (strcmp(im->graphfile,"-")==0) {
+	fo = stdout;
+    } else {
+	if ((fo = fopen(im->graphfile,"wb")) == NULL) {
+	    perror("rrd_graph gif write:");
+	    rrd_set_error("cannot open %s for write",im->graphfile);
+	    return (-1);
+	}
+    }
+    gdImageGif(gif, fo);    
+    if (strcmp(im->graphfile,"-") != 0)
+	fclose(fo);
+    gdImageDestroy(gif);
+    return 0;
+}
+
+
+/*****************************************************
+ * graph stuff 
+ *****************************************************/
+
+int
+gdes_alloc(image_desc_t *im){
+
+    long def_step = (im->end-im->start)/im->xsize;
+
+    im->gdes_c++;
+    
+    if ((im->gdes = (graph_desc_t *) realloc(im->gdes, (im->gdes_c)
+					   * sizeof(graph_desc_t)))==NULL){
+	rrd_set_error("realloc graph_descs");
+	return -1;
+    }
+
+
+    im->gdes[im->gdes_c-1].step=def_step; 
+    im->gdes[im->gdes_c-1].start=im->start; 
+    im->gdes[im->gdes_c-1].end=im->end; 
+    im->gdes[im->gdes_c-1].vname[0]='\0'; 
+    im->gdes[im->gdes_c-1].data=NULL;
+    im->gdes[im->gdes_c-1].ds_namv=NULL;
+    im->gdes[im->gdes_c-1].data_first=0;
+    im->gdes[im->gdes_c-1].p_data=NULL;
+    im->gdes[im->gdes_c-1].rpnp=NULL;
+    im->gdes[im->gdes_c-1].col.red = -1;
+    im->gdes[im->gdes_c-1].col.i=-1;
+    im->gdes[im->gdes_c-1].legend[0]='\0';
+    im->gdes[im->gdes_c-1].rrd[0]='\0';
+    im->gdes[im->gdes_c-1].ds=-1;    
+    im->gdes[im->gdes_c-1].p_data=NULL;    
+    return 0;
+}
+
+/* copies input untill the first unescaped colon is found
+   or until input ends. backslashes have to be escaped as well */
+int
+scan_for_col(char *input, int len, char *output)
+{
+    int inp,outp=0;
+    for (inp=0; 
+	 inp < len &&
+	   input[inp] != ':' &&
+	   input[inp] != '\0';
+	 inp++){
+      if (input[inp] == '\\' &&
+	  input[inp+1] != '\0' &&
+	  input[inp+1] == ':')
+	output[outp++] = input[++inp];
+      else
+	output[outp++] = input[inp];
+    }
+    output[outp] = '\0';
+    return inp;
+}
+
+int 
+rrd_graph(int argc, char **argv, char ***prdata, int *xsize, int *ysize)
+{
+    
+    image_desc_t   im;
+    int            i;
+    long           long_tmp,start_tmp,end_tmp;
+    char           scan_gtm[12],scan_mtm[12],scan_ltm[12],col_nam[12];
+    char           symname[100];
+    unsigned int            col_red,col_green,col_blue;
+    long           scancount;
+    int linepass = 0; /* stack can only follow directly after LINE* AREA or STACK */    
+#ifdef WANT_AT_STYLE_TIMESPEC
+    struct time_value start_tv, end_tv;
+    char *parsetime_error = NULL;
+    int start_tmp_is_ok = 0,
+	end_tmp_is_ok = 0;
+#endif
+
+    /* default values */
+    end_tmp = time(NULL);
+    start_tmp = -24*3600;
+#ifdef WANT_AT_STYLE_TIMESPEC
+    end_tv.type = ABSOLUTE_TIME;
+    end_tv.tm = *localtime(&end_tmp);
+    end_tv.offset = 0;
+
+    start_tv.type = RELATIVE_TO_END_TIME;
+    start_tv.tm = *localtime(&end_tmp); /* to init tm_zone and tm_gmtoff */
+    start_tv.offset = -24*3600;/* to be compatible with the original code.  */
+    start_tv.tm.tm_sec = 0;    /** alternatively we could set tm_mday to -1 */
+    start_tv.tm.tm_min = 0;    /** but this would yield -23(25) hours offset */
+    start_tv.tm.tm_hour = 0;   /** twice a year, when DST is coming in or   */
+    start_tv.tm.tm_mday = 0;   /** out of effect                            */
+    start_tv.tm.tm_mon = 0;
+    start_tv.tm.tm_year = 0;
+    start_tv.tm.tm_wday = 0;
+    start_tv.tm.tm_yday = 0;
+    start_tv.tm.tm_isdst = -1; /* for mktime to guess */
+#endif
+    im.xlab_user.minsec = -1;
+    im.xgif=0;
+    im.ygif=0;
+    im.xsize = 400;
+    im.ysize = 100;
+    im.ylegend[0] = '\0';
+    im.title[0] = '\0';
+    im.minval = DNAN;
+    im.maxval = DNAN;    
+    im.interlaced = 0;
+    im.rigid = 0;
+    im.logarithmic = 0;
+    im.ygridstep = DNAN;
+    im.base = 1000;
+    im.gdes_c = 0;
+    im.gdes = NULL;
+
+
+    for(i=0;i<DIM(graph_col);i++)
+	im.graph_col[i].red=-1;
+    
+    
+    while (1){
+	static struct option long_options[] =
+	{
+	    {"start",      required_argument, 0, 's'},
+	    {"end",        required_argument,0,'e'},
+	    {"x-grid",     required_argument,0,'x'},
+	    {"y-grid",     required_argument,0,'y'},
+	    {"vertical-label",required_argument,0,'v'},
+	    {"width",      required_argument,0,'w'},
+	    {"height",     required_argument,0,'h'},
+	    {"interlaced", no_argument,0,'i'},
+	    {"upper-limit",required_argument,0,'u'},
+	    {"lower-limit",required_argument,0,'l'},
+	    {"rigid",      no_argument,0,'r'},
+	    {"base",       required_argument,0,'b'},
+	    {"logarithmic",no_argument,0,'o'},
+	    {"color",      required_argument,0,'c'},
+	    {"title",      required_argument,0,'t'},
+	    {0,0,0,0}};
+	int option_index = 0;
+	int opt;
+
+	
+	opt = getopt_long(argc, argv, 
+			  "s:e:x:y:v:w:h:iu:b:l:roc:t:",
+			  long_options, &option_index);
+
+	if (opt == EOF)
+	    break;
+	
+	switch(opt) {
+	case 's':
+	    if(im.gdes_c > 0){
+		rrd_set_error("set start before graphing");
+		im_free(&im);
+		return -1;
+	    }
+#ifdef WANT_AT_STYLE_TIMESPEC
+	    {
+	    char *endp;
+	    start_tmp_is_ok = 0;
+	    start_tmp = strtol(optarg, &endp, 0);
+	    if (*endp == '\0') /* it was a valid number */
+	        if (start_tmp > 31122038 || /* 31 Dec 2038 in DDMMYYYY */
+		    start_tmp < 0) {
+		    start_tmp_is_ok = 1;
+		    break;
+		}
+	    if ((parsetime_error = parsetime(optarg, &start_tv))) {
+	        rrd_set_error( "start time: %s", parsetime_error );
+		im_free(&im);
+		return -1;
+	     }
+	    }
+#else
+	    start_tmp = atol(optarg);
+#endif
+	    break;
+	case 'e':
+	    if(im.gdes_c > 0){
+		rrd_set_error("set end before graphing");
+		im_free(&im);
+		return -1;
+	    }
+#ifdef WANT_AT_STYLE_TIMESPEC
+	    {
+	    char *endp;
+	    end_tmp_is_ok = 0;
+	    end_tmp = strtol(optarg, &endp, 0);
+	    if (*endp == '\0') /* it was a valid number */
+	        if (end_tmp > 31122038) { /* 31 Dec 2038 in DDMMYYYY */
+		    end_tmp_is_ok = 1;
+		    break;
+		}
+	    if ((parsetime_error = parsetime(optarg, &end_tv))) {
+	        rrd_set_error( "end time: %s", parsetime_error );
+		im_free(&im);
+		return -1;
+	     }
+	    }
+#else
+	    end_tmp = atol(optarg);
+#endif
+	    break;
+	case 'x':
+	    if(sscanf(optarg,
+		      "%10[A-Z]:%lu:%10[A-Z]:%lu:%10[A-Z]:%lu:%lu:%100s",
+		      scan_gtm,
+		      &im.xlab_user.gridst,
+		      scan_mtm,
+		      &im.xlab_user.mgridst,
+		      scan_ltm,
+		      &im.xlab_user.labst,
+		      &im.xlab_user.precis,
+		      im.xlab_form) == 8){
+		if((im.xlab_user.gridtm = tmt_conv(scan_gtm)) == -1){
+		    rrd_set_error("unknown keyword %s",scan_gtm);
+		    im_free(&im);		    return -1;
+		} else if ((im.xlab_user.mgridtm = tmt_conv(scan_mtm)) == -1){
+		    rrd_set_error("unknown keyword %s",scan_mtm);
+		    im_free(&im);		    return -1;
+		} else if ((im.xlab_user.labtm = tmt_conv(scan_ltm)) == -1){
+		    rrd_set_error("unknown keyword %s",scan_ltm);
+		    im_free(&im);		    return -1;
+		} 
+		im.xlab_user.minsec = 1;
+		im.xlab_user.stst = im.xlab_form;
+	    } else {
+		rrd_set_error("invalid xgrid format");
+		im_free(&im);return -1;
+	    }
+	    break;
+	case 'y':
+	    if(sscanf(optarg,
+		      "%lf:%d",
+		      &im.ygridstep,
+		      &im.ylabfact) == 2) {
+		if(im.ygridstep<=0){
+		    rrd_set_error("grid step must be > 0");
+		    im_free(&im);return -1;
+		} else if (im.ylabfact < 1){
+		    rrd_set_error("label factor must be > 0");
+		    im_free(&im);return -1;
+		} 
+	    } else {
+		rrd_set_error("invalid ygrid format");
+		im_free(&im);return -1;
+	    }
+	    break;
+	case 'v':
+	    strncpy(im.ylegend,optarg,150);
+	    break;
+	case 'u':
+	    im.maxval = atof(optarg);
+	    break;
+	case 'l':
+	    im.minval = atof(optarg);
+	    break;
+	case 'b':
+	    im.base = atol(optarg);
+	    if(im.base != 1024 && im.base != 1000 ){
+		rrd_set_error("the only sensible value for base apart from 1000 is 1024");
+		im_free(&im);
+		return -1;
+	    }
+	    break;
+	case 'w':
+	    long_tmp = atol(optarg);
+	    if(im.gdes_c > 0){
+		rrd_set_error("set width before graphing");
+		im_free(&im);
+		return -1;
+	    }
+	    if (long_tmp < 10) {
+		rrd_set_error("width below 10 pixels");
+		im_free(&im);return -1;
+	    }
+	    im.xsize = long_tmp;
+	    break;
+	case 'h':
+	    long_tmp = atol(optarg);
+	    if (long_tmp < 10) {
+		rrd_set_error("height below 10 pixels");
+		im_free(&im);		return -1;
+	    }
+	    im.ysize = long_tmp;
+	    break;
+	case 'i':
+	    im.interlaced = 1;
+	    break;
+	case 'r':
+	    im.rigid = 1;
+	    break;
+	case 'o':
+	    im.logarithmic = 1;
+	    if (isnan(im.minval))
+		im.minval=1;
+	    break;
+	case 'c':
+	    if(sscanf(optarg,
+		      "%10[A-Z]#%2x%2x%2x",
+		      col_nam,&col_red,&col_green,&col_blue) == 4){
+		int ci;
+		if((ci=grc_conv(col_nam)) != -1){
+		    im.graph_col[ci].red=col_red;
+		    im.graph_col[ci].green=col_green;
+		    im.graph_col[ci].blue=col_blue;
+		}  else {
+		  rrd_set_error("invalid color name '%s'",col_nam);
+		}
+	    } else {
+		rrd_set_error("invalid color def format");
+		im_free(&im);return -1;
+	    }
+	    break;	  
+	case 't':
+	    strncpy(im.title,optarg,150);
+	    break;
+
+	case '?':
+	    rrd_set_error("unknown option '%s'",argv[optind-1]);
+	    return(-1);
+	}
+    }
+
+    if (im.logarithmic == 1 && (im.minval <= 0 || isnan(im.minval))){
+	rrd_set_error("for a logarithmic yaxis you must specify a lower-limit > 0");
+	return(-1);
+    }
+
+    strncpy(im.graphfile,argv[optind],254);
+
+#ifdef WANT_AT_STYLE_TIMESPEC
+    if ((start_tv.type == RELATIVE_TO_END_TIME ||
+	   (start_tmp_is_ok && start_tmp < 0)) && /* same as the line above */
+           end_tv.type == RELATIVE_TO_START_TIME) {
+	rrd_set_error("the start and end times cannot be specified "
+		      "relative to each other");
+	return(-1);
+    }
+
+    if (start_tv.type == RELATIVE_TO_START_TIME) {
+	rrd_set_error("the start time cannot be specified relative to itself");
+	return(-1);
+    }
+
+    if (end_tv.type == RELATIVE_TO_END_TIME) {
+	rrd_set_error("the end time cannot be specified relative to itself");
+	return(-1);
+    }
+
+    /* We don't care to keep all the values in their range,
+       mktime will do this for us */
+    if (start_tv.type == RELATIVE_TO_END_TIME) {
+	if (end_tmp_is_ok)
+	    end_tv.tm = *localtime( &end_tmp );
+	start_tv.tm.tm_sec  += end_tv.tm.tm_sec; 
+	start_tv.tm.tm_min  += end_tv.tm.tm_min; 
+	start_tv.tm.tm_hour += end_tv.tm.tm_hour; 
+	start_tv.tm.tm_mday += end_tv.tm.tm_mday; 
+	start_tv.tm.tm_mon  += end_tv.tm.tm_mon; 
+	start_tv.tm.tm_year += end_tv.tm.tm_year; 
+    }
+    if (end_tv.type == RELATIVE_TO_START_TIME) {
+	if (start_tmp_is_ok)
+	    start_tv.tm = *localtime( &start_tmp );
+	end_tv.tm.tm_sec  += start_tv.tm.tm_sec; 
+	end_tv.tm.tm_min  += start_tv.tm.tm_min; 
+	end_tv.tm.tm_hour += start_tv.tm.tm_hour; 
+	end_tv.tm.tm_mday += start_tv.tm.tm_mday; 
+	end_tv.tm.tm_mon  += start_tv.tm.tm_mon; 
+	end_tv.tm.tm_year += start_tv.tm.tm_year; 
+    }
+    if (!start_tmp_is_ok)
+        start_tmp = mktime(&start_tv.tm) + start_tv.offset;
+    if (!end_tmp_is_ok)
+        end_tmp = mktime(&end_tv.tm) + end_tv.offset;
+#endif
+
+    if (start_tmp < 0) 
+	start_tmp = end_tmp + start_tmp;
+    
+    if (start_tmp < 3600*24*365*10){
+	rrd_set_error("the first entry to fetch should be after 1980 (%ld)",start_tmp);
+	return(-1);
+    }
+    
+    if (end_tmp < start_tmp) {
+	rrd_set_error("start (%ld) should be less than end (%ld)", 
+	       start_tmp, end_tmp);
+	return(-1);
+    }
+    
+    im.start = start_tmp;
+    im.end = end_tmp;
+    
+    for(i=optind+1;i<argc;i++){
+	int   argstart=0;
+	int   strstart=0;
+	char  varname[30],rpnex[256];
+	gdes_alloc(&im);
+	if(sscanf(argv[i],"%10[A-Z0-9]:%n",symname,&argstart)==1){
+            if((im.gdes[im.gdes_c-1].gf=gf_conv(symname))==-1){
+                im_free(&im);
+                rrd_set_error("unknown function '%s'",symname);
+                return -1;
+            }
+	} else {
+	    rrd_set_error("can't parse '%s'",argv[i]);
+            im_free(&im);
+            return -1;
+	}
+	/* reset linepass if a non LINE/STACK/AREA operator gets parsed */
+	if (im.gdes[im.gdes_c-1].gf != GF_LINE1 &&
+	    im.gdes[im.gdes_c-1].gf != GF_LINE2 &&
+	    im.gdes[im.gdes_c-1].gf != GF_LINE3 &&
+	    im.gdes[im.gdes_c-1].gf != GF_AREA &&
+	    im.gdes[im.gdes_c-1].gf != GF_STACK) {
+	  linepass = 0;
+	}
+	/* allow \: to use : in strings */
+	
+
+	/* if we are still alive we got a valid graph operator */
+
+	switch(im.gdes[im.gdes_c-1].gf){
+   	case GF_PRINT:
+	case GF_GPRINT:
+	    if(sscanf(
+		&argv[i][argstart],
+		"%29[^#:]:" CF_NAM_FMT ":%n",
+		varname,symname,&strstart) == 2){
+		scan_for_col(&argv[i][argstart+strstart],FMT_LEG_LEN,im.gdes[im.gdes_c-1].format);
+		if((im.gdes[im.gdes_c-1].vidx=find_var(&im,varname))==-1){
+		    im_free(&im);
+		    rrd_set_error("unknown variable '%s'",varname);
+		    return -1;
+		}	
+		if((im.gdes[im.gdes_c-1].cf=cf_conv(symname))==-1){
+		    im_free(&im);
+		    return -1;
+		}
+		
+	    } else {
+		im_free(&im);
+		rrd_set_error("can't parse '%s'",&argv[i][argstart]);
+		return -1;
+	    }
+	    break;
+   	case GF_COMMENT:
+	    if(strlen(&argv[i][argstart])>FMT_LEG_LEN) argv[i][argstart+FMT_LEG_LEN-3]='\0' ;
+	    strcpy(im.gdes[im.gdes_c-1].legend, &argv[i][argstart]);
+	    break;
+	case GF_HRULE:
+	    if(sscanf(
+		&argv[i][argstart],
+		"%lf#%2x%2x%2x:%n",
+		&im.gdes[im.gdes_c-1].yrule,
+		&col_red,&col_green,&col_blue,
+		&strstart) >=  4){
+		im.gdes[im.gdes_c-1].col.red = col_red;
+		im.gdes[im.gdes_c-1].col.green = col_green;
+		im.gdes[im.gdes_c-1].col.blue = col_blue;
+		if(strstart <= 0){
+		   im.gdes[im.gdes_c-1].legend[0] = '\0';
+		} else { 
+		    scan_for_col(&argv[i][argstart+strstart],FMT_LEG_LEN,im.gdes[im.gdes_c-1].legend);
+		}
+	    } else {
+		im_free(&im);
+		rrd_set_error("can't parse '%s'",&argv[i][argstart]);
+		return -1;
+	    } 
+	    break;
+	case GF_VRULE:
+	    if(sscanf(
+		&argv[i][argstart],
+		"%lu#%2x%2x%2x:%n",
+		&im.gdes[im.gdes_c-1].xrule,
+		&col_red,
+		&col_green,
+		&col_blue,
+		&strstart) >=  4){
+		im.gdes[im.gdes_c-1].col.red = col_red;
+		im.gdes[im.gdes_c-1].col.green = col_green;
+		im.gdes[im.gdes_c-1].col.blue = col_blue;
+		if(strstart <= 0){                    
+		   im.gdes[im.gdes_c-1].legend[0] = '\0';
+		} else { 
+		    scan_for_col(&argv[i][argstart+strstart],FMT_LEG_LEN,im.gdes[im.gdes_c-1].legend);
+		}
+	    } else {
+		im_free(&im);
+		rrd_set_error("can't parse '%s'",&argv[i][argstart]);
+		return -1;
+	    }
+	    break;
+	case GF_STACK:
+	    if(linepass == 0){
+		im_free(&im);
+		rrd_set_error("STACK must follow AREA, LINE or STACK");
+		return -1; 
+	    }		
+	case GF_LINE1:
+	case GF_LINE2:
+	case GF_LINE3:
+	case GF_AREA:
+	    linepass = 1;
+	    if((scancount=sscanf(
+		&argv[i][argstart],
+		"%29[^:#]#%2x%2x%2x:%n",
+		varname,
+		&col_red,
+		&col_green,
+		&col_blue,
+		&strstart))>=1){
+		im.gdes[im.gdes_c-1].col.red = col_red;
+		im.gdes[im.gdes_c-1].col.green = col_green;
+		im.gdes[im.gdes_c-1].col.blue = col_blue;
+		if(strstart <= 0){
+		   im.gdes[im.gdes_c-1].legend[0] = '\0';
+		} else { 
+		    scan_for_col(&argv[i][argstart+strstart],FMT_LEG_LEN,im.gdes[im.gdes_c-1].legend);
+		}
+		if((im.gdes[im.gdes_c-1].vidx=find_var(&im,varname))==-1){
+		    im_free(&im);
+		    rrd_set_error("unknown variable '%s'",varname);
+		    return -1;
+		}		
+		if (scancount < 4)
+		    im.gdes[im.gdes_c-1].col.red = -1;		
+		
+	    } else {
+		im_free(&im);
+		rrd_set_error("can't parse '%s'",&argv[i][argstart]);
+		return -1;
+	    }
+	    break;
+	case GF_CDEF:
+	    if(sscanf(
+		&argv[i][argstart],
+		"%29[_A-Za-z0-9]=%254[^: ]",
+		im.gdes[im.gdes_c-1].vname,
+		rpnex) != 2){
+		im_free(&im);
+		rrd_set_error("can't parse CDEF '%s'",&argv[i][argstart]);
+		return -1;
+	    }
+	    /* checking for duplicate DEF CDEFS */
+	    if(find_var(&im,im.gdes[im.gdes_c-1].vname) != -1){
+		im_free(&im);
+		rrd_set_error("duplicate variable '%s'",
+		       im.gdes[im.gdes_c-1].vname);
+		return -1; 
+	    }	   
+	    if((im.gdes[im.gdes_c-1].rpnp = str2rpn(&im,rpnex))== NULL){
+		rrd_set_error("invalid rpn expression '%s'", rpnex);
+		im_free(&im);		
+		return -1;
+	    }
+
+	    break;
+	case GF_DEF:
+#ifdef WIN32
+/* count the number of ':', if 2 : short filename, if 3 : complete filename */
+	{
+	    char * a; int cnt = 0;
+	    for ( a = &argv[i][argstart]; *a !=0; a++  ) {
+		if ( *a == ':' ) cnt++;
+	    }
+	    if (cnt == 3) {
+		if(sscanf(
+		    &argv[i][argstart],
+		    "%29[_A-Za-z0-9]=%1[A-Za-z]:%252[^:]:" DS_NAM_FMT ":" CF_NAM_FMT,
+		    im.gdes[im.gdes_c-1].vname,
+		    im.gdes[im.gdes_c-1].rrd,im.gdes[im.gdes_c-1].rrd+2,
+		    im.gdes[im.gdes_c-1].ds_nam,
+		    symname) != 5) {
+		    im_free(&im);
+		    rrd_set_error("can't parse DEF '%s'",&argv[i][argstart]);
+		    return -1;
+		}
+		*(im.gdes[im.gdes_c-1].rrd+1) = ':';
+	    } else {
+#endif /*WIN32*/
+		if(sscanf(
+		    &argv[i][argstart],
+		    "%29[_A-Za-z0-9]=%254[^:]:" DS_NAM_FMT ":" CF_NAM_FMT,
+		    im.gdes[im.gdes_c-1].vname,
+		    im.gdes[im.gdes_c-1].rrd,
+		    im.gdes[im.gdes_c-1].ds_nam,
+		    symname) != 4){
+		    im_free(&im);
+		    rrd_set_error("can't parse DEF '%s'",&argv[i][argstart]);
+		    return -1;
+		}
+#ifdef WIN32
+	    }
+	}
+#endif /*WIN32*/
+
+	    /* checking for duplicate DEF CDEFS */
+	    if(find_var(&im,im.gdes[im.gdes_c-1].vname) != -1){
+		im_free(&im);
+		rrd_set_error("duplicate variable '%s'",
+		       im.gdes[im.gdes_c-1].vname);
+		return -1; 
+	    }	   
+	    if((im.gdes[im.gdes_c-1].cf=cf_conv(symname))==-1){
+		im_free(&im);
+		rrd_set_error("unknown cf '%s'",symname);
+		return -1;
+	    }
+	    break;
+	}
+	
+    }
+    
+    
+    if (im.gdes_c==0){
+	rrd_set_error("can't make a graph without contents");
+	im_free(&im);
+	return(-1); 
+    }
+      
+
+    /* parse rest of arguments containing information on what to draw*/
+    
+    if (graph_paint(&im,prdata)==-1){
+	im_free(&im);
+	return -1;
+    }
+    *xsize=im.xgif;
+    *ysize=im.ygif;
+    im_free(&im);
+    return 0;
+}
+
+
+

Added: trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_last.c
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_last.c	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_last.c	Sat Jul 13 18:46:03 2002
@@ -0,0 +1,34 @@
+/*****************************************************************************
+ * RRDTOOL 0.99.29 Copyright Tobias Oetiker, 1997, 1998, 1999
+ *****************************************************************************
+ * rrd_last.c
+ *****************************************************************************
+ * Initial version by Russ Wright, @Home Network, 9/28/98
+ *****************************************************************************/
+
+#include "rrd_tool.h"
+
+time_t
+rrd_last(int argc, char **argv)
+{
+    FILE	*in_file;
+    time_t       lastup;
+
+    rrd_t	 rrd;
+
+    if(argc < 2){
+        rrd_set_error("please specify an rrd");
+        return(-1);
+    }
+    if(rrd_open(argv[1], &in_file, &rrd, RRD_READONLY)==-1){
+        return(-1);
+    }
+    lastup = rrd.live_head->last_up;
+    rrd_free(&rrd);
+    fclose(in_file);
+    return(lastup);
+}
+ 
+
+
+

Added: trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_create.c
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_create.c	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_create.c	Sat Jul 13 18:46:03 2002
@@ -0,0 +1,332 @@
+/*****************************************************************************
+ * RRDTOOL 0.99.29 Copyright Tobias Oetiker, 1997, 1998, 1999
+ *****************************************************************************
+ * rrd_create.c  creates new rrds
+ *****************************************************************************/
+
+#include "rrd_tool.h"
+
+
+int
+rrd_create(int argc, char **argv) 
+{
+    rrd_t          rrd;
+    long                i,long_tmp;
+    time_t             last_up;
+#ifdef WANT_AT_STYLE_TIMESPEC
+    struct time_value last_up_tv;
+    char *parsetime_error = NULL;
+    int last_up_is_ok = 0;
+#endif
+
+    /* init rrd clean */
+    rrd_init(&rrd);
+    /* static header */
+    if((rrd.stat_head = calloc(1,sizeof(stat_head_t)))==NULL){
+	rrd_set_error("allocating rrd.stat_head");
+	return(-1);
+    }
+
+    /* live header */
+    if((rrd.live_head = calloc(1,sizeof(live_head_t)))==NULL){
+	rrd_set_error("allocating rrd.live_head");
+	return(-1);
+    }
+
+    /* set some defaults */
+    strcpy(rrd.stat_head->cookie,RRD_COOKIE);
+    strcpy(rrd.stat_head->version,RRD_VERSION);
+    rrd.stat_head->float_cookie = FLOAT_COOKIE;
+    rrd.stat_head->ds_cnt = 0; /* this will be adjusted later */
+    rrd.stat_head->rra_cnt = 0; /* ditto */
+    rrd.stat_head->pdp_step = 300; /* 5 minute default */
+
+    /* a default value */
+    rrd.ds_def = NULL;
+    rrd.rra_def = NULL;
+    last_up = time(NULL);
+    while (1){
+	static struct option long_options[] =
+	{
+	    {"start",      required_argument, 0, 'b'},
+	    {"step",        required_argument,0,'s'},
+	    {0,0,0,0}
+	};
+	int option_index = 0;
+	int opt;
+	opt = getopt_long(argc, argv, "b:s:", 
+			  long_options, &option_index);
+	
+	if (opt == EOF)
+	  break;
+	
+	switch(opt) {
+	case 'b':
+#ifdef WANT_AT_STYLE_TIMESPEC
+            {
+            char *endp;
+            last_up_is_ok = 0;
+            last_up = strtol(optarg, &endp, 0);
+            if (*endp == '\0') /* it was a valid number */
+                if (last_up > 31122038 || /* 31 Dec 2038 in DDMMYYYY */
+                    last_up < 0) {
+                    last_up_is_ok = 1;
+                    break;
+                }
+            if ((parsetime_error = parsetime(optarg, &last_up_tv))) {
+                rrd_set_error("last update time: %s", parsetime_error );
+		rrd_free(&rrd);
+                return(-1);
+	    }
+	    if (last_up_tv.type == RELATIVE_TO_END_TIME ||
+		last_up_tv.type == RELATIVE_TO_START_TIME) {
+		rrd_set_error("specifying time relative to the 'start' "
+                              "or 'end' makes no sense here");
+		rrd_free(&rrd);
+		return(-1);
+	    }
+	    if (!last_up_is_ok)
+		last_up = mktime(&last_up_tv.tm) + last_up_tv.offset;
+            }/* this is for the entire block */
+	
+#else
+	    last_up = atol(optarg);
+#endif
+	    if (last_up < 0) /* if time is negative this means go back from now. */
+	      last_up = time(NULL)+last_up;
+	    if (last_up < 3600*24*365*10){
+		rrd_set_error("the first entry to the RRD should be after 1980");
+		rrd_free(&rrd);
+		return(-1);
+	    }	
+	    break;
+
+	case 's':
+	    long_tmp = atol(optarg);
+	    if (long_tmp < 1){
+		rrd_set_error("step size should be no less than one second");
+		rrd_free(&rrd);
+		return(-1);
+	    }
+	    rrd.stat_head->pdp_step = long_tmp;
+	    break;
+
+	case '?':
+	    rrd_set_error("unknown option '%s'",argv[optind-1]);
+            rrd_free(&rrd);
+	    return(-1);
+	}
+    }
+    rrd.live_head->last_up = last_up;
+
+    for(i=optind+1;i<argc;i++){
+	char minstr[20], maxstr[20];	
+	if (strncmp(argv[i],"DS:",3)==0){
+	    size_t old_size = sizeof(ds_def_t)*(rrd.stat_head->ds_cnt);
+	    if((rrd.ds_def = realloc(rrd.ds_def,
+				     old_size+sizeof(ds_def_t)))==NULL){
+		rrd_set_error("allocating rrd.ds_def");
+		rrd_free(&rrd);
+		return(-1);	
+	    }
+	    memset(&rrd.ds_def[rrd.stat_head->ds_cnt], 0, sizeof(ds_def_t));
+	    if (sscanf(&argv[i][3],
+		       DS_NAM_FMT ":" DST_FMT ":%lu:%18[^:]:%18[^:]",
+		       rrd.ds_def[rrd.stat_head->ds_cnt].ds_nam,
+		       rrd.ds_def[rrd.stat_head->ds_cnt].dst,
+		       &rrd.ds_def[rrd.stat_head->ds_cnt].par[DS_mrhb_cnt].u_cnt,
+		       minstr,maxstr) == 5){
+		if(dst_conv(rrd.ds_def[rrd.stat_head->ds_cnt].dst) == -1){
+		    rrd_free(&rrd);
+		    return (-1);
+		}
+		if (minstr[0] == 'U' && minstr[1] == 0)
+		    rrd.ds_def[rrd.stat_head->ds_cnt].par[DS_min_val].u_val = DNAN;
+		else
+		    rrd.ds_def[rrd.stat_head->ds_cnt].par[DS_min_val].u_val = atof(minstr);
+		
+		if (maxstr[0] == 'U' && maxstr[1] == 0)
+		    rrd.ds_def[rrd.stat_head->ds_cnt].par[DS_max_val].u_val = DNAN;
+		else
+		    rrd.ds_def[rrd.stat_head->ds_cnt].par[DS_max_val].u_val  = atof(maxstr);
+		
+		if (! isnan(rrd.ds_def[rrd.stat_head->ds_cnt].par[DS_min_val].u_val) &&
+		    ! isnan(rrd.ds_def[rrd.stat_head->ds_cnt].par[DS_max_val].u_val) &&
+		    rrd.ds_def[rrd.stat_head->ds_cnt].par[DS_min_val].u_val
+		    >= rrd.ds_def[rrd.stat_head->ds_cnt].par[DS_max_val].u_val ) {
+		    rrd_set_error("min must be less than max in DS definition");
+		    rrd_free(&rrd);
+		    return (-1);		
+		}
+		rrd.stat_head->ds_cnt++;	    
+	    } else {
+		rrd_set_error("can't parse argument '%s'",argv[i]);
+		rrd_free(&rrd);
+		return (-1);		
+	    }
+	} else if (strncmp(argv[i],"RRA:",3)==0){
+	    size_t old_size = sizeof(rra_def_t)*(rrd.stat_head->rra_cnt);
+	    if((rrd.rra_def = realloc(rrd.rra_def,
+				      old_size+sizeof(rra_def_t)))==NULL){
+		rrd_set_error("allocating rrd.rra_def");
+		rrd_free(&rrd);
+		return(-1);	
+	    }
+	    memset(&rrd.rra_def[rrd.stat_head->rra_cnt], 0, sizeof(rra_def_t));
+	    if (sscanf(&argv[i][4],
+		       CF_NAM_FMT ":%lf:%lu:%lu",
+		       rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam,
+		       &rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_cdp_xff_val].u_val,
+		       &rrd.rra_def[rrd.stat_head->rra_cnt].pdp_cnt,
+		       &rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt) == 4){
+		if(cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam) == -1){
+		    rrd_free(&rrd);
+		    return (-1);
+		}
+	        if (rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_cdp_xff_val].u_val<0.0 ||
+		    rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_cdp_xff_val].u_val>=1.0) {
+		    rrd_set_error("the xff must always be >= 0 and < 1");
+		    rrd_free(&rrd);
+		    return (-1);
+		}
+		rrd.stat_head->rra_cnt++;	    		
+	    }
+	    else {  
+		rrd_set_error("can't parse argument '%s'",argv[i]);
+		rrd_free(&rrd);
+		return (-1);		
+	    }
+
+	} else {
+	    rrd_set_error("can't parse argument '%s'",argv[i]);
+	    rrd_free(&rrd);
+            return -1;
+	}
+    }
+
+
+    if (rrd.stat_head->rra_cnt < 1){
+	rrd_set_error("you must define at least one Round Robin Archive");
+	rrd_free(&rrd);
+	return(-1);
+    }
+
+    if (rrd.stat_head->ds_cnt < 1){
+	rrd_set_error("you must define at least one Data Source");
+	rrd_free(&rrd);
+	return(-1);
+    }
+    return rrd_create_fn(argv[optind],&rrd);
+}
+
+/* create and empty rrd file according to the specs given */
+
+int
+rrd_create_fn(char *file_name, rrd_t *rrd)
+{
+    unsigned long    i,ii;
+    FILE             *rrd_file;
+    rrd_value_t       unknown = DNAN ;
+
+    if ((rrd_file = fopen(file_name,"wb")) == NULL ) {
+	rrd_set_error("can't create '%s'",file_name);
+	free(rrd->stat_head);
+	free(rrd->ds_def);
+	free(rrd->rra_def);
+	return(-1);
+    }
+    
+    fwrite(rrd->stat_head,
+	   sizeof(stat_head_t), 1, rrd_file);
+
+    fwrite(rrd->ds_def,
+	   sizeof(ds_def_t), rrd->stat_head->ds_cnt, rrd_file);
+
+    fwrite(rrd->rra_def,
+	   sizeof(rra_def_t), rrd->stat_head->rra_cnt, rrd_file);
+    
+    fwrite(rrd->live_head,
+	   sizeof(live_head_t),1, rrd_file);
+
+    if((rrd->pdp_prep = calloc(1,sizeof(pdp_prep_t))) == NULL){
+	rrd_set_error("allocating pdp_prep");
+	rrd_free(rrd);
+	fclose(rrd_file);
+	return(-1);
+    }
+
+    strcpy(rrd->pdp_prep->last_ds,"UNKN");
+
+    rrd->pdp_prep->scratch[PDP_val].u_val = 0.0;
+    rrd->pdp_prep->scratch[PDP_unkn_sec_cnt].u_cnt = 
+	rrd->live_head->last_up % rrd->stat_head->pdp_step;
+
+    for(i=0; i < rrd->stat_head->ds_cnt; i++)
+	fwrite( rrd->pdp_prep,sizeof(pdp_prep_t),1,rrd_file);
+    
+    if((rrd->cdp_prep = calloc(1,sizeof(cdp_prep_t))) == NULL){
+	rrd_set_error("allocating cdp_prep");
+	rrd_free(rrd);
+	fclose(rrd_file);
+	return(-1);
+    }
+
+    /* can not be zero because we don't know nothing ... */
+    rrd->cdp_prep->scratch[CDP_val].u_val = DNAN;
+    for(i=0; i < rrd->stat_head->rra_cnt; i++) {
+
+	/* startup missing pdp count */
+	rrd->cdp_prep->scratch[CDP_unkn_pdp_cnt].u_cnt = 
+	    ((rrd->live_head->last_up -
+	     rrd->pdp_prep->scratch[PDP_unkn_sec_cnt].u_cnt)
+	    % (rrd->stat_head->pdp_step 
+	       * rrd->rra_def[i].pdp_cnt)) / rrd->stat_head->pdp_step;	
+
+
+	for(ii=0; ii < rrd->stat_head->ds_cnt; ii++) {
+	    fwrite( rrd->cdp_prep,sizeof(cdp_prep_t),1,rrd_file);
+	}
+    }
+
+    /* now, we must make sure that the rest of the rrd
+       struct is properly initialized */
+
+    if((rrd->rra_ptr = calloc(1,sizeof(rra_ptr_t))) == NULL) {
+	rrd_set_error("allocating rra_ptr");
+	rrd_free(rrd);
+	fclose(rrd_file);
+	return(-1);
+    }
+
+    rrd->rra_ptr->cur_row = 0;
+    for(i=0; i <rrd->stat_head->rra_cnt; i++)
+	fwrite( rrd->rra_ptr,
+		sizeof(rra_ptr_t), 1,rrd_file);
+
+
+
+    /* write the empty data area */
+    for(i=0; 
+	i <  rrd->stat_head->rra_cnt;
+	i++)
+	{
+	    for(ii=0; 
+		ii <  rrd->rra_def[i].row_cnt 
+		    * rrd->stat_head->ds_cnt;
+		ii++){
+		fwrite(&unknown,sizeof(rrd_value_t),1,rrd_file);
+	    }
+	}
+
+    /* lets see if we had an error */
+    if(ferror(rrd_file)){
+	rrd_set_error("a file error occurred while creating '%s'",file_name);
+	fclose(rrd_file);	
+	rrd_free(rrd);
+	return(-1);
+    }
+
+    fclose(rrd_file);    
+    rrd_free(rrd);
+    return (0);
+}

Added: trunk/orca/packages/rrdtool-0.99.29.1/src/ntconfig.h
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/src/ntconfig.h	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/src/ntconfig.h	Sat Jul 13 18:46:03 2002
@@ -0,0 +1,10 @@
+/* config.h.nt: what configure _would_ say, if it ran on NT */
+
+#define STDC_HEADERS 1
+
+/* Define if you have the strftime function.  */
+#define HAVE_STRFTIME 1
+
+/* Define if you have the <math.h> header file.  */
+#define HAVE_MATH_H 1
+

Added: trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_dump.c
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_dump.c	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_dump.c	Sat Jul 13 18:46:03 2002
@@ -0,0 +1,154 @@
+/*****************************************************************************
+ * RRDTOOL 0.99.29 Copyright Tobias Oetiker, 1997, 1998, 1999
+ *****************************************************************************
+ * rrd_dump  Display a RRD
+ *****************************************************************************
+ * $Id: rrd_dump.c,v 1.5 1998/03/08 12:35:11 oetiker Exp oetiker $
+ * $Log: rrd_dump.c,v $
+ *****************************************************************************/
+
+#include "rrd_tool.h"
+
+int
+rrd_dump(int argc, char **argv)    
+{   
+    int          i,ii,iii,full=0;
+    time_t       now;
+    char         somestring[255];
+    rrd_value_t  my_cdp;
+
+    FILE                  *in_file;
+    rrd_t             rrd;
+
+
+    while (1){
+	static struct option long_options[] =
+	{
+	    {"full",      no_argument, 0, 'f'},
+	    {0,0,0,0}
+	};
+	int option_index = 0;
+	int opt;
+	opt = getopt_long(argc, argv, "f", 
+			  long_options, &option_index);
+	if (opt == EOF)
+	    break;
+
+	switch(opt) {
+	case 'f':
+	    full=1;
+	    break;
+	case '?':
+	    rrd_set_error("unknown option '%s'",argv[optind-1]);
+	    return(-1);   	    
+	}
+    }
+    
+    if(optind >= argc){
+	rrd_set_error("please specify an rrd");
+	return(-1);   
+    }
+    if(rrd_open(argv[optind],&in_file,&rrd, RRD_READONLY)==-1){
+	return(-1);
+    }
+    puts("RRD Header");
+    puts("---------------------------");
+    puts("");
+    puts("* stat_head");
+    printf("\tcookie:       '%s'\n",rrd.stat_head->cookie);
+    printf("\tversion:      '%s'\n",rrd.stat_head->version);
+    printf("\tfloat_cookie: %e\n",rrd.stat_head->float_cookie);
+	
+    printf("\tds_cnt:       %lu\n",rrd.stat_head->ds_cnt);
+    printf("\trra_cnt:      %lu\n",rrd.stat_head->rra_cnt);
+    printf("\tpdp_step:     %lu seconds\n",rrd.stat_head->pdp_step);
+
+    for(i=0;i<rrd.stat_head->ds_cnt;i++){
+	printf("\n* ds_def[%i]\n",i);
+	printf("\tds-nam:       %s\n",rrd.ds_def[i].ds_nam);
+	printf("\tdst:          %s\n",rrd.ds_def[i].dst);
+	printf("\tds_mrhb:      %lu\n",rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt);
+	printf("\tmax_val:      %e\n",rrd.ds_def[i].par[DS_max_val].u_val);
+	printf("\tmin_val:      %e\n",rrd.ds_def[i].par[DS_min_val].u_val);
+    }
+
+    for(i=0;i<rrd.stat_head->rra_cnt;i++){
+	printf("\n* rra_def[%i]\n",i);
+	printf("\tcf_name:      %s\n",rrd.rra_def[i].cf_nam);
+	printf("\trow_cnt:      %lu\n",rrd.rra_def[i].row_cnt);
+	printf("\tpdp_cnt:      %lu\n",rrd.rra_def[i].pdp_cnt);
+    }
+ 
+    printf("\n* live_head\n");
+#if HAVE_STRFTIME
+    strftime(somestring,200,"%Y-%m-%d %H:%M:%S",
+	     localtime(&rrd.live_head->last_up));
+#else
+# error "Need strftime"
+#endif
+    printf("\tlast_up:       '%lu' %s\n",
+	   rrd.live_head->last_up,somestring);
+
+    printf("\n* pdp_prep\n");
+    for(i=0;i<rrd.stat_head->ds_cnt;i++){
+	printf("\n  (ds='%s')\n",rrd.ds_def[i].ds_nam);
+
+	
+	printf("\tlast_ds:      '%s'\n",rrd.pdp_prep[i].last_ds);
+	printf("\tvalue:         %e\n",rrd.pdp_prep[i].scratch[PDP_val].u_val);
+	printf("\tunkn_sec:      %lu seconds\n",
+	       rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt);
+    }
+ 
+    printf("\n* cdp_prep");
+    for(i=0;i<rrd.stat_head->rra_cnt;i++){
+	printf("\n  (rra=%i)\n",i);
+	for(ii=0;ii<rrd.stat_head->ds_cnt;ii++){
+	    printf("\n    (ds=%s)\n",rrd.ds_def[ii].ds_nam);
+	    printf("\tvalue:          %e\n",
+		   rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_val].u_val);
+	    printf("\tunkn_pdp:       %lu pdp\n",
+		   rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_unkn_pdp_cnt].u_cnt);
+	}
+    } 
+
+    for(i=0;i<rrd.stat_head->rra_cnt;i++){
+	printf("\n* rra_ptr[%i]\n",i);
+	printf("\tcur_row:        %lu\n",rrd.rra_ptr[i].cur_row);
+    }
+
+    if (full) {
+	puts("");   
+	puts("RRD Contents");
+	puts("-----------------------");
+	puts("");      
+	for(i=0;i<rrd.stat_head->rra_cnt;i++){
+	    printf("[%3i]:\n",i);
+	    now = (rrd.live_head->last_up 
+		   - rrd.live_head->last_up % (rrd.rra_def[i].pdp_cnt*rrd.stat_head->pdp_step)
+		   - rrd.rra_ptr[i].cur_row * rrd.rra_def[i].pdp_cnt*rrd.stat_head->pdp_step);
+	    for(ii=0;ii<rrd.rra_def[i].row_cnt;ii++){
+		if (rrd.rra_ptr[i].cur_row==ii) {
+		    printf("-> ");
+		} else {
+		    printf("   ");
+		}
+		printf("%10lu",now);
+		now += rrd.rra_def[i].pdp_cnt*rrd.stat_head->pdp_step;
+		if (rrd.rra_ptr[i].cur_row==ii) 
+		    now -= rrd.rra_def[i].pdp_cnt*rrd.stat_head->pdp_step*rrd.rra_def[i].row_cnt;
+		
+		for(iii=0;iii<rrd.stat_head->ds_cnt;iii++){			 
+		    fread(&my_cdp,sizeof(rrd_value_t),1,in_file);
+		    
+		    printf(" %12.3f",my_cdp);
+		}
+		printf("\n");
+	    }
+	}
+    }
+    rrd_free(&rrd);
+    fclose(in_file);
+    return(0);
+}
+

Added: trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_diff.c
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_diff.c	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_diff.c	Sat Jul 13 18:46:03 2002
@@ -0,0 +1,89 @@
+/*****************************************************************************
+ * RRDTOOL 0.99.29 Copyright Tobias Oetiker, 1999
+ * This code is stolen from rateup (mrtg-2.x) by Dave Rand
+ *****************************************************************************
+ * diff calculate the difference between two very long integers available as
+ *      strings
+ *****************************************************************************
+ * $Id: diff.c,v 1.1 1998/10/08 18:21:45 oetiker Exp oetiker $
+ * $Log: diff.c,v $
+ * Revision 1.1  1998/10/08 18:21:45  oetiker
+ * Initial revision
+ *
+ * Revision 1.3  1998/02/06 21:10:52  oetiker
+ * removed max define .. it is now in rrd_tool.h
+ *
+ * Revision 1.2  1997/12/07 20:38:03  oetiker
+ * ansified
+ *
+ * Revision 1.1  1997/11/28 23:31:59  oetiker
+ * Initial revision
+ *
+ *****************************************************************************/
+
+#include "rrd_tool.h"
+
+double
+rrd_diff(char *a, char *b)
+{
+    char res[LAST_DS_LEN+1], *a1, *b1, *r1, *fix;
+    int c,x,m;
+    
+    while (!isdigit((int)*a) || *a==0)
+        a++;
+    fix=a;
+    while (isdigit((int)*fix)) 
+	fix++;
+    *fix = 0; /* maybe there is some non digit data in the string */ 
+    while (!isdigit((int)*b) || *b==0)
+        b++;
+    fix=b;
+    while (isdigit((int)*fix)) 
+	fix++;
+    *fix = 0; /* maybe there is some non digit data in the string */ 
+    if(!isdigit((int)*a) || !isdigit((int)*b))
+	return DNAN;
+    a1 = &a[strlen(a)-1];
+    m = max(strlen(a),strlen(b));
+    if (m > LAST_DS_LEN) return DNAN; /* result string too short */
+
+    r1 = &res[m+1];
+    for (b1 = res;b1 <= r1; b1++) *b1 = ' ';
+    b1 = &b[strlen(b)-1];
+    r1[1] = 0;  /* Null terminate result */
+    c = 0;
+    for (x=0; x<m; x++) {
+        if (a1 >= a && b1 >= b) {
+            *r1 = ((*a1 - c) - *b1) + '0';
+        } else if (a1 >= a) {
+            *r1 = (*a1 - c);
+        } else {
+            *r1 = ('0' - *b1 - c) + '0';
+        }
+        if (*r1 < '0') {
+            *r1 += 10;
+            c=1;
+        } else
+	  if (*r1 > '9') { /* 0 - 10 */
+	    *r1 -= 10;
+	    c=1;	    
+	  } else {
+            c=0;
+        }
+        a1--;b1--;r1--;
+    }
+    if (c) {
+        r1 = &res[m+1];
+        for (x=0; isdigit((int)*r1) && x<m; x++,r1--)  {
+            *r1 = ('9' - *r1 + c) + '0';
+            if (*r1 > '9') {
+                *r1 -= 10;
+                c=1;
+            } else {
+                c=0;
+            }
+        }
+        return(-atof(res));
+    } else
+        return(atof(res));
+}                                                       

Added: trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_tune.c
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_tune.c	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_tune.c	Sat Jul 13 18:46:03 2002
@@ -0,0 +1,159 @@
+/*****************************************************************************
+ * RRDTOOL 0.99.29 Copyright Tobias Oetiker, 1997, 1998, 1999
+ *****************************************************************************
+ * change header parameters of an rrd
+ *****************************************************************************
+ * $Id: rrd_dump.c,v 1.5 1998/03/08 12:35:11 oetiker Exp oetiker $
+ * $Log: rrd_dump.c,v $
+ *****************************************************************************/
+
+#include "rrd_tool.h"
+
+int
+rrd_tune(int argc, char **argv)    
+{   
+    rrd_t               rrd;
+    FILE               *rrd_file;
+    int                 matches;
+    int                 optcnt = 0;
+    long                ds;
+    char                ds_nam[DS_NAM_SIZE];
+    char                ds_new[DS_NAM_SIZE];
+    long                heartbeat;
+    double              min;
+    double              max;
+    char                dst[DST_SIZE];
+
+
+    if(rrd_open(argv[1],&rrd_file,&rrd, RRD_READWRITE)==-1){
+        return -1;
+    }
+
+    
+    while (1){
+	static struct option long_options[] =
+	{
+	    {"heartbeat",        required_argument, 0, 'h'},
+	    {"minimum",          required_argument, 0, 'i'},
+	    {"maximum",          required_argument, 0, 'a'},
+	    {"data-source-type", required_argument, 0, 'd'},
+	    {"data-source-rename", required_argument, 0, 'r'},
+	    {0,0,0,0}
+	};
+	int option_index = 0;
+	int opt;
+	opt = getopt_long(argc, argv, "h:i:a:d:r:", 
+			  long_options, &option_index);
+	if (opt == EOF)
+	    break;
+	
+	optcnt++;
+	switch(opt) {	    
+	case 'h':
+	    if ((matches = sscanf(optarg, DS_NAM_FMT ":%ld",ds_nam,&heartbeat)) != 2){
+		rrd_set_error("invalid arguments for heartbeat");
+		rrd_free(&rrd);
+		return -1;
+	    }
+	    if ((ds=ds_match(&rrd,ds_nam))==-1){
+		rrd_free(&rrd);
+		return -1;
+	    }
+	    rrd.ds_def[ds].par[DS_mrhb_cnt].u_cnt = heartbeat;
+	    break;
+
+	case 'i':
+	    if ((matches = sscanf(optarg,DS_NAM_FMT ":%lf",ds_nam,&min)) <1){
+		rrd_set_error("invalid arguments for minimum ds value");
+		rrd_free(&rrd);
+		return -1;
+	    }
+	    if ((ds=ds_match(&rrd,ds_nam))==-1){
+		rrd_free(&rrd);
+		return -1;
+	    }
+
+	    if(matches == 1)
+		min= DNAN;
+	    rrd.ds_def[ds].par[DS_min_val].u_val = min;
+	    break;
+
+	case 'a':
+	    if ((matches = sscanf(optarg, DS_NAM_FMT ":%lf",ds_nam,&max)) <1){
+		rrd_set_error("invalid arguments for maximum ds value");
+		rrd_free(&rrd);
+		return -1;
+	    }
+	    if ((ds=ds_match(&rrd,ds_nam))==-1){
+		rrd_free(&rrd);
+		return -1;
+	    }
+	    if(matches == 1) 
+		max= DNAN; 
+	    rrd.ds_def[ds].par[DS_max_val].u_val = max;
+	    break;
+
+	case 'd':
+	    if ((matches = sscanf(optarg, DS_NAM_FMT ":" DST_FMT ,ds_nam,dst)) != 2){
+		rrd_set_error("invalid arguments for data source type");
+		rrd_free(&rrd);
+		return -1;
+	    }
+	    if ((ds=ds_match(&rrd,ds_nam))==-1){
+		rrd_free(&rrd);
+		return -1;
+	    }
+	    if (dst_conv(dst) == -1){
+		rrd_free(&rrd);
+		return -1;
+	    }
+	    strncpy(rrd.ds_def[ds].dst,dst,DST_SIZE);
+
+	    rrd.pdp_prep[ds].last_ds[0] = 'U';
+	    rrd.pdp_prep[ds].last_ds[1] = 'N';
+	    rrd.pdp_prep[ds].last_ds[2] = 'K';
+	    rrd.pdp_prep[ds].last_ds[3] = 'N';
+	    rrd.pdp_prep[ds].last_ds[4] = '\0';
+	    
+	    break;
+	case 'r':
+	    if ((matches = 
+		 sscanf(optarg,DS_NAM_FMT ":" DS_NAM_FMT , ds_nam,ds_new)) != 2){
+		rrd_set_error("invalid arguments for data source type");
+		rrd_free(&rrd);
+		return -1;
+	    }
+	    if ((ds=ds_match(&rrd,ds_nam))==-1){
+		rrd_free(&rrd);
+		return -1;
+	    }
+	    strncpy(rrd.ds_def[ds].ds_nam,ds_new,DS_NAM_SIZE);
+	    break;
+	case '?':
+            rrd_set_error("unknown option '%s'",argv[optind-1]);
+	    rrd_free(&rrd);	    
+            return -1;
+        }
+    }
+    if(optcnt>0){
+	
+	fseek(rrd_file,0,SEEK_SET);
+	fwrite(rrd.stat_head,
+	       sizeof(stat_head_t),1, rrd_file);
+	fwrite(rrd.ds_def,
+	       sizeof(ds_def_t), rrd.stat_head->ds_cnt, rrd_file);
+    } else {
+	int i;
+	for(i=0;i< rrd.stat_head->ds_cnt;i++)
+	    printf("DS[%s] typ: %s\thbt: %ld\tmin: %1.4f\tmax: %1.4f\n",
+		   rrd.ds_def[i].ds_nam,
+		   rrd.ds_def[i].dst,
+		   rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt,
+		   rrd.ds_def[i].par[DS_min_val].u_val,
+		   rrd.ds_def[i].par[DS_max_val].u_val);
+    }
+    fclose(rrd_file);
+    rrd_free(&rrd);
+    return 0;
+}
+

Added: trunk/orca/packages/rrdtool-0.99.29.1/src/getopt1.c
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/src/getopt1.c	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/src/getopt1.c	Sat Jul 13 18:46:03 2002
@@ -0,0 +1,189 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+   Copyright (C) 1987,88,89,90,91,92,93,94,96,97 Free Software Foundation, Inc.
+
+   This file is part of the GNU C Library.  Its master source is NOT part of
+   the C library, however.  The master source lives in /gd/gnu/lib.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "getopt.h"
+
+#if !defined (__STDC__) || !__STDC__
+/* This is a separate conditional since some stdc systems
+   reject `defined (const)'.  */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2
+#include <gnu-versions.h>
+#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#define ELIDE_CODE
+#endif
+#endif
+
+#ifndef ELIDE_CODE
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#endif
+
+#ifndef	NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+   If an option that starts with '-' (not '--') doesn't match a long option,
+   but does match a short option, it is parsed as a short option
+   instead.  */
+
+int
+getopt_long_only (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif	/* Not ELIDE_CODE.  */
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+      int option_index = 0;
+      static struct option long_options[] =
+      {
+	{"add", 1, 0, 0},
+	{"append", 0, 0, 0},
+	{"delete", 1, 0, 0},
+	{"verbose", 0, 0, 0},
+	{"create", 0, 0, 0},
+	{"file", 1, 0, 0},
+	{0, 0, 0, 0}
+      };
+
+      c = getopt_long (argc, argv, "abc:d:0123456789",
+		       long_options, &option_index);
+      if (c == -1)
+	break;
+
+      switch (c)
+	{
+	case 0:
+	  printf ("option %s", long_options[option_index].name);
+	  if (optarg)
+	    printf (" with arg %s", optarg);
+	  printf ("\n");
+	  break;
+
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+	  if (digit_optind != 0 && digit_optind != this_option_optind)
+	    printf ("digits occur in two different argv-elements.\n");
+	  digit_optind = this_option_optind;
+	  printf ("option %c\n", c);
+	  break;
+
+	case 'a':
+	  printf ("option a\n");
+	  break;
+
+	case 'b':
+	  printf ("option b\n");
+	  break;
+
+	case 'c':
+	  printf ("option c with value `%s'\n", optarg);
+	  break;
+
+	case 'd':
+	  printf ("option d with value `%s'\n", optarg);
+	  break;
+
+	case '?':
+	  break;
+
+	default:
+	  printf ("?? getopt returned character code 0%o ??\n", c);
+	}
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+	printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */

Added: trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_tool.c
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_tool.c	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_tool.c	Sat Jul 13 18:46:04 2002
@@ -0,0 +1,308 @@
+/*****************************************************************************
+ * RRDTOOL 0.99.29 Copyright Tobias Oetiker, 1997, 1998, 1999
+ *****************************************************************************
+ * rrd_tool.c  Startup wrapper
+ *****************************************************************************
+ * $Id: rrd_tool.c,v 1.8 1998/03/08 12:35:11 oetiker Exp oetiker $
+ * $Log: rrd_tool.c,v $
+ *****************************************************************************/
+
+#include "rrd_tool.h"
+
+void PrintUsage(void);
+int CountArgs(char *aLine);
+int CreateArgs(char *, char *, int, char **);
+int HandleInputLine(int, char **, FILE*);
+#define TRUE		1
+#define FALSE		0
+#define MAX_LENGTH	10000
+
+
+void PrintUsage(void)
+{
+    printf("\n"
+	   "RRD TOOL 0.99.28  Copyright (C) 1999 by Tobias Oetiker <tobi at oetiker.ch>\n\n"
+	   "Usage: rrdtool [options] command command_options\n\n"
+	   "Valid commands and command_options are listed below.\n\n"
+
+	   "* create - create a new RRD\n\n"
+	   "\trrdtool create filename [--start|-b start time]\n"
+	   "\t\t[--step|-s step]\n"
+	   "\t\t[DS:ds-name:DST:heartbeat:min:max] [RRA:CF:xff:steps:rows]\n\n"
+
+	   "* dump - dump an RRD\n\n"
+	   "\trrdtool dump filename.rrd [--full|-f]\n\n"
+
+           "* last - show last update time for RRD\n\n"
+           "\trrdtool last filename.rrd\n\n"
+
+	   "* update - update an RRD\n\n"
+	   "\trrdtool update filename\n"
+	   "\t\ttime|N:value[:value...]\n\n"
+	   "\t\t[ time:value[:value...] ..]\n\n"
+
+	   "* fetch - fetch data out of an RRD\n\n"
+	   "\trrdtool fetch filename.rrd CF\n"
+	   "\t\t[--resolution|-r resolution]\n"
+	   "\t\t[--start|-s start] [--end|-e end]\n\n"
+	   	   
+	   "* graph - generate a graph from one or several RRD\n\n"
+	   "\trrdtool graph filename [-s|--start seconds] [-e|--end seconds]\n"
+	   "\t\t[-x|--x-grid x-axis grid and label]\n"
+	   "\t\t[-y|--y-grid y-axis grid and label]\n"
+	   "\t\t[-v|--vertical-label string] [-w|--width pixels]\n"
+	   "\t\t[-h|--height pixels] [-o|--logarithmic]\n"
+	   "\t\t[-u|--upper-limit value]\n"
+	   "\t\t[-l|--lower-limit value] [-r|--rigid]\n"
+	   "\t\t[-c|--color COLORTAG#rrggbb] [-t|--title string]\n"
+	   "\t\t[DEF:vname=rrd:ds-name:CF]\n"
+	   "\t\t[CDEF:vname=rpn-expression]\n"
+	   "\t\t[PRINT:vname:CF:format]\n"
+	   "\t\t[GPRINT:vname:CF:format]\n"
+	   "\t\t[HRULE:value#rrggbb[:legend]]\n"
+	   "\t\t[VRULE:value#rrggbb[:legend]]\n"
+	   "\t\t[LINE{1|2|3}:vname[#rrggbb[:legend]]]\n"
+	   "\t\t[AREA:vname[#rrggbb[:legend]]]\n"
+	   "\t\t[STACK:vname[#rrggbb[:legend]]]\n\n"
+
+	   
+	   " * tune -  Modify some basic properties of an RRD\n\n"
+	   "\trrdtool tune filename\n"
+	   "\t\t[--heartbeat|-h ds-name:heartbeat]\n"
+	   "\t\t[--data-source-type|-d ds-name:DST\n"
+	   "\t\t[--data-source-rename|-r old-name:new-name\n"
+	   "\t\t[--minimum|-i ds-name:min] [--maximum|-a ds-name:max]\n\n"
+
+	   "RRD TOOL is distributed under the Terms of the GNU General\n"
+	   "Public License Version 2. (www.gnu.org/copyleft/gpl.html)\n\n"
+
+	   "For more information read the RRD manpages\n\n");
+}
+
+
+int main(int argc, char *argv[])
+{
+    char **myargv;
+    char aLine[MAX_LENGTH];
+
+    if (argc == 1)
+	{
+	    PrintUsage();
+	    return 0;
+	}
+    
+    if ((argc == 2) && (*argv[1] == '-'))
+	{
+#if HAVE_GETRUSAGE
+	  struct rusage  myusage;
+	  struct timeval starttime;
+	  struct timeval currenttime;
+	  struct timezone tz;
+
+	    tz.tz_minuteswest =0;
+	    tz.tz_dsttime=0;
+	    gettimeofday(&starttime,&tz);
+#endif
+
+	    while (fgets(aLine, sizeof(aLine)-1, stdin)){
+		if ((argc = CountArgs(aLine)) == 0)  {
+		    fprintf(stderr,"ERROR: not enough arguments\n");		    
+		}
+		if ((myargv = (char **) malloc((argc+1) * 
+					       sizeof(char *))) == NULL)   {
+		    perror("malloc");
+		    return -1;
+		}
+		if ((argc=CreateArgs(argv[0], aLine, argc, myargv)) < 0) {
+		    fprintf(stderr, "ERROR: creating arguments\n");
+		    return -1;
+		}
+
+		if (HandleInputLine(argc, myargv, stdout))
+		    return -1;
+		free(myargv);
+
+#if HAVE_GETRUSAGE
+		getrusage(RUSAGE_SELF,&myusage);
+		gettimeofday(&currenttime,&tz);
+		printf("OK u:%1.2f s:%1.2f r:%1.2f\n",
+		       (double)myusage.ru_utime.tv_sec+
+		       (double)myusage.ru_utime.tv_usec/1000000.0,
+		       (double)myusage.ru_stime.tv_sec+
+		       (double)myusage.ru_stime.tv_usec/1000000.0,
+		       (double)(currenttime.tv_sec-starttime.tv_sec)
+		       +(double)(currenttime.tv_usec-starttime.tv_usec)
+		       /1000000.0);
+#else
+		printf("OK\n");
+#endif
+		fflush(stdout); /* this is important for pipes to work */
+	    }
+	}
+    else
+	HandleInputLine(argc, argv, stderr);    
+    return 0;
+}
+
+int HandleInputLine(int argc, char **argv, FILE* out)
+{
+    optind=0; /* reset gnu getopt */
+    opterr=0; /* no error messages */
+
+    if (argc < 3 
+	|| strcmp("help", argv[1]) == 0
+	|| strcmp("-h", argv[1]) == 0 ) {
+	PrintUsage();
+	return 0;
+    }
+    
+    if (strcmp("create", argv[1]) == 0)	
+	rrd_create(argc-1, &argv[1]);
+    else if (strcmp("dump", argv[1]) == 0)
+	rrd_dump(argc-1, &argv[1]);
+    else if (strcmp("last", argv[1]) == 0)
+        printf("%ld\n",rrd_last(argc-1, &argv[1]));
+    else if (strcmp("update", argv[1]) == 0)
+	rrd_update(argc-1, &argv[1]);
+    else if (strcmp("fetch", argv[1]) == 0) {
+	time_t        start,end;
+	unsigned long step, ds_cnt,i,ii;
+	rrd_value_t   *data,*datai;
+	char          **ds_namv;
+	if (rrd_fetch(argc-1, &argv[1],&start,&end,&step,&ds_cnt,&ds_namv,&data) != -1) {
+	    datai=data;
+	    printf("           ");
+	    for (i = 0; i<ds_cnt;i++)
+	        printf("%10s",ds_namv[i]);
+	    printf ("\n\n");
+	    for (i = start; i <= end; i += step){
+	        printf("%10lu:", i);
+	        for (ii = 0; ii < ds_cnt; ii++)
+		    printf("%10.2f", *(datai++));
+	        printf("\n");
+	    }
+	    for (i=0;i<ds_cnt;i++)
+	          free(ds_namv[i]);
+	    free(ds_namv);
+	    free (data);
+	}
+    }
+    else if (strcmp("graph", argv[1]) == 0) {
+	char **calcpr;
+	int xsize, ysize;
+	int i;
+	calcpr = NULL;
+	if( rrd_graph(argc-1, &argv[1], &calcpr, &xsize, &ysize) != -1 ) {
+	    if (strcmp(argv[2],"-") != 0) 
+		printf ("%dx%d\n",xsize,ysize);
+	    if (calcpr) {
+		for(i=0;calcpr[i];i++){
+		    if (strcmp(argv[2],"-") != 0) 
+			printf("%s\n",calcpr[i]);
+		    free(calcpr[i]);
+		} 
+		free(calcpr);
+	    }
+	}
+	
+    } else if (strcmp("tune", argv[1]) == 0) 
+		rrd_tune(argc-1, &argv[1]);
+    else {
+		rrd_set_error("unknown function '%s'",argv[1]);
+    }
+    if (rrd_test_error()) {
+	fprintf(out, "ERROR: %s\n",rrd_get_error());
+	rrd_clear_error();
+    }
+    return(0);
+}
+
+int CountArgs(char *aLine)
+{
+    int i=0;
+    int aCount = 0;
+    int inarg = 0;
+    while (aLine[i] == ' ') i++;
+    while (aLine[i] != 0){       
+	if((aLine[i]== ' ') && inarg){
+	    inarg = 0;
+	}
+	if((aLine[i]!= ' ') && ! inarg){
+	    inarg = 1;
+	    aCount++;
+	}
+	i++;
+    }
+    return aCount;
+}
+
+/*
+ * CreateArgs - take a string (aLine) and tokenize
+ */
+int CreateArgs(char *pName, char *aLine, int argc, char **argv)
+{
+    char	*getP, *putP;
+    char	**pargv = argv;
+    char        Quote = 0;
+    int inArg = 0;
+    int	len;
+
+    len = strlen(aLine);
+    /* remove trailing space and newlines */
+    while (len && aLine[len] <= ' ') {
+	aLine[len] = 0 ; len--;
+    }
+    /* sikp leading blanks */
+    while (*aLine && *aLine <= ' ') aLine++;
+
+    pargv[0] = pName;
+    argc = 1;
+    getP = aLine;
+    putP = aLine;
+    while (*getP){
+	switch (*getP) {
+	case ' ': 
+	    if (Quote){
+		*(putP++)=*getP;
+	    } else 
+		if(inArg) {
+		    *(putP++) = 0;
+		    inArg = 0;
+		}
+	    break;
+	case '"':
+	case '\'':
+	    if (Quote != 0) {
+		if (Quote == *getP) 
+		    Quote = 0;
+		else {
+		    *(putP++)=*getP;
+		}
+	    } else {
+		if(!inArg){
+		    pargv[argc++] = putP;
+		    inArg=1;
+		}	    
+		Quote = *getP;
+	    }
+	    break;
+	default:
+	    if(!inArg){
+		pargv[argc++] = putP;
+		inArg=1;
+	    }
+	    *(putP++)=*getP;
+	    break;
+	}
+	getP++;
+    }
+
+    *putP = '\0';
+
+    if (Quote) 
+	return -1;
+    else
+	return argc;
+}
+
+

Added: trunk/orca/packages/rrdtool-0.99.29.1/src/parsetime.c
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/src/parsetime.c	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/src/parsetime.c	Sat Jul 13 18:46:04 2002
@@ -0,0 +1,857 @@
+/* 
+ *  parsetime.c - parse time for at(1)
+ *  Copyright (C) 1993, 1994  Thomas Koenig
+ *
+ *  modifications for english-language times
+ *  Copyright (C) 1993  David Parsons
+ *
+ *  A lot of modifications and extensions 
+ *  (including the new syntax being useful for RRDB)
+ *  Copyright (C) 1999  Oleg Cherevko (aka Olwi Deer)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author(s) may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * The BNF-like specification of the time syntax parsed is below:
+ *                                                               
+ * As usual, [ X ] means that X is optional, { X } means that X may
+ * be either omitted or specified as many times as needed,
+ * alternatives are separated by |, brackets are used for grouping.
+ * (# marks the beginning of comment that extends to the end of line)
+ *
+ * TIME-SPECIFICATION ::= TIME-REFERENCE [ OFFSET-SPEC ] |
+ *			                   OFFSET-SPEC   |
+ *			   ( START | END ) OFFSET-SPEC 
+ *
+ * TIME-REFERENCE ::= NOW | TIME-OF-DAY-SPEC [ DAY-SPEC-1 ] |
+ *                        [ TIME-OF-DAY-SPEC ] DAY-SPEC-2
+ *
+ * TIME-OF-DAY-SPEC ::= NUMBER [(':'|'.') NUMBER] [am|pm] | # HH:MM HH.MM HH[MM]
+ *                     'noon' | 'midnight' | 'teatime'
+ *
+ * DAY-SPEC-1 ::= NUMBER '/' NUMBER '/' NUMBER |  # MM/DD/[YY]YY
+ *                NUMBER '.' NUMBER '.' NUMBER |  # DD.MM.[YY]YY
+ *                NUMBER                          # DDMM[YY]YY
+ *
+ * DAY-SPEC-2 ::= MONTH-NAME NUMBER [NUMBER] |    # Month DD [YY]YY
+ *                'yesterday' | 'today' | 'tomorrow' |
+ *                DAY-OF-WEEK
+ *
+ *
+ * OFFSET-SPEC ::= '+'|'-' NUMBER TIME-UNIT { ['+'|'-'] NUMBER TIME-UNIT }
+ *
+ * TIME-UNIT ::= SECONDS | MINUTES | HOURS |
+ *               DAYS | WEEKS | MONTHS | YEARS
+ *
+ * NOW ::= 'now' | 'n'
+ *
+ * START ::= 'start' | 's'
+ * END   ::= 'end' | 'e'
+ *
+ * SECONDS ::= 'seconds' | 'second' | 'sec' | 's'
+ * MINUTES ::= 'minutes' | 'minute' | 'min' | 'm'
+ * HOURS   ::= 'hours' | 'hour' | 'hr' | 'h'
+ * DAYS    ::= 'days' | 'day' | 'd'
+ * WEEKS   ::= 'weeks' | 'week' | 'wk' | 'w'
+ * MONTHS  ::= 'months' | 'month' | 'mon' | 'm'
+ * YEARS   ::= 'years' | 'year' | 'yr' | 'y'
+ *
+ * MONTH-NAME ::= 'jan' | 'january' | 'feb' | 'february' | 'mar' | 'march' |
+ *                'apr' | 'april' | 'may' | 'jun' | 'june' | 'jul' | 'july' |
+ *                'aug' | 'august' | 'sep' | 'september' | 'oct' | 'october' |
+ *		  'nov' | 'november' | 'dec' | 'december'
+ *
+ * DAY-OF-WEEK ::= 'sunday' | 'sun' | 'monday' | 'mon' | 'tuesday' | 'tue' |
+ *                 'wednesday' | 'wed' | 'thursday' | 'thu' | 'friday' | 'fri' |
+ *                 'saturday' | 'sat'
+ *
+ *
+ * As you may note, there is an ambiguity with respect to
+ * the 'm' time unit (which can mean either minutes or months).
+ * To cope with this, code tries to read users mind :) by applying
+ * certain heuristics. There are two of them:
+ *
+ * 1. If 'm' is used in context of (i.e. right after the) years,
+ *    months, weeks, or days it is assumed to mean months, while
+ *    in the context of hours, minutes, and seconds it means minutes.
+ *    (e.g., in -1y6m or +3w1m 'm' means 'months', while in
+ *    -3h20m or +5s2m 'm' means 'minutes')
+ *
+ * 2. Out of context (i.e. right after the '+' or '-' sign) the
+ *    meaning of 'm' is guessed from the number it directly follows.
+ *    Currently, if the number absolute value is below 25 it is assumed
+ *    that 'm' means months, otherwise it is treated as minutes.
+ *    (e.g., -25m == -25 minutes, while +24m == +24 months)
+ *
+ */
+
+/* System Headers */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+#include <stdarg.h>
+
+/* Local headers */
+
+#include "parsetime.h"
+
+/* Structures and unions */
+
+enum {	/* symbols */
+    MIDNIGHT, NOON, TEATIME,
+    PM, AM, YESTERDAY, TODAY, TOMORROW, NOW, START, END,
+    SECONDS, MINUTES, HOURS, DAYS, WEEKS, MONTHS, YEARS,
+    MONTHS_MINUTES,
+    NUMBER, PLUS, MINUS, DOT, COLON, SLASH, ID, JUNK,
+    JAN, FEB, MAR, APR, MAY, JUN,
+    JUL, AUG, SEP, OCT, NOV, DEC,
+    SUN, MON, TUE, WED, THU, FRI, SAT
+    };
+
+/* the below is for plus_minus() */
+#define PREVIOUS_OP	(-1)
+
+/* parse translation table - table driven parsers can be your FRIEND!
+ */
+struct SpecialToken {
+    char *name;	/* token name */
+    int value;	/* token id */
+};
+static struct SpecialToken VariousWords[] = {
+    { "midnight", MIDNIGHT },	/* 00:00:00 of today or tomorrow */
+    { "noon", NOON },		/* 12:00:00 of today or tomorrow */
+    { "teatime", TEATIME },	/* 16:00:00 of today or tomorrow */
+    { "am", AM },		/* morning times for 0-12 clock */
+    { "pm", PM },		/* evening times for 0-12 clock */
+    { "tomorrow", TOMORROW },
+    { "yesterday", YESTERDAY },
+    { "today", TODAY },
+    { "now", NOW },
+    { "n", NOW },
+    { "start", START },
+    { "s", START },	
+    { "end", END },
+    { "e", END },
+
+    { "jan", JAN },
+    { "feb", FEB },
+    { "mar", MAR },
+    { "apr", APR },
+    { "may", MAY },
+    { "jun", JUN },
+    { "jul", JUL },
+    { "aug", AUG },
+    { "sep", SEP },
+    { "oct", OCT },
+    { "nov", NOV },
+    { "dec", DEC },
+    { "january", JAN },
+    { "february", FEB },
+    { "march", MAR },
+    { "april", APR },
+    { "may", MAY },
+    { "june", JUN },
+    { "july", JUL },
+    { "august", AUG },
+    { "september", SEP },
+    { "october", OCT },
+    { "november", NOV },
+    { "december", DEC },
+    { "sunday", SUN },
+    { "sun", SUN },
+    { "monday", MON },
+    { "mon", MON },
+    { "tuesday", TUE },
+    { "tue", TUE },
+    { "wednesday", WED },
+    { "wed", WED },
+    { "thursday", THU },
+    { "thu", THU },
+    { "friday", FRI },
+    { "fri", FRI },
+    { "saturday", SAT },
+    { "sat", SAT },
+    { NULL, 0 }			/*** SENTINEL ***/
+};
+
+static struct SpecialToken TimeMultipliers[] = {
+    { "second", SECONDS },	/* seconds multiplier */
+    { "seconds", SECONDS },	/* (pluralized) */
+    { "sec", SECONDS },		/* (generic) */
+    { "s", SECONDS },		/* (short generic) */
+    { "minute", MINUTES },	/* minutes multiplier */
+    { "minutes", MINUTES },	/* (pluralized) */
+    { "min", MINUTES },		/* (generic) */
+    { "m", MONTHS_MINUTES },	/* (short generic) */
+    { "hour", HOURS },		/* hours ... */
+    { "hours", HOURS },		/* (pluralized) */
+    { "hr", HOURS },		/* (generic) */
+    { "h", HOURS },		/* (short generic) */
+    { "day", DAYS },		/* days ... */
+    { "days", DAYS },		/* (pluralized) */
+    { "d", DAYS },		/* (short generic) */
+    { "week", WEEKS },		/* week ... */
+    { "weeks", WEEKS },		/* (pluralized) */
+    { "wk", WEEKS },		/* (generic) */
+    { "w", WEEKS },		/* (short generic) */
+    { "month", MONTHS },	/* week ... */
+    { "months", MONTHS },	/* (pluralized) */
+    { "mon", MONTHS },		/* (generic) */
+    { "year", YEARS },		/* year ... */
+    { "years", YEARS },		/* (pluralized) */
+    { "yr", YEARS },		/* (generic) */
+    { "y", YEARS },		/* (short generic) */
+    { NULL, 0 }			/*** SENTINEL ***/
+};
+
+/* File scope variables */
+
+/* context dependant list of specials for parser to recognize,
+ * required for us to be able distinguish between 'mon' as 'month'
+ * and 'mon' as 'monday'
+ */
+static struct SpecialToken *Specials;
+
+static char **scp;	/* scanner - pointer at arglist */
+static char scc;	/* scanner - count of remaining arguments */
+static char *sct;	/* scanner - next char pointer in current argument */
+static int need;	/* scanner - need to advance to next argument */
+
+static char *sc_token;	/* scanner - token buffer */
+static size_t sc_len;   /* scanner - lenght of token buffer */
+static int sc_tokid;	/* scanner - token id */
+
+static int need_to_free = 0; /* means that we need deallocating memory */
+
+/* Local functions */
+
+void EnsureMemFree ()
+{
+  if( need_to_free )
+    {
+    free(sc_token);
+    need_to_free = 0;
+    }
+}
+
+/*
+ * A hack to compensate for the lack of the C++ exceptions
+ *
+ * Every function func that might generate parsing "exception"
+ * should return TIME_OK (aka NULL) or pointer to the error message,
+ * and should be called like this: try(func(args));
+ *
+ * [NOTE: when try(...) is used as the only statement in the "if-true"
+ *  part of the if statement that also has an "else" part it should be
+ *  either enclosed in the curly braces (despite the fact that it looks
+ *  like a single statement) or NOT follwed by the ";"]
+ */
+#define try(b)		{ \
+			char *_e; \
+			if((_e=(b))) \
+			  { \
+			  EnsureMemFree(); \
+			  return _e; \
+			  } \
+			}
+
+/*
+ * The panic() function was used in the original code to die, we redefine
+ * it as macro to start the chain of ascending returns that in conjunction
+ * with the try(b) above will simulate a sort of "exception handling"
+ */
+
+#define panic(e)	{ \
+			EnsureMemFree(); \
+			return (e); \
+			}
+
+/*
+ * ve() and e() are used to set the return error,
+ * the most aprropriate use for these is inside panic(...) 
+ */
+#define MAX_ERR_MSG_LEN	1024
+static char errmsg[ MAX_ERR_MSG_LEN ];
+
+static char *
+ve ( char *fmt, va_list ap )
+{
+/* vsnprintf( errmsg, MAX_ERR_MSG_LEN, fmt, ap ); */
+  vsprintf( errmsg, fmt, ap );
+  EnsureMemFree();
+  return( errmsg );
+}
+
+static char *
+e ( char *fmt, ... )
+{
+  char *err;
+  va_list ap;
+  va_start( ap, fmt );
+  err = ve( fmt, ap );
+  va_end( ap );
+  return( err );
+}
+
+/*
+ * parse a token, checking if it's something special to us
+ */
+static int
+parse_token(char *arg)
+{
+    int i;
+
+    for (i=0; Specials[i].name != NULL; i++)
+	if (strcasecmp(Specials[i].name, arg) == 0)
+	    return sc_tokid = Specials[i].value;
+
+    /* not special - must be some random id */
+    return sc_tokid = ID;
+} /* parse_token */
+
+
+/*
+ * init_scanner() sets up the scanner to eat arguments
+ */
+static char *
+init_scanner(int argc, char **argv)
+{
+    scp = argv;
+    scc = argc;
+    need = 1;
+    sc_len = 1;
+    while (argc-- > 0)
+	sc_len += strlen(*argv++);
+
+    sc_token = (char *) malloc(sc_len);
+    if( sc_token == NULL )
+      return "Failed to allocate memory";
+    need_to_free = 1;
+    return TIME_OK;
+} /* init_scanner */
+
+/*
+ * token() fetches a token from the input stream
+ */
+static int
+token()
+{
+    int idx;
+
+    while (1) {
+	memset(sc_token, 0, sc_len);
+	sc_tokid = EOF;
+	idx = 0;
+
+	/* if we need to read another argument, walk along the argument list;
+	 * when we fall off the arglist, we'll just return EOF forever
+	 */
+	if (need) {
+	    if (scc < 1)
+		return sc_tokid;
+	    sct = *scp;
+	    scp++;
+	    scc--;
+	    need = 0;
+	}
+	/* eat whitespace now - if we walk off the end of the argument,
+	 * we'll continue, which puts us up at the top of the while loop
+	 * to fetch the next argument in
+	 */
+	while (isspace(*sct) || *sct == '_' || *sct == ',' )
+	    ++sct;
+	if (!*sct) {
+	    need = 1;
+	    continue;
+	}
+
+	/* preserve the first character of the new token
+	 */
+	sc_token[0] = *sct++;
+
+	/* then see what it is
+	 */
+	if (isdigit(sc_token[0])) {
+	    while (isdigit(*sct))
+		sc_token[++idx] = *sct++;
+	    sc_token[++idx] = 0;
+	    return sc_tokid = NUMBER;
+	}
+	else if (isalpha(sc_token[0])) {
+	    while (isalpha(*sct))
+		sc_token[++idx] = *sct++;
+	    sc_token[++idx] = 0;
+	    return parse_token(sc_token);
+	}
+	else switch(sc_token[0]) {
+	    case ':': return sc_tokid = COLON;
+	    case '.': return sc_tokid = DOT;
+	    case '+': return sc_tokid = PLUS;
+	    case '-': return sc_tokid = MINUS;
+	    case '/': return sc_tokid = SLASH;
+	    default:  return sc_tokid = JUNK;
+	}
+    } /* while (1) */
+} /* token */
+
+
+/* 
+ * expect() gets a token and complins if it's not the token we want
+ */
+static char *
+expect(int desired, char *complain_fmt, ...)
+{
+    va_list ap;
+    va_start( ap, complain_fmt );
+    if (token() != desired) {
+	panic(ve( complain_fmt, ap ));
+    }
+    va_end( ap );
+    return TIME_OK;
+    
+} /* expect */
+
+
+/*
+ * plus_minus() is used to parse a single NUMBER TIME-UNIT pair
+ *              for the OFFSET-SPEC.
+ *              It allso applies those m-guessing euristics.
+ */
+static char *
+plus_minus(struct time_value *ptv, int doop)
+{
+    static int op = PLUS;
+    static int prev_multiplier = -1;
+    int delta;
+
+    if( doop >= 0 ) 
+      {
+      op = doop;
+      try(expect(NUMBER,"There should be number after '%c'", op == PLUS ? '+' : '-'));
+      prev_multiplier = -1; /* reset months-minutes guessing mechanics */
+      }
+    /* if doop is < 0 then we repeat the previous op
+     * with the prefetched number */
+
+    delta = atoi(sc_token);
+
+    if( token() == MONTHS_MINUTES )
+      {
+      /* hard job to guess what does that -5m means: -5mon or -5min? */
+      switch(prev_multiplier)
+	{
+        case DAYS:
+        case WEEKS:
+        case MONTHS:
+        case YEARS:
+             sc_tokid = MONTHS;
+	     break;
+
+        case SECONDS:
+        case MINUTES:
+        case HOURS:
+	     sc_tokid = MINUTES;
+	     break;
+
+        default:
+             if( delta < 25 ) /* it may be some other value but in the context
+			       * of RRD who needs less than 25 min deltas? */
+               sc_tokid = MONTHS;
+             else
+	       sc_tokid = MINUTES;
+        }
+      }
+    prev_multiplier = sc_tokid;
+    switch (sc_tokid) {
+    case YEARS:
+	    ptv->tm.tm_year += (op == PLUS) ? delta : -delta;
+	    return TIME_OK;
+    case MONTHS:
+	    ptv->tm.tm_mon += (op == PLUS) ? delta : -delta;
+	    return TIME_OK;
+    case WEEKS:
+	    delta *= 7;
+	    /* FALLTHRU */
+    case DAYS:
+	    ptv->tm.tm_mday += (op == PLUS) ? delta : -delta;
+	    return TIME_OK;
+    case HOURS:
+	    ptv->offset += (op == PLUS) ? delta*60*60 : -delta*60*60;
+	    return TIME_OK;
+    case MINUTES:
+	    ptv->offset += (op == PLUS) ? delta*60 : -delta*60;
+	    return TIME_OK;
+    case SECONDS:
+	    ptv->offset += (op == PLUS) ? delta : -delta;
+	    return TIME_OK;
+    }
+    panic(e("well-known time unit expected after %d", delta));
+    /* NORETURN */
+    return TIME_OK; /* to make compiler happy :) */
+} /* plus_minus */
+
+
+/*
+ * tod() computes the time of day (TIME-OF-DAY-SPEC)
+ */
+static char *
+tod(struct time_value *ptv)
+{
+    int hour, minute = 0;
+    int tlen;
+
+    hour = atoi(sc_token);
+    tlen = strlen(sc_token);
+
+    /* first pick out the time of day - if it's 4 digits, we assume
+     * a HHMM time, otherwise it's HH (COLON|DOT) MM time
+     */
+    token();
+    if (sc_tokid == COLON || sc_tokid == DOT) {
+	try(expect(NUMBER,
+            "Parsing HH%cMM syntax, expecting MM as number, got none",
+            sc_tokid == DOT ? '.' : ':' ));
+	minute = atoi(sc_token);
+	if (minute > 59) {
+	    panic(e("parsing HH%cMM syntax, got MM = %d (>59!)",
+                     sc_tokid == DOT ? '.' : ':', minute ));
+	}
+	token();
+    }
+    else if (tlen == 4) {
+	minute = hour%100;
+	if (minute > 59) {
+	    panic(e("parsing HHMM syntax, got MM = %d (>59!)", minute ));
+	}
+	hour = hour/100;
+    }
+
+    /* check if an AM or PM specifier was given
+     */
+    if (sc_tokid == AM || sc_tokid == PM) {
+	if (hour > 12) {
+	    panic(e("there cannot be more than 12 AM or PM hours"));
+	}
+	if (sc_tokid == PM) {
+	    if (hour != 12)	/* 12:xx PM is 12:xx, not 24:xx */
+			hour += 12;
+	} else {
+	    if (hour == 12)	/* 12:xx AM is 00:xx, not 12:xx */
+			hour = 0;
+	}
+	token();
+    }
+    else if (hour > 23) {
+	panic(e("the time-of-day hour > 23"));
+    }
+    ptv->tm.tm_hour = hour;
+    ptv->tm.tm_min = minute;
+    ptv->tm.tm_sec = 0;
+    if (ptv->tm.tm_hour == 24) {
+	ptv->tm.tm_hour = 0;
+	ptv->tm.tm_mday++;
+    }
+  return TIME_OK;
+} /* tod */
+
+
+/*
+ * assign_date() assigns a date, adjusting year as appropriate
+ */
+static char *
+assign_date(struct time_value *ptv, long mday, long mon, long year)
+{
+    if (year > 99) {
+	if (year > 1899)
+	    year -= 1900;
+	else {
+	    panic(e("invalid year %d (should be either 00-99 or >1900)",
+                    year));
+	}
+    } else if( year >= 0 && year < 38 ) {
+	year += 100;	     /* Allow year 2000-2037 to be specified as   */
+    }			     /* 00-37 until the problem of 2038 year will */
+			     /* arise for unices with 32-bit time_t :)    */
+    if (year < 0) {
+      panic(e("don't know what's the use of the year %d (negative!)?", year));
+    }
+    if (year < 70) {
+      panic(e("won't handle dates before epoch (01/01/1970), sorry"));
+    }
+
+    ptv->tm.tm_mday = mday;
+    ptv->tm.tm_mon = mon;
+    ptv->tm.tm_year = year;
+  return TIME_OK;
+} /* assign_date */
+
+
+/* 
+ * day() picks apart DAY-SPEC-[12]
+ */
+static char *
+day(struct time_value *ptv)
+{
+    long mday, wday, mon, year = ptv->tm.tm_year;
+    int tlen;
+
+    switch (sc_tokid) {
+    case YESTERDAY:
+	    ptv->tm.tm_mday--;
+	    /* FALLTRHU */
+    case TODAY:	/* force ourselves to stay in today - no further processing */
+	    token();
+	    break;
+    case TOMORROW:
+	    ptv->tm.tm_mday++;
+	    token();
+	    break;
+
+    case JAN: case FEB: case MAR: case APR: case MAY: case JUN:
+    case JUL: case AUG: case SEP: case OCT: case NOV: case DEC:
+	    /* do month mday [year]
+	     */
+	    mon = (sc_tokid-JAN);
+	    try(expect(NUMBER,
+		"the day of the month should follow month name"));
+	    mday = atol(sc_token);
+	    if (token() == NUMBER) {
+		year = atol(sc_token);
+		token();
+	    }
+	    else
+		year = ptv->tm.tm_year;
+	    try(assign_date(ptv, mday, mon, year));
+	    break;
+
+    case SUN: case MON: case TUE:
+    case WED: case THU: case FRI:
+    case SAT:
+	    /* do a particular day of the week
+	     */
+	    wday = (sc_tokid-SUN);
+	    ptv->tm.tm_mday += (wday - ptv->tm.tm_wday);
+	    break;
+	    /*
+	    mday = ptv->tm.tm_mday;
+	    mday += (wday - ptv->tm.tm_wday);
+	    ptv->tm.tm_wday = wday;
+
+	    try(assign_date(ptv, mday, ptv->tm.tm_mon, ptv->tm.tm_year));
+	    break;
+	    */
+
+    case NUMBER:
+	    /* get numeric DDMM[YY]YY, MM/DD/[YY]YY, or DD.MM.[YY]YY
+	     */
+	    tlen = strlen(sc_token);
+	    mon = atol(sc_token);
+	    token();
+
+	    if (sc_tokid == SLASH || sc_tokid == DOT) {
+		int sep;
+
+		sep = sc_tokid;
+		try(expect(NUMBER,"there should be %s number after '%c'",
+			   sep == DOT ? "month" : "day", sep == DOT ? '.' : '/'));
+		mday = atol(sc_token);
+		if (token() == sep) {
+		    try(expect(NUMBER,"there should be year number after '%c'",
+			       sep == DOT ? '.' : '/'));
+		    year = atol(sc_token);
+		    token();
+		}
+
+		/* flip months and days for european timing
+		 */
+		if (sep == DOT) {
+		    long x = mday;
+		    mday = mon;
+		    mon = x;
+		}
+	    }
+	    else if (tlen == 6 || tlen == 8) {
+		if (tlen == 8) {
+		    year = (mon % 10000) - 1900;
+		    mon /= 10000;
+		}
+		else {
+		    year = mon % 100;
+		    mon /= 100;
+		}
+		mday = mon / 100;
+		mon %= 100;
+	    }
+	    else {
+		panic(e("can't parse your date as DDMM[YY]YY"));
+	    }
+
+	    mon--;
+	    if(mon < 0 || mon > 11 ) {
+	        panic(e("did you really mean month %d?", mon+1));
+	    }
+	    if(mday < 1 || mday > 31) {
+	        panic(e("I'm afraid that %d is not a valid day of the month",
+                         mday));
+	    }
+
+	    try(assign_date(ptv, mday, mon, year));
+	    break;
+    } /* case */
+  return TIME_OK;
+} /* month */
+
+
+/* Global functions */
+
+
+/*
+ * parsetime() is the external interface that takes tspec, parses
+ * it and puts the result in the time_value structure *ptv.
+ * It can return either absolute times (these are ensured to be
+ * correct) or relative time references that are expected to be
+ * added to some absolute time value and then normalized by
+ * mktime() The return value is either TIME_OK (aka NULL) or
+ * the pointer to the error message in the case of problems
+ */
+char *
+parsetime(char *tspec, struct time_value *ptv)
+{
+    time_t now = time(NULL);
+    int hr = 0;
+    /* this MUST be initialized to zero for midnight/noon/teatime */
+
+    Specials = VariousWords; /* initialize special words context */
+
+    try(init_scanner( 1, &tspec ));
+
+    /* establish the default time reference */
+    ptv->type = ABSOLUTE_TIME;
+    ptv->offset = 0;
+    ptv->tm = *localtime(&now);
+    ptv->tm.tm_isdst = -1; /* ?not needed? */
+
+    token();
+    switch (sc_tokid) {
+    case PLUS:
+    case MINUS:
+	    break; /* jump to OFFSET-SPEC part */
+
+    case START:
+	    ptv->type = RELATIVE_TO_START_TIME;
+	    goto KeepItRelative;
+    case END:
+	    ptv->type = RELATIVE_TO_END_TIME;
+	 KeepItRelative:
+	    ptv->tm.tm_sec  = 0;
+	    ptv->tm.tm_min  = 0;
+	    ptv->tm.tm_hour = 0;
+	    ptv->tm.tm_mday = 0;
+	    ptv->tm.tm_mon  = 0;
+	    ptv->tm.tm_year = 0;
+	    /* FALLTHRU */
+    case NOW:
+	    {
+	    int time_reference = sc_tokid;
+	    token();
+	    if( sc_tokid == PLUS || sc_tokid == MINUS )
+	      break;
+	    if( time_reference != NOW ) {
+	      panic(e("'start' or 'end' MUST be followed by +|- offset"));
+	    }
+	    else
+	      if( sc_tokid != EOF ) {
+	 	panic(e("'now' can be followed only be +|- offset"));	
+	      }
+	    };
+	    break;
+
+    /* Only absolute time specifications below */
+    case NUMBER:
+	    try(tod(ptv));
+	    try(day(ptv));
+	    break;
+
+	    /* evil coding for TEATIME|NOON|MIDNIGHT - we've initialised
+	     * hr to zero up above, then fall into this case in such a
+	     * way so we add +12 +4 hours to it for teatime, +12 hours
+	     * to it for noon, and nothing at all for midnight, then
+	     * set our rettime to that hour before leaping into the
+	     * month scanner
+	     */
+    case TEATIME:
+	    hr += 4;
+	    /* FALLTHRU */
+    case NOON:
+	    hr += 12;
+	    /* FALLTHRU */
+    case MIDNIGHT:
+	    if (ptv->tm.tm_hour >= hr) {
+		ptv->tm.tm_mday++;
+		ptv->tm.tm_wday++;
+	    }
+	    ptv->tm.tm_hour = hr;
+	    ptv->tm.tm_min = 0;
+	    token();
+	    /* fall through to month setting */
+	    /* FALLTHRU */
+    default:
+	    try(day(ptv));
+	    break;
+    } /* ugly case statement */
+
+    /*
+     * the OFFSET-SPEC part
+     *
+     * (NOTE, the sc_tokid was prefetched for us by the previous code)
+     */
+    if( sc_tokid == PLUS || sc_tokid == MINUS ) {
+	Specials = TimeMultipliers; /* switch special words context */
+	while( sc_tokid == PLUS || sc_tokid == MINUS ||
+			       sc_tokid == NUMBER ) {
+	    if( sc_tokid == NUMBER ) {
+	        try(plus_minus(ptv, PREVIOUS_OP ));
+	    } else
+	        try(plus_minus(ptv, sc_tokid));
+	    token(); /* We will get EOF eventually but that's OK, since
+			    token() will return us as many EOFs as needed */
+	}
+    }
+
+    /* now we should be at EOF */
+    if( sc_tokid != EOF ) {
+      panic(e("unparsable trailing text: '...%s%s'", sc_token, sct ));
+    }
+
+    ptv->tm.tm_isdst = -1; /* for mktime to guess DST status */
+    if( ptv->type == ABSOLUTE_TIME )
+      if( mktime( &ptv->tm ) == -1 ) { /* normalize & check */
+        /* can happen for "nonexistent" times, e.g. around 3am */
+	/* when winter -> summer time correction eats a hour */
+        panic(e("the specified time is incorrect (out of range?)"));
+      }
+    return TIME_OK;
+} /* parsetime */

Added: trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_tool.h
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_tool.h	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_tool.h	Sat Jul 13 18:46:04 2002
@@ -0,0 +1,133 @@
+/*****************************************************************************
+ * RRDTOOL 0.99.29 Copyright Tobias Oetiker, 1997,1998, 1999
+ *****************************************************************************
+ * rrd_tool.h   Common Header File
+ *****************************************************************************
+ * $Id: rrd_tool.h,v 1.5 1998/03/08 12:35:11 oetiker Exp oetiker $
+ * $Log: rrd_tool.h,v $
+ *****************************************************************************/
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+
+#ifndef _RRD_TOOL_H
+#define _RRD_TOOL_H
+
+#ifdef WIN32
+# include "ntconfig.h"
+#else
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+
+#if HAVE_MATH_H
+# include <math.h>
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#if HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+#if HAVE_SYS_TIMES_H
+# include <sys/times.h>
+#endif
+#if HAVE_SYS_RESOURCE_H
+# include <sys/resource.h>
+#if (defined(__svr4__) && defined(__sun__))
+/* Solaris headers (pre 2.6) don't have a getrusage prototype.
+   Use this instead. */
+extern int getrusage(int, struct rusage *);
+#endif /* __svr4__ && __sun__ */
+#endif
+
+#ifdef WANT_AT_STYLE_TIMESPEC
+#include "parsetime.h"
+#endif
+
+#ifndef WIN32
+
+/* unix-only includes */
+#ifndef isnan
+int isnan(double value);
+#endif
+
+#else
+
+/* Win32 only includes */
+
+#include <float.h>        /* for _isnan  */
+#define isnan _isnan
+
+#endif
+
+/* local include files -- need to be after the system ones */
+#include "getopt.h"
+#include "rrd_format.h"
+
+#ifndef max
+#define max(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+#ifndef min
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#endif                                                   
+
+#define DIM(x) (sizeof(x)/sizeof(x[0]))
+
+/* main function blocks */
+int    rrd_create(int argc, char **argv);
+int    rrd_update(int argc, char **argv);
+int    rrd_graph(int argc, char **argv, char ***prdata, int *xsize, int *ysize);
+int    rrd_fetch(int argc, char **argv, 
+		 time_t *start, time_t *end, unsigned long *step, 
+		 unsigned long *ds_cnt, char ***ds_namv, rrd_value_t **data);
+int    rrd_dump(int argc, char **argv);
+int    rrd_tune(int argc, char **argv);
+time_t rrd_last(int argc, char **argv);
+
+/* HELPER FUNCTIONS */
+void rrd_set_error(char *fmt,...);
+void rrd_clear_error(void);
+int  rrd_test_error(void);
+char *rrd_get_error(void);
+
+int rrd_create_fn(char *file_name, rrd_t *rrd);
+int rrd_fetch_fn(char *filename, enum cf_en cf_idx,
+		 time_t *start,time_t *end,
+		 unsigned long *step,
+		 unsigned long *ds_cnt,
+		 char        ***ds_namv,
+		 rrd_value_t **data);
+void rrd_free(rrd_t *rrd);
+void rrd_init(rrd_t *rrd);
+
+int  rrd_open(char *file_name, FILE **in_file, rrd_t *rrd, int rdwr);
+
+
+#define RRD_READONLY    0
+#define RRD_READWRITE   1
+
+enum cf_en cf_conv(char *string);
+enum dst_en dst_conv(char *string);
+long ds_match(rrd_t *rrd,char *ds_nam);
+double rrd_diff(char *a, char *b);
+
+#endif
+
+
+
+#ifdef  __cplusplus
+}
+#endif
+
+

Added: trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_update.c
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_update.c	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/src/rrd_update.c	Sat Jul 13 18:46:04 2002
@@ -0,0 +1,732 @@
+/*****************************************************************************
+ * RRDTOOL 0.99.29 Copyright Tobias Oetiker, 1997, 1998, 1999
+ *****************************************************************************
+ * rrd_update.c  RRD Update Function
+ *****************************************************************************
+ * $Id: rrd_update.c,v 1.7 1998/03/08 12:35:11 oetiker Exp oetiker $
+ * $Log: rrd_update.c,v $
+ *****************************************************************************/
+
+#include "rrd_tool.h"
+#include <sys/types.h>
+#include <fcntl.h>
+
+#ifdef WIN32
+ #include <sys/locking.h>
+ #include <sys/stat.h>
+ #include <io.h>
+#else
+ #include <unistd.h>
+#endif
+
+
+/* Prototypes */
+int LockRRD(FILE *rrd_file);
+
+/*#define DEBUG */
+
+int 
+rrd_update(int argc, char **argv)
+{
+
+    int              arg_i = 2;
+    long             i,ii,iii;
+
+    unsigned long    rra_begin;          /* byte pointer to the rra
+					  * area in the rrd file.  this
+					  * pointer never changes value */
+    unsigned long    rra_start;          /* byte pointer to the rra
+					  * area in the rrd file.  this
+					  * pointer changes as each rrd is
+					  * processed. */
+    unsigned long    interval,
+	pre_int,post_int;                /* interval between this and
+					  * the last run */
+    unsigned long    proc_pdp_st;        /* which pdp_st was the last
+					  * to be processed */
+    unsigned long    occu_pdp_st;        /* when was the pdp_st
+					  * before the last update
+					  * time */
+    unsigned long    proc_pdp_age;       /* how old was the data in
+					  * the pdp prep area when it
+					  * was last updated */
+    unsigned long    occu_pdp_age;       /* how long ago was the last
+					  * pdp_step time */
+    unsigned long    pdp_st;             /* helper for cdp_prep 
+					  * processing */
+    rrd_value_t      *pdp_new;           /* prepare the incoming data
+					  * to be added the the
+					  * existing entry */
+    rrd_value_t      *pdp_temp;          /* prepare the pdp values 
+					  * to be added the the
+					  * cdp values */
+
+    long             *tmpl_idx;          /* index representing the settings
+					    transported by the template index */
+    long             tmpl_max = 0;
+
+    FILE             *rrd_file;
+    rrd_t            rrd;
+    time_t           current_time = time(NULL);
+    char             **updvals;
+    int              wrote_to_file = 0;
+    char             *template = NULL;          
+
+    rrd_init(&rrd);
+    while (1) {
+	static struct option long_options[] =
+	{
+	    {"template",      required_argument, 0, 't'},
+	    {0,0,0,0}
+	};
+	int option_index = 0;
+	int opt;
+	opt = getopt_long(argc, argv, "t:", 
+			  long_options, &option_index);
+	
+	if (opt == EOF)
+	  break;
+	
+	switch(opt) {
+	case 't':
+	    template = optarg;
+	    break;
+
+	case '?':
+	    rrd_set_error("unknown option '%s'",argv[optind-1]);
+            rrd_free(&rrd);
+	    return(-1);
+	}
+    }
+
+    /* need at least 2 arguments: filename, data. */
+    if (argc-optind < 2) {
+	rrd_set_error("not enough arguments");
+	return -1;
+    }
+
+    if(rrd_open(argv[optind],&rrd_file,&rrd, RRD_READWRITE)==-1){
+	return -1;
+    }
+    rra_begin=ftell(rrd_file);
+    rra_start=rra_begin;
+
+    /* get exclusive lock to whole file.
+     * lock gets removed when we close the file.
+     */
+    if (LockRRD(rrd_file) != 0) {
+      rrd_set_error("could not lock RRD");
+      rrd_free(&rrd);
+      fclose(rrd_file);
+      return(-1);   
+    }
+
+    if((updvals = malloc( sizeof(char*) * (rrd.stat_head->ds_cnt+1)))==NULL){
+	rrd_set_error("allocating updvals pointer array");
+	rrd_free(&rrd);
+        fclose(rrd_file);
+	return(-1);
+    }
+
+    if ((pdp_temp = malloc(sizeof(rrd_value_t)
+			   *rrd.stat_head->ds_cnt))==NULL){
+	rrd_set_error("allocating pdp_temp ...");
+	free(updvals);
+	rrd_free(&rrd);
+        fclose(rrd_file);
+	return(-1);
+    }
+
+    if ((tmpl_idx = malloc(sizeof(unsigned long)
+			   *(rrd.stat_head->ds_cnt+1)))==NULL){
+	rrd_set_error("allocating template_idx ...");
+	free(pdp_temp);
+	free(updvals);
+	rrd_free(&rrd);
+        fclose(rrd_file);
+	return(-1);
+    }
+    /* initialize template redirector */
+    for (i=0;i<=rrd.stat_head->ds_cnt;i++) tmpl_idx[i]=i;
+    tmpl_max=rrd.stat_head->ds_cnt;
+    if (template) {
+	char *dsname;
+	long temp_len;
+	dsname = template;
+	temp_len = strlen(template);
+	tmpl_max = 0;
+	for (i=0;i<=temp_len;i++) {
+	    if (template[i] == ':' || template[i] =='\0') {
+		template[i] = '\0';
+		if ((tmpl_idx[++tmpl_max] = ds_match(&rrd,dsname)) == -1){			    free(updvals);
+		    free(pdp_temp);
+		    free(tmpl_idx);
+		    rrd_free(&rrd);
+		    fclose(rrd_file);
+		    return(-1);
+		}
+		/* the first element is always the time */
+		tmpl_idx[tmpl_max]++; 
+	    }	    
+	}
+    }
+    if ((pdp_new = malloc(sizeof(rrd_value_t)
+			  *rrd.stat_head->ds_cnt))==NULL){
+	rrd_set_error("allocating pdp_new ...");
+	free(updvals);
+	free(pdp_temp);
+	free(tmpl_idx);
+	rrd_free(&rrd);
+        fclose(rrd_file);
+	return(-1);
+    }
+
+    /* loop through the arguments. */
+    for(arg_i=optind+1; arg_i<argc;arg_i++) {
+	unsigned long count_colons = 0;
+
+/* fprintf(stderr, "Handling %s\t%s\n", argv[arg_i]); */
+	/* parse the update line ... the first value is the time, the
+	   remaining ones are the datasources */
+	/* skip any initial :'s */
+	i=0;
+	while (argv[arg_i][i] && argv[arg_i][i] == ':')
+	    ++i;
+	
+	/* initialize all ds input to unknown except the first one
+           which has always got to be set */
+	for(ii=1;ii<=rrd.stat_head->ds_cnt;ii++)
+	    updvals[ii] = "U";
+	ii=0;
+	updvals[ii++] = &argv[arg_i][i];
+	for (;argv[arg_i][i] != '\0';++i) {
+	    if (argv[arg_i][i] == ':') {
+		count_colons++;
+		argv[arg_i][i] = '\0';
+		if (ii<=tmpl_max) {
+		    updvals[tmpl_idx[ii++]] = &argv[arg_i][i+1];
+		}
+	    }
+	}
+
+	if (ii-1 != count_colons || ii-1 != tmpl_max) {
+	    rrd_set_error("expected %lu data source readings (got %lu) from %s...",
+			  tmpl_max, count_colons, argv[arg_i]);
+	    break;
+	}
+	
+        /* get the time from the reading ... handle N */
+	if (strcmp(updvals[0],"N")==0){
+	    current_time = time(NULL);
+	} else {
+	    current_time = atol(updvals[0]);
+	}
+	
+	if(current_time <= rrd.live_head->last_up){
+	    rrd_set_error("illegal attempt to update using time %ld when "
+			  "last update time is %ld (minimum one second step ",
+			  current_time, rrd.live_head->last_up);
+	    break;
+	}
+	
+	
+	/* seek to the beginning of the rrd's */
+	if(fseek(rrd_file, rra_begin, SEEK_SET) != 0) {
+	    rrd_set_error("seek error in rrd");
+	    break;
+	}
+	
+	rra_start = rra_begin;
+
+	/* when was the current pdp started */
+	proc_pdp_age = rrd.live_head->last_up % rrd.stat_head->pdp_step;
+	proc_pdp_st = rrd.live_head->last_up - proc_pdp_age;
+
+	/* when did the last pdp_st occur */
+	occu_pdp_age = current_time % rrd.stat_head->pdp_step;
+	occu_pdp_st = current_time - occu_pdp_age;
+	interval = current_time - rrd.live_head->last_up;
+    
+	if (occu_pdp_st > proc_pdp_st){
+	    /* OK we passed the pdp_st moment*/
+	    pre_int =  occu_pdp_st - rrd.live_head->last_up; /* how much of the input data
+							      * occurred before the latest
+							      * pdp_st moment*/
+	    post_int = occu_pdp_age;			     /* how much after it */
+	} else {
+	    pre_int = interval;
+	    post_int = 0;
+	}
+
+#ifdef DEBUG
+	printf(
+	       "proc_pdp_age %lu\t"
+	       "proc_pdp_st %lu\t" 
+	       "occu_pfp_age %lu\t" 
+	       "occu_pdp_st %lu\t"
+	       "int %lu\t"
+	       "pre_int %lu\t"
+	       "post_int %lu\n", proc_pdp_age, proc_pdp_st, 
+		occu_pdp_age, occu_pdp_st,
+	       interval, pre_int, post_int);
+#endif
+    
+	/* process the data sources and update the pdp_prep 
+	 * area accordingly */
+	for(i=0;i<rrd.stat_head->ds_cnt;i++){
+	    enum dst_en dst_idx;
+	    dst_idx= dst_conv(rrd.ds_def[i].dst);
+	    if((updvals[i+1][0] != 'U') &&
+	       rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt >= interval) {
+		/* the data source type defines how to process the data */
+		/* pdp_temp contains rate * time ... eg the bytes
+		 * transferred during the interval. Doing it this way saves
+		 * a lot of math operations */
+		
+
+		switch(dst_idx){
+		case DST_COUNTER:
+		case DST_DERIVE:
+		    if(rrd.pdp_prep[i].last_ds[0] != 'U'){
+			pdp_new[i]= rrd_diff(updvals[i+1],rrd.pdp_prep[i].last_ds);
+			if(dst_idx == DST_COUNTER) {
+				/* simple overflow catcher sugestet by andres kroonmaa */
+				/* this will fail terribly for non 32 or 64 bit counters ... */
+				/* are there any others in SNMP land ? */
+			    if (pdp_new[i] < (double)0.0 ) 
+				pdp_new[i] += (double)4294967296.0 ;  /* 2^32 */
+			    if (pdp_new[i] < (double)0.0 ) 
+				pdp_new[i] += (double)18446744069414584320.0; /* 2^64-2^32 */;
+			}
+		    }
+			else
+			    pdp_new[i]= DNAN;		
+		    break;
+		case DST_ABSOLUTE:
+		    pdp_new[i]= atof(updvals[i+1]);		
+		    break;
+		case DST_GAUGE:
+		    pdp_new[i] = atof(updvals[i+1]) * interval;
+		    break;
+		default:
+		    rrd_set_error("rrd contains and DS type : '%s'",
+				  rrd.ds_def[i].dst);
+		    break;
+		}
+		/* break out of this for loop if the error string is set */
+		if (rrd_test_error())
+		    break;
+	    } else {
+		/* no news is news all the same */
+		pdp_new[i] = DNAN;
+	    }
+	    
+	    /* make a copy of the command line argument for the next run */
+#ifdef DEBUG
+	    fprintf(stderr,
+		    "prep ds[%lu]\t"
+		    "last_arg '%s'\t"
+		    "this_arg '%s'\t"
+		    "pdp_new %10.2f\n",
+		    i,
+		    rrd.pdp_prep[i].last_ds,
+		    updvals[i+1], pdp_new[i]);
+#endif
+	    if(dst_idx == DST_COUNTER || dst_idx == DST_DERIVE){
+		strncpy(rrd.pdp_prep[i].last_ds,
+			updvals[i+1],LAST_DS_LEN-1);
+		rrd.pdp_prep[i].last_ds[LAST_DS_LEN]=0;
+	    }
+	}
+	/* break out of the argument parsing loop if the error_string is set */
+	if (rrd_test_error())
+	    break;
+
+	/* has a pdp_st moment occurred since the last run ? */
+
+	if (proc_pdp_st == occu_pdp_st){
+	    /* no we have not passed a pdp_st moment. therefore update is simple */
+
+	    for(i=0;i<rrd.stat_head->ds_cnt;i++){
+		if(isnan(pdp_new[i]))
+		    rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt += interval;
+		else
+		    rrd.pdp_prep[i].scratch[PDP_val].u_val+= pdp_new[i];
+#ifdef DEBUG
+		fprintf(stderr,
+			"NO PDP  ds[%lu]\t"
+			"value %10.2f\t"
+			"unkn_sec %5lu\n",
+			i,
+			rrd.pdp_prep[i].scratch[PDP_val].u_val,
+			rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt);
+#endif
+	    }	
+	} else {
+	    /* an pdp_st has occurred. */
+
+	    /* in pdp_prep[].scratch[PDP_val].u_val we have collected rate*seconds which 
+	     * occurred up to the last run. 	   
+	    pdp_new[] contains rate*seconds from the latest run.
+	    pdp_temp[] will contain the rate for cdp */
+
+
+	    for(i=0;i<rrd.stat_head->ds_cnt;i++){
+		/* update pdp_prep to the current pdp_st */
+		if(isnan(pdp_new[i]))
+		    rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt += pre_int;
+		else
+		    rrd.pdp_prep[i].scratch[PDP_val].u_val += 
+			pdp_new[i]/(double)interval*(double)pre_int;
+
+		/* if too much of the pdp_prep is unknown we dump it */
+		if ((rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt 
+		     > rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt) ||
+		    (occu_pdp_st-proc_pdp_st <= 
+		     rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt)) {
+		    pdp_temp[i] = DNAN;
+		} else {
+		    pdp_temp[i] = rrd.pdp_prep[i].scratch[PDP_val].u_val
+			/ (double)( occu_pdp_st
+				   - proc_pdp_st
+				   - rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt);
+		}
+		/* make pdp_prep ready for the next run */
+		if(isnan(pdp_new[i])){
+		    rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt = post_int;
+		    rrd.pdp_prep[i].scratch[PDP_val].u_val = 0.0;
+		} else {
+		    rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt = 0;
+		    rrd.pdp_prep[i].scratch[PDP_val].u_val = 
+			pdp_new[i]/(double)interval*(double)post_int;
+		}
+		/* make sure pdp_temp is neither too large or too small
+		 * if any of these occur it becomes unknown ...
+		 * sorry folks ... */
+		if (! isnan(pdp_temp[i]) && 
+		   	((! isnan(rrd.ds_def[i].par[DS_max_val].u_val) &&
+		           pdp_temp[i] > rrd.ds_def[i].par[DS_max_val].u_val) ||
+		         (! isnan(rrd.ds_def[i].par[DS_min_val].u_val) &&
+		           pdp_temp[i] < rrd.ds_def[i].par[DS_min_val].u_val))) {
+		    pdp_temp[i] = DNAN;
+		}
+#ifdef DEBUG
+		fprintf(stderr,
+			"PDP UPD ds[%lu]\t"
+			"pdp_temp %10.2f\t"
+			"new_prep %10.2f\t"
+			"new_unkn_sec %5lu\n",
+			i, pdp_temp[i],
+			rrd.pdp_prep[i].scratch[PDP_val].u_val,
+			rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt);
+#endif
+	    }
+
+
+	    /* now we have to integrate this data into the cdp_prep areas */
+	    /* going through the round robin archives */
+	    for(i = 0;
+		i < rrd.stat_head->rra_cnt;
+		i++){
+		enum cf_en current_cf = cf_conv(rrd.rra_def[i].cf_nam);
+		/* going through all pdp_st moments which have occurred 
+		 * since the last run */
+		for(pdp_st  = proc_pdp_st+rrd.stat_head->pdp_step; 
+		    pdp_st <= occu_pdp_st; 
+		    pdp_st += rrd.stat_head->pdp_step){
+
+#ifdef DEBUG
+		    fprintf(stderr,"RRA %lu STEP %lu\n",i,pdp_st);
+#endif
+
+		    if((pdp_st %
+			(rrd.rra_def[i].pdp_cnt*rrd.stat_head->pdp_step)) == 0){
+
+			/* later on the cdp_prep values will be transferred to
+			 * the rra.  we want to be in the right place. */
+			rrd.rra_ptr[i].cur_row++;
+			if (rrd.rra_ptr[i].cur_row >= rrd.rra_def[i].row_cnt)
+			    /* oops ... we have to wrap the beast ... */
+			    rrd.rra_ptr[i].cur_row=0;			
+#ifdef DEBUG
+			fprintf(stderr,"  -- RRA Preseek %ld\n",ftell(rrd_file));
+#endif
+
+			if(fseek(rrd_file, 
+				 (rra_start + (rrd.stat_head->ds_cnt
+					       *rrd.rra_ptr[i].cur_row
+					       * sizeof(rrd_value_t))), SEEK_SET) != 0){
+			    rrd_set_error("seek error in rrd");
+			    break;
+			}
+#ifdef DEBUG
+			fprintf(stderr,"  -- RRA Postseek %ld\n",ftell(rrd_file));
+#endif
+		    }
+
+		    for(ii = 0;
+			ii < rrd.stat_head->ds_cnt;
+			ii++){
+			iii=i*rrd.stat_head->ds_cnt+ii;
+		    
+			/* the contents of cdp_prep[].scratch[CDP_val].u_val depends
+			 * on the consolidation function ! */
+		    
+			if (isnan(pdp_temp[ii])){    /* pdp is unknown */
+			    rrd.cdp_prep[iii].scratch[CDP_unkn_pdp_cnt].u_cnt++;
+#ifdef DEBUG
+			    fprintf(stderr,"  ** UNKNOWN ADD %lu\n",
+				    rrd.cdp_prep[iii].scratch[CDP_unkn_pdp_cnt].u_cnt);
+#endif
+			} else {
+			    if (isnan(rrd.cdp_prep[iii].scratch[CDP_val].u_val)){
+				/* cdp_prep is unknown when it does not
+				 * yet contain data. It can not be zero for
+				 * things like mim and max consolidation
+				 * functions */
+#ifdef DEBUG
+				fprintf(stderr,"  ** INIT CDP %e\n", pdp_temp[ii]);
+#endif
+				rrd.cdp_prep[iii].scratch[CDP_val].u_val = pdp_temp[ii];
+			    }
+			    else {
+				switch (current_cf){
+				    case CF_AVERAGE:				
+					rrd.cdp_prep[iii].scratch[CDP_val].u_val+=pdp_temp[ii];
+#ifdef DEBUG
+					fprintf(stderr,"  ** AVERAGE %e\n", 
+						rrd.cdp_prep[iii].scratch[CDP_val].u_val);
+#endif
+					break;    
+				    case CF_MINIMUM:
+					if (pdp_temp[ii] < rrd.cdp_prep[iii].scratch[CDP_val].u_val)
+					    rrd.cdp_prep[iii].scratch[CDP_val].u_val = pdp_temp[ii];
+#ifdef DEBUG
+					fprintf(stderr,"  ** MINIMUM %e\n", 
+						rrd.cdp_prep[iii].scratch[CDP_val].u_val);
+#endif
+					break;
+				    case CF_MAXIMUM:
+					if (pdp_temp[ii] > rrd.cdp_prep[iii].scratch[CDP_val].u_val)
+					    rrd.cdp_prep[iii].scratch[CDP_val].u_val = pdp_temp[ii];
+#ifdef DEBUG
+					fprintf(stderr,"  ** MAXIMUM %e\n", 
+						rrd.cdp_prep[iii].scratch[CDP_val].u_val);
+#endif
+					break;
+				    case CF_LAST:
+					rrd.cdp_prep[iii].scratch[CDP_val].u_val=pdp_temp[ii];
+#ifdef DEBUG
+					fprintf(stderr,"  ** LAST %e\n", 
+						rrd.cdp_prep[iii].scratch[CDP_val].u_val);
+#endif
+					break;    
+				    default:
+					rrd_set_error("Unknown cf %s",
+						      rrd.rra_def[i].cf_nam);
+					break;
+				}
+			    }
+			}
+
+
+			/* is the data in the cdp_prep ready to go into
+			 * its rra ? */
+			if((pdp_st % 
+			    (rrd.rra_def[i].pdp_cnt*rrd.stat_head->pdp_step)) == 0){
+
+			    /* prepare cdp_pref for its transition to the rra. */
+			    if (rrd.cdp_prep[iii].scratch[CDP_unkn_pdp_cnt].u_cnt 
+				> rrd.rra_def[i].pdp_cnt*
+				rrd.rra_def[i].par[RRA_cdp_xff_val].u_val)
+				/* to much of the cdp_prep is unknown ... */
+				rrd.cdp_prep[iii].scratch[CDP_val].u_val = DNAN;
+			    else if (current_cf == CF_AVERAGE){
+				/* for a real average we have to divide
+				 * the sum we built earlier on. While ignoring
+				 * the unknown pdps */
+				rrd.cdp_prep[iii].scratch[CDP_val].u_val 
+					/= (rrd.rra_def[i].pdp_cnt
+					    -rrd.cdp_prep[iii].scratch[CDP_unkn_pdp_cnt].u_cnt);
+			    }
+			    /* we can write straight away, because we are
+			     * already in the right place ... */
+
+#ifdef DEBUG
+			    fprintf(stderr,"  -- RRA WRITE VALUE %e, at %ld\n",
+				    rrd.cdp_prep[iii].scratch[CDP_val].u_val,ftell(rrd_file));
+#endif
+
+			    if(fwrite(&(rrd.cdp_prep[iii].scratch[CDP_val].u_val),
+				      sizeof(rrd_value_t),1,rrd_file) != 1){
+				rrd_set_error("writing rrd");
+				break;
+			    }
+			    wrote_to_file = 1;
+
+#ifdef DEBUG
+			    fprintf(stderr,"  -- RRA WROTE new at %ld\n",ftell(rrd_file));
+#endif
+
+			    /* make cdp_prep ready for the next run */
+			    rrd.cdp_prep[iii].scratch[CDP_val].u_val = DNAN;
+			    rrd.cdp_prep[iii].scratch[CDP_unkn_pdp_cnt].u_cnt = 0;
+			}
+		    }
+		    /* break out of this loop if error_string has been set */
+		    if (rrd_test_error())
+			break;
+		}
+		/* break out of this loop if error_string has been set */
+		if (rrd_test_error())
+		    break;
+		/* to be able to position correctly in the next rra w move
+		 * the rra_start pointer on to the next rra */
+		rra_start += rrd.rra_def[i].row_cnt
+			*rrd.stat_head->ds_cnt*sizeof(rrd_value_t);
+
+	    }
+	    /* break out of the argument parsing loop if error_string is set */
+	    if (rrd_test_error())
+		break;
+	}
+	rrd.live_head->last_up = current_time;
+    }
+
+    /* if we got here and if there is an error and if the file has not been
+     * written to, then close things up and return. */
+    if (rrd_test_error()) {
+	free(updvals);
+	free(tmpl_idx);
+	rrd_free(&rrd);
+	free(pdp_temp);
+	free(pdp_new);
+        fclose(rrd_file);
+	return(-1);
+    }
+
+    /* aargh ... that was tough ... so many loops ... anyway, its done.
+     * we just need to write back the live header portion now*/
+
+    if (fseek(rrd_file, (sizeof(stat_head_t)
+			 + sizeof(ds_def_t)*rrd.stat_head->ds_cnt 
+			 + sizeof(rra_def_t)*rrd.stat_head->rra_cnt),
+	      SEEK_SET) != 0) {
+	rrd_set_error("seek rrd for live header writeback");
+	free(updvals);
+	free(tmpl_idx);
+	rrd_free(&rrd);
+	free(pdp_temp);
+	free(pdp_new);
+        fclose(rrd_file);
+	return(-1);
+    }
+
+    if(fwrite( rrd.live_head,
+	       sizeof(live_head_t), 1, rrd_file) != 1){
+	rrd_set_error("fwrite live_head to rrd");
+	free(updvals);
+	rrd_free(&rrd);
+	free(tmpl_idx);
+	free(pdp_temp);
+	free(pdp_new);
+        fclose(rrd_file);
+	return(-1);
+    }
+
+    if(fwrite( rrd.pdp_prep,
+	       sizeof(pdp_prep_t),
+	       rrd.stat_head->ds_cnt, rrd_file) != rrd.stat_head->ds_cnt){
+	rrd_set_error("ftwrite pdp_prep to rrd");
+	free(updvals);
+	rrd_free(&rrd);
+	free(tmpl_idx);
+	free(pdp_temp);
+	free(pdp_new);
+        fclose(rrd_file);
+	return(-1);
+    }
+
+    if(fwrite( rrd.cdp_prep,
+	       sizeof(cdp_prep_t),
+	       rrd.stat_head->rra_cnt *rrd.stat_head->ds_cnt, rrd_file) 
+       != rrd.stat_head->rra_cnt *rrd.stat_head->ds_cnt){
+
+	rrd_set_error("ftwrite cdp_prep to rrd");
+	free(updvals);
+	free(tmpl_idx);
+	rrd_free(&rrd);
+	free(pdp_temp);
+	free(pdp_new);
+        fclose(rrd_file);
+	return(-1);
+    }
+
+    if(fwrite( rrd.rra_ptr,
+	       sizeof(rra_ptr_t), 
+	       rrd.stat_head->rra_cnt,rrd_file) != rrd.stat_head->rra_cnt){
+	rrd_set_error("fwrite rra_ptr to rrd");
+	free(updvals);
+	free(tmpl_idx);
+	rrd_free(&rrd);
+	free(pdp_temp);
+	free(pdp_new);
+        fclose(rrd_file);
+	return(-1);
+    }
+
+    /* OK now close the files and free the memory */
+    if(fclose(rrd_file) != 0){
+	rrd_set_error("closing rrd");
+	free(updvals);
+	free(tmpl_idx);
+	rrd_free(&rrd);
+	free(pdp_temp);
+	free(pdp_new);
+	return(-1);
+    }
+
+    rrd_free(&rrd);
+    free(updvals);
+    free(tmpl_idx);
+    free(pdp_new);
+    free(pdp_temp);
+    return(0);
+}
+
+/*
+ * get exclusive lock to whole file.
+ * lock gets removed when we close the file
+ *
+ * returns 0 on success
+ */
+int
+LockRRD(FILE *rrdfile)
+{
+    int	rrd_fd;		/* File descriptor for RRD */
+    int			stat;
+
+    rrd_fd = fileno(rrdfile);
+
+	{
+#ifndef WIN32    
+		struct flock	lock;
+    lock.l_type = F_WRLCK;    /* exclusive write lock */
+    lock.l_len = 0;	      /* whole file */
+    lock.l_start = 0;	      /* start of file */
+    lock.l_whence = SEEK_SET;   /* end of file */
+
+    stat = fcntl(rrd_fd, F_SETLK, &lock);
+#else
+		struct _stat st;
+
+		if ( _fstat( rrd_fd, &st ) == 0 ) {
+			stat = _locking ( rrd_fd, _LK_NBLCK, st.st_size );
+		} else {
+			stat = -1;
+		}
+#endif
+	}
+
+    return(stat);
+}

Added: trunk/orca/packages/rrdtool-0.99.29.1/src/rrdtool.dsp
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/src/rrdtool.dsp	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/src/rrdtool.dsp	Sat Jul 13 18:46:04 2002
@@ -0,0 +1,92 @@
+# Microsoft Developer Studio Project File - Name="rrdtool" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=rrdtool - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "rrdtool.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "rrdtool.mak" CFG="rrdtool - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "rrdtool - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "rrdtool - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "rrdtool - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "rrdtool_"
+# PROP BASE Intermediate_Dir "rrdtool_"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "toolrelease"
+# PROP Intermediate_Dir "toolrelease"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I "..\gd1.2" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_CTYPE_DISABLE_MACROS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x100c /d "NDEBUG"
+# ADD RSC /l 0x100c /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib g!
di32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ..\gd1.2\release\gd.lib release\rrd.lib /nologo /subsystem:console /incremental:yes /debug /machine:I386
+
+!ELSEIF  "$(CFG)" == "rrdtool - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "rrdtool0"
+# PROP BASE Intermediate_Dir "rrdtool0"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "tooldebug"
+# PROP Intermediate_Dir "tooldebug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "." /I "..\gd1.2" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "_CTYPE_DISABLE_MACROS" /FR /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x100c /d "_DEBUG"
+# ADD RSC /l 0x100c /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo /o"rrdtool.bsc"
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ..\gd1.2\debug\gd.lib debug\rrd.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "rrdtool - Win32 Release"
+# Name "rrdtool - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\rrd_tool.c
+# End Source File
+# End Target
+# End Project
Added: trunk/orca/packages/rrdtool-0.99.29.1/src/rrd.dsp
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/src/rrd.dsp	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/src/rrd.dsp	Sat Jul 13 18:46:04 2002
@@ -0,0 +1,138 @@
+# Microsoft Developer Studio Project File - Name="rrd" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=rrd - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "rrd.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "rrd.mak" CFG="rrd - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "rrd - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "rrd - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "rrd - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "rrd___Wi"
+# PROP BASE Intermediate_Dir "rrd___Wi"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "release"
+# PROP Intermediate_Dir "release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I "..\gd1.2" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_CTYPE_DISABLE_MACROS" /FD /c
+# SUBTRACT CPP /X /YX
+# ADD BASE RSC /l 0x100c
+# ADD RSC /l 0x100c
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF  "$(CFG)" == "rrd - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "rrd___W0"
+# PROP BASE Intermediate_Dir "rrd___W0"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "debug"
+# PROP Intermediate_D!
ir "debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "." /I "..\gd1.2" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "_CTYPE_DISABLE_MACROS" /FR /FD /c
+# SUBTRACT CPP /X /YX
+# ADD BASE RSC /l 0x100c
+# ADD RSC /l 0x100c
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo /o"rrd.bsc"
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ENDIF 
+
+# Begin Target
+
+# Name "rrd - Win32 Release"
+# Name "rrd - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\diff.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\getopt.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\getopt1.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rrd_create.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rrd_dump.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rrd_error.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rrd_fetch.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rrd_format.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rrd_graph.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rrd_last.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rrd_open.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rrd_tune.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rrd_update.c
+# End Source File
+# End Target
+# End Project
Added: trunk/orca/packages/rrdtool-0.99.29.1/README
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/README	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/README	Sat Jul 13 18:46:04 2002
@@ -0,0 +1,77 @@
+Round Robin Database Tools
+==========================
+
+It is pretty easy to gather status information from all sorts of things,
+ranging from the temperature in your office to the number of octets which
+have passed through the FDDI interface of your router. But it is not so
+trivial to store this data in a efficient and systematic manner. This is
+where rrdtool kicks in. It lets you log and analyze the data you gather from
+all kinds of data- sources (DS). The data analysis part of rrdtool is based
+on the ability to quickly generate graphical representations of the data
+values collected over a definable time period.
+
+
+To compile:
+-----------
+
+		sh configure
+		make
+
+	(Please report configure/compilation problems to
+	 the developers list, so I can make it better. -jra)
+	
+	Please note that you should get perl-5.004 for things to work
+
+	Win32 users:
+	------------
+
+	Win32 things are controlled by the #define WIN32.
+	If your compiler doesn't define that, you should add it to
+	the compile line.	-jeff (jeff.allen at acm.org)
+
+
+Perl bindings:
+--------------
+The package contains two sets of Perl bindings.
+
+a) perl-piped which uses teh rrdtool through a set of pipes
+b) perl-shared which builds a shared library from rrdtool
+
+Both bindings get built by the toplevel make. Additionally
+you might want to:
+
+make test
+make install
+
+There is an example script in each of the directories. The example
+scrips work even when you don't intall the perl extensions.
+
+To learn:
+---------
+
+Read the documentation in the doc directory. Start of with
+rrdtool. All documents are available as html and as ascii text.  
+
+If you want to know about the format of the logfiles check
+src/rrd_format.h there are a lot of comments in there ...
+
+To Contribute:
+--------------
+
+Contributed feature and bug patches are most welcome. But please
+send complete patches. A complete patch patches the CODE as well
+as the CHANGES, CONTRIBUTORS and the POD files.
+
+If you want to keep in touch, make sure you subscribe to the
+mrtg-developers mailinglist by sending a message with the subject
+'subscribe' to mrtg-developers-request at list.ee.ethz.ch
+
+The latest Version:
+-------------------
+
+Is available from http://ee-staff.ethz.ch/~oetiker/webtools/rrdtool/
+
+
+Tobias Oetiker <oetiker at ee.ethz.ch>
+
+

Added: trunk/orca/packages/rrdtool-0.99.29.1/CONTRIBUTORS
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/CONTRIBUTORS	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/CONTRIBUTORS	Sat Jul 13 18:46:05 2002
@@ -0,0 +1,53 @@
+I would like to thank to following people for helping to
+bring mrtg 3.0 into existence.
+
+Planning and Inspiration
+
+	Daniel Wesemann
+	Krister Karlson
+	Simon Leinen
+
+Debugging and code contributions
+
+	Jeff R. Allen <jeff.allen at acm.org> (autoconfigure, portability)  
+	Philippe.Simonet <Philippe.Simonet at swisscom.com> (NT porting)
+	Wrolf Courtney <wrolf at concentric.net> (HP-UX)
+	Dan Dunn <dandunn at computer.org>
+	Russ Wright <wright at LBL.Gov>
+	Simon Leinen <simon at switch.ch>
+	Jost.Krieger <Jost.Krieger at ruhr-uni-bochum.de>
+	Blair Zajac <bzajac at geostaff.com>
+	Andrew Turner <turner at mint.net> (LAST and TOTAL consolidators)
+	Andreas Kroomaa <andre at ml.ee>
+        Oleg Cherevko <olwi at icyb.kiev.ua>
+	Otmar Lendl <O.Lendl at Austria.EU.net> (core dump fix)
+        Tom Crawley <Tom.Crawley at hi.riotinto.com.au> (GCC&HP configuration)
+        Jeremy Fischer <jeremy at pobox.com> (Makefile changes & RPM builds)
+        Alan Lichty <alan_lichty at eli.net>
+        Steen Linden <Steen.Linden at ebone.net>
+
+Documentation
+
+        Russ Wright <rwwright at home.com>
+        Wrolf Courtney <wrolf at concentric.net>      
+        Amos Shapira <amos at gezernet.co.il>
+        Kai Siering <kai.siering at mediaways.net>
+	Alex van den Bogaerdt <alex at ergens.op.het.net>
+	Alan Lichty <alan_lichty at eli.net>
+
+Further I would like to note, that rrdtool would not exist without
+the following free software products:
+
+	Perl by Larry Wall
+	gd library by Thomas Boutell
+	SNMP Perl-Module by Simon Leinen
+
+	and last but not least
+	
+	Linux by Linus Torvalds	
+
+I would also like to thank the Department of Electrical Engineering
+at the Swiss Federal Institute of Technology who allow me to
+use their network resources to publish rrdtool ...
+
+Tobias Oetiker <oetiker at ee.ethz.ch>

Added: trunk/orca/packages/rrdtool-0.99.29.1/config.h.in
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/config.h.in	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/config.h.in	Sat Jul 13 18:46:05 2002
@@ -0,0 +1,34 @@
+/* config.h.in.  Generated automatically from configure.in by autoheader.  */
+
+/* Define if you have the strftime function.  */
+#undef HAVE_STRFTIME
+
+/* Define if you have the ANSI C header files.  */
+#undef STDC_HEADERS
+
+/* Define if your <sys/time.h> declares struct tm.  */
+#undef TM_IN_SYS_TIME
+
+/* Define if you have the getrusage function.  */
+#undef HAVE_GETRUSAGE
+
+/* Define if you have the mktime function.  */
+#undef HAVE_MKTIME
+
+/* Define if you have the <math.h> header file.  */
+#undef HAVE_MATH_H
+
+/* Define if you have the <sys/resource.h> header file.  */
+#undef HAVE_SYS_RESOURCE_H
+
+/* Define if you have the <sys/time.h> header file.  */
+#undef HAVE_SYS_TIME_H
+
+/* Define if you have the <sys/times.h> header file.  */
+#undef HAVE_SYS_TIMES_H
+
+/* Define if you have the <unistd.h> header file.  */
+#undef HAVE_UNISTD_H
+
+/* Define if you have the m library (-lm).  */
+#undef HAVE_LIBM

Added: trunk/orca/packages/rrdtool-0.99.29.1/contrib/log2rrd/log2rrd.pl
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/contrib/log2rrd/log2rrd.pl	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/contrib/log2rrd/log2rrd.pl	Sat Jul 13 18:46:05 2002
@@ -0,0 +1,231 @@
+#! /usr/local/bin/perl 
+#
+# Log 2 RRD.  This script translates a MRTG 2.x log file
+# into a RRD archive.  The original version was written by
+# Wrolf Courtney <wrolf at concentric.net> and
+# Russ Wright <wright at LBL.Gov> with an early test version
+# of RRDTOOL (mrtg-19980526.08) and has been modified to match
+# the parameters of rrdtool version 99.23 by Alan Lichty at
+# Electric Lightwave, Inc. <alichty at eli.net>.
+#
+# this script optimized for being called up by another script
+# that cycles through a list of routers and invokes this for each
+# interface.  It can be run just as easily from a command line for
+# small numbers of logfiles.
+#
+# The RRD we create looks like the following:  Note
+# that we have to use type GAUGE in order to have RRDTOOL
+# populate the new rr archive correctly.  Otherwise RRDTOOL will try 
+# to interpet the data as new octet counts instead of existing
+# data rate averages.
+#
+# DS:GAUGE:86400:U:U	        # in counter
+# DS:GAUGE:86400:U:U	        # out counter
+# RRA:AVERAGE:0.5:1:600	        # 5 minute samples
+# RRA:MAX:0.5:1:600		# 5 minute samples
+# RRA:AVERAGE:0.5:6:600	        # 30 minute samples
+# RRA:MAX:0.5:6:600		# 30 minute samples
+# RRA:AVERAGE:0.5:24:600	        # 2 hour samples
+# RRA:MAX:0.5:24:600		# 2 hour samples
+# RRA:AVERAGE:0.5:288:732	# 1 day samples
+# RRA:MAX:0.5:288:732            # 1 day samples
+#
+# 
+
+use English;
+use strict;
+
+require "ctime.pl";
+
+use RRDs;
+
+my $DEBUG=0;
+
+&main;
+
+sub main {
+
+    my($inBytes, $outBytes);
+    my($lastRunDate, $firstRunDate);
+    my($i, $dataFile, $firstRun);
+    my($oldestRun, $lastRun);
+    my($curTime, $oldestTime, $totRec);
+    my($avgIn, $avgOut, $maxIn, $maxOut);
+    my(@lines, @finalRecs);
+    my($RRD, $START, $destDir, $dsType);
+
+#
+# get the logfile name to process
+# the default is to strip out the .log extension and create
+# a new file with the extension .rrd
+#
+
+    $dataFile=$ARGV[0];
+
+    $destDir = $ARGV[1];
+
+#
+# strip off .log from file name - complain and die if no .log
+# in the filename
+#
+
+    if ($dataFile =~ /(.*)\.log$/) {
+	$RRD = "$1";
+    }
+
+    if ($RRD eq "") {
+	printf("Usage: log2rrd [log file] [destination dir]\n");
+	exit;
+    }
+
+#
+# strip out path info (if present) to get at just the filename
+#
+
+    if ($RRD =~ /(.*)\/(.*)$/){
+	$RRD = "$2";
+    }
+
+#
+# add the destination path (if present) and .rrd suffix
+#
+
+    if ($destDir){
+	$RRD = "$destDir/$RRD.rrd";
+
+    }else{
+	$RRD = "$RRD.rrd";
+    }
+
+    open(IN,"$dataFile") || die ("Couldn't open $dataFile");
+
+#
+# Get first line - has most current sample
+#
+
+    $_ = <IN>;
+    chop;
+    ($lastRun, $inBytes, $outBytes) = split;
+    $lastRunDate = &ctime($lastRun);
+    chop $lastRunDate;
+
+    $firstRun = $lastRun;
+    $i=2;
+
+#
+# start w/line 2 and read them into the lines array
+# (2nd line is in position 2)
+#
+    while (<IN>) {
+	chop;
+	$lines[$i++] = $_;
+	($curTime) = split;
+	if ($curTime < $firstRun) {
+	    $firstRun = $curTime;
+	}
+    }
+    close(IN);
+
+#
+#  Let's say source start time is 5 minutes before 1st sample
+#
+
+    $START=$firstRun - 300;
+    print STDERR "\$START = $START\n" if $DEBUG>1;
+
+    $firstRunDate = &ctime($firstRun);
+    chop $firstRunDate;
+
+    printf("Data from $firstRunDate\n       to $lastRunDate\n") if $DEBUG>0;
+
+    $oldestTime=$lastRun;
+#
+# OK- sort through the data and put it in a new array.
+# This gives us a chance to find errors in the log files and
+# handles any overlap of data (there shouldn't be any)
+#
+# NOTE: We start w/ record # 3, not #2 since #2 could be partial
+#
+
+    for ($i=3; $i <= 2533; $i++) {
+
+	($curTime, $avgIn, $avgOut, $maxIn, $maxOut) = split(/\s+/, $lines[$i]);
+
+	if ($curTime < $oldestTime) {
+
+#
+# only add data if older than anything already in array
+# this should always be true, just checking
+#
+
+	    $oldestTime = $curTime;
+	    $finalRecs[$totRec++]=$lines[$i];
+	}
+    }
+
+
+    PopulateRRD($totRec, $RRD, $START, \@finalRecs);
+
+#
+# if you know that most of your MRTG logfiles are using
+# counter data, uncomment the following lines to automatically
+# run rrdtune and change the data type.
+#
+#    my(@tuneparams) = ("$RRD", "-d", "ds0:COUNTER", "-d", "ds1:COUNTER");
+#    RRDs::tune(@tuneparams);
+
+
+}
+
+sub PopulateRRD {
+
+    my($totRec, $RRD, $START, $finalRecs) = @_;
+    my($i, $curTime, $avgIn, $avgOut, $maxIn, $maxOut);
+    my($saveReal, $line);
+    my($createret, $updret);
+
+    print "* Creating RRD $RRD\n\n" if $DEBUG>0;
+
+#
+# We'll create RRAs for both AVG and MAX. MAX isn't currently filled but 
+# may be later
+#
+
+    RRDs::create ("$RRD", "-b", $START, "-s", 300,
+    "DS:ds0:GAUGE:86400:U:U",
+    "DS:ds1:GAUGE:86400:U:U",
+    "RRA:AVERAGE:0.5:1:600",
+    "RRA:MAX:0.5:1:600",
+    "RRA:AVERAGE:0.5:6:600",
+    "RRA:MAX:0.5:6:600",
+    "RRA:AVERAGE:0.5:24:600",
+    "RRA:MAX:0.5:24:600",
+    "RRA:AVERAGE:0.5:288:600",
+    "RRA:MAX:0.5:288:600");
+
+    if (my $error = RRDs::error()) {
+	print "Cannot create $RRD: $error\n";
+    }
+
+
+    print "* Adding entries to $RRD\n\n" if $DEBUG>0;
+
+    for ($i=$totRec - 1; $i >= 0; $i--) {
+
+	($curTime, $avgIn, $avgOut, $maxIn, $maxOut) = split(/\s+/, @$finalRecs[$i]);
+
+        RRDs::update ("$RRD", "$curTime:$avgIn:$avgOut");
+
+	if (my $error = RRDs::error()) {
+	    print "Cannot update $RRD: $error\n";
+	}
+
+  
+# NOTE: Need to add checking on RRDread and include the Max values
+# print status every now and then
+#	print $i if $i % 25 && $DEBUG>0;
+#	print "$i\n";
+
+    }
+
+}

Added: trunk/orca/packages/rrdtool-0.99.29.1/contrib/log2rrd/README
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/contrib/log2rrd/README	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/contrib/log2rrd/README	Sat Jul 13 18:46:05 2002
@@ -0,0 +1,62 @@
+			       log2rrd
+
+Usage:
+
+log2rrd.pl {mrtg logfile} {destination directory}
+
+Log2rrd is a simple tool for converting MRTG logfiles into round robin
+database (RRD) files.  The original version was written last year by
+Wrolf Courtney <wrolf at concentric.net> and Russ Wright <wright at LBL.Gov>
+with an early test version of RRDTOOL (mrtg-19980526.08).  This
+version has been modified to work with the current shared-perl release
+of RRD (RRDs).
+
+This script only moves the input/output data averages and does not
+make any effort to retain the maximum data rate info that is present
+in the mrtg logfiles.  This means that when you request maximum values
+for a given time range from your new rrd archive, it will only show
+you the averaged max values and not the original data peaks that
+occured in the averaged time period.  This may or may not be a problem
+at your site.
+
+The conversion script expects 2 arguments - the mrtg logfile to read
+and the path for the resulting rrd file.  The script will attempt to
+isolate the filename from any path specified for the mrtg input
+logfile to create the rrd output file name with the specified
+destination directory.  If no destination directory name is included,
+the rrd file will be written in the connected directory. 
+
+Note that the resulting rrd DS type is GAUGE.  With a DS type of
+counter, rrdupdate will attempt to interpret input data as a counter
+value and make a new data average for the specified time interval.
+In this case, we need to trick rrdcreate/rrdupdate into letting us
+input the data values directly because mrtg had already consolidated
+the counter data.  The script contains lines of code that can be
+uncommented to allow log2rrd to automatically call rrdtune to change
+the resulting file to use the COUNTER data type after the mrtg
+logfiles have been read in.  Since not all mrtg data files are counter
+data, I leave this option up to the user as to whether to convert
+later by hand with rrdtune or let log2rrd perform the task.
+
+Considerations for filenames and converting large numbers of files:
+
+At my own site, I have over 40 Cisco 75xx routers with lots of
+interfaces being monitored per router plus about 60 Cisco 5300
+terminal servers.  Running log2rrd for each interface individually
+would be a very painful process.  Since I am in the process of moving
+all of my mrtg datasets over to Cricket, I hacked a separate version
+of log2rrd that had more specific file name conversion code to match
+my Cricket target names.  This version of log2rrd was called up by
+another script that looped through an entire mrtg workdir and
+converted all logfiles present in that directory.  This code was far
+too specific to my site's version of mrtg logfile names and desired
+Cricket target info to be included here.  It would not be a difficult
+task to wrap this log2rrd script in a similar fashion tailored to your
+own needs.  If you have 100's or 1000's of logfiles to move, the
+effort is well worthwhile.
+
+Alan Lichty
+Internetworking Planner
+Electric Lightwave, Inc.
+(360)816-4167
+

Added: trunk/orca/packages/rrdtool-0.99.29.1/contrib/README
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/contrib/README	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/contrib/README	Sat Jul 13 18:46:05 2002
@@ -0,0 +1,7 @@
+This directory should contain YOUR scripts ... please sent them to me ...
+
+each script should come with an apropriate README file ...
+
+
+cheees
+tobi

Added: trunk/orca/packages/rrdtool-0.99.29.1/contrib/trytime/Makefile
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/contrib/trytime/Makefile	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/contrib/trytime/Makefile	Sat Jul 13 18:46:05 2002
@@ -0,0 +1,43 @@
+# Generated automatically from Makefile.in by configure.
+# things that the GNU standards document suggests all makefiles
+# should have.
+SHELL = /bin/sh
+.SUFFIXES:
+.SUFFIXES: .c .o .pl .pm .pod .html .man
+
+# variables we got from configure
+# (you can mess with these, if you want)
+
+CC = gcc
+AR = ar
+CFLAGS_EXTRA =  -Wall -pedantic -fpic
+CFLAGS = -g -O2
+CFLAGS_ALL = $(CFLAGS) $(CFLAGS_EXTRA) -I.. -I../../src -DHAVE_CONFIG_H \
+             -DWANT_AT_STYLE_TIMESPEC
+LDFLAGS = 
+LIBS = -L../../src -lrrd
+LIBS_DEPEND = ../../src/librrd.a
+
+###
+### Things you might NOT want to play with ... 
+###
+
+HEADERS = ../../src/getopt.h ../../src/parsetime.h
+
+SRC = trytime.c
+
+OBJ = $(SRC:.c=.o)
+
+all: trytime
+
+trytime: $(OBJ) $(LIBS_DEPEND)
+	$(CC) -o trytime $(OBJ) $(LDFLAGS) $(LIBS)
+
+clean:  
+	-rm *.o
+
+realclean: clean
+	-rm trytime
+
+.c.o:	$(HEADERS)
+	$(CC) $(CFLAGS_ALL) -c $<

Added: trunk/orca/packages/rrdtool-0.99.29.1/contrib/trytime/README
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/contrib/trytime/README	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/contrib/trytime/README	Sat Jul 13 18:46:05 2002
@@ -0,0 +1,85 @@
+"trytime" is a small program that allows you to play with at-style
+time specifications without actually bothering any of the rrd databases.
+It takes either single at-style specification or two of those
+(for start and end time, just like rrdtool fetch or graph do) and
+reports what it thinks of it. The diagnostic is as close as possible
+to that of rrdtool compiled for at-style time specification support.
+
+To learn what's possible with at-style time specifications, see
+the AT-STYLE TIME SPECIFICATION section in the rrdfetch documentation.
+
+The formal syntax parsed is (this is taken right from the parsetime.c):
+
+/*
+ * The BNF-like specification of the time syntax parsed is below:
+ *                                                               
+ * As usual, [ X ] means that X is optional, { X } means that X may
+ * be either omitted or specified as many times as needed,
+ * alternatives are separated by |, brackets are used for grouping.
+ * (# marks the beginning of comment that extends to the end of line)
+ *
+ * TIME-SPECIFICATION ::= TIME-REFERENCE [ OFFSET-SPEC ] |
+ *			                   OFFSET-SPEC   |
+ *			   ( START | END ) OFFSET-SPEC 
+ *
+ * TIME-REFERENCE ::= NOW | TIME-OF-DAY-SPEC [ DAY-SPEC-1 ] |
+ *                        [ TIME-OF-DAY-SPEC ] DAY-SPEC-2
+ *
+ * TIME-OF-DAY-SPEC ::= NUMBER [(':'|'.') NUMBER] [am|pm] | # HH:MM HH.MM HH[MM]
+ *                     'noon' | 'midnight' | 'teatime'
+ *
+ * DAY-SPEC-1 ::= NUMBER '/' NUMBER '/' NUMBER |  # MM/DD/[YY]YY
+ *                NUMBER '.' NUMBER '.' NUMBER |  # DD.MM.[YY]YY
+ *                NUMBER                          # DDMM[YY]YY
+ *
+ * DAY-SPEC-2 ::= MONTH-NAME NUMBER [NUMBER] |    # Month DD [YY]YY
+ *                'yesterday' | 'today' | 'tomorrow' |
+ *                DAY-OF-WEEK
+ *
+ *
+ * OFFSET-SPEC ::= '+'|'-' NUMBER TIME-UNIT { ['+'|'-'] NUMBER TIME-UNIT }
+ *
+ * TIME-UNIT ::= SECONDS | MINUTES | HOURS |
+ *               DAYS | WEEKS | MONTHS | YEARS
+ *
+ * NOW ::= 'now' | 'n'
+ *
+ * START ::= 'start' | 's'
+ * END   ::= 'end' | 'e'
+ *
+ * SECONDS ::= 'seconds' | 'second' | 'sec' | 's'
+ * MINUTES ::= 'minutes' | 'minute' | 'min' | 'm'
+ * HOURS   ::= 'hours' | 'hour' | 'hr' | 'h'
+ * DAYS    ::= 'days' | 'day' | 'd'
+ * WEEKS   ::= 'weeks' | 'week' | 'wk' | 'w'
+ * MONTHS  ::= 'months' | 'month' | 'mon' | 'm'
+ * YEARS   ::= 'years' | 'year' | 'yr' | 'y'
+ *
+ * MONTH-NAME ::= 'jan' | 'january' | 'feb' | 'february' | 'mar' | 'march' |
+ *                'apr' | 'april' | 'may' | 'jun' | 'june' | 'jul' | 'july' |
+ *                'aug' | 'august' | 'sep' | 'september' | 'oct' | 'october' |
+ *		  'nov' | 'november' | 'dec' | 'december'
+ *
+ * DAY-OF-WEEK ::= 'sunday' | 'sun' | 'monday' | 'mon' | 'tuesday' | 'tue' |
+ *                 'wednesday' | 'wed' | 'thursday' | 'thu' | 'friday' | 'fri' |
+ *                 'saturday' | 'sat'
+ *
+ *
+ * As you may note, there is an ambiguity with respect to
+ * the 'm' time unit (which can mean either minutes or months).
+ * To cope with this, code tries to read users mind :) by applying
+ * certain heuristics. There are two of them:
+ *
+ * 1. If 'm' is used in context of (i.e. right after the) years,
+ *    months, weeks, or days it is assumed to mean months, while
+ *    in the context of hours, minutes, and seconds it means minutes.
+ *    (e.g., in -1y6m or +3w1m 'm' means 'months', while in
+ *    -3h20m or +5s2m 'm' means 'minutes')
+ *
+ * 2. Out of context (i.e. right after the '+' or '-' sign) the
+ *    meaning of 'm' is guessed from the number it directly follows.
+ *    Currently, if the number absolute value is below 25 it is assumed
+ *    that 'm' means months, otherwise it is treated as minutes.
+ *    (e.g., -25m == -25 minutes, while +24m == +24 months)
+ *
+ */

Added: trunk/orca/packages/rrdtool-0.99.29.1/contrib/trytime/trytime.c
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/contrib/trytime/trytime.c	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/contrib/trytime/trytime.c	Sat Jul 13 18:46:05 2002
@@ -0,0 +1,258 @@
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "getopt.h"
+#include "parsetime.h"
+
+#ifndef	WANT_AT_STYLE_TIMESPEC
+#define	WANT_AT_STYLE_TIMESPEC
+#endif
+
+#define BUF_LEN 128
+
+static char soption[BUF_LEN];
+static char eoption[BUF_LEN];
+
+int main ( int ac, char **av )
+{
+  static struct option long_options[] =
+  {
+     {"start",      required_argument, 0, 's'},
+     {"end",        required_argument, 0, 'e'},
+     {0,0,0,0}};
+  int option_index = 0;
+  int opt;
+
+  time_t start_tmp, end_tmp, Now = time(NULL);
+  char *ct;
+
+#ifdef WANT_AT_STYLE_TIMESPEC
+    struct time_value start_tv, end_tv;
+    char *parsetime_error = NULL;
+    int start_tmp_is_ok = 0,
+	end_tmp_is_ok = 0;
+#endif
+
+    /* default values */
+    end_tmp = time(NULL);
+    start_tmp = -24*3600;
+#ifdef WANT_AT_STYLE_TIMESPEC
+    end_tv.type = ABSOLUTE_TIME;
+    end_tv.tm = *localtime(&end_tmp);
+    end_tv.offset = 0;
+
+    start_tv.type = RELATIVE_TO_END_TIME;
+    start_tv.tm = *localtime(&end_tmp); /* to init tm_zone and tm_gmtoff */
+    start_tv.offset = -24*3600;/* to be compatible with the original code.  */
+    start_tv.tm.tm_sec = 0;    /** alternatively we could set tm_mday to -1 */
+    start_tv.tm.tm_min = 0;    /** but this would yield -23(25) hours offset */
+    start_tv.tm.tm_hour = 0;   /** twice a year, when DST is coming in or   */
+    start_tv.tm.tm_mday = 0;   /** out of effect                            */
+    start_tv.tm.tm_mon = 0;
+    start_tv.tm.tm_year = 0;
+    start_tv.tm.tm_wday = 0;
+    start_tv.tm.tm_yday = 0;
+    start_tv.tm.tm_isdst = -1; /* for mktime to guess */
+#endif
+    *soption = '\0';
+    *eoption = '\0';
+
+  if( ac < 2 )
+    {
+    printf( "usage: %s time-specification-to-try\n"
+	    "or     %s [--start|-s start] [--end|-e end]\n"
+	    "\n"
+	    "In plain English, this means that to time specification try\n"
+	    "a single time specification (just like in the rrdtool create)\n"
+	    "you can use the first form, while to try two of them at once\n"
+	    "(just like in rrdtool graph or fetch) you need the seconf form\n",
+	    av[0], av[0] );
+    exit(0);
+    }
+
+  printf( "The time now is: %s\n", ctime(&Now) );
+
+  if( av[1][0] != '-' )
+    {
+    if( ac > 2 )
+      {
+      printf( "Warning: you specified several arguments,\n"
+	      "         of those I will use only one: '%s'\n"
+	      "(hint: perhaps, you should put quotes around your timespec?)\n",
+	      av[1] );
+      }
+#ifdef WANT_AT_STYLE_TIMESPEC
+    {
+    char *endp;
+    start_tmp_is_ok = 0;
+    start_tmp = strtol(av[1], &endp, 0);
+    if (*endp == '\0') /* it was a valid number */
+        if (start_tmp > 31122038 || /* 31 Dec 2038 in DDMMYYYY */
+            start_tmp < 0) {
+            start_tmp_is_ok = 1;
+            goto CheckRelative;
+        }
+    if ((parsetime_error = parsetime(av[1], &start_tv))) {
+        fprintf( stderr, "ERROR: %s\n", parsetime_error );
+        return(-1);
+    }
+    if (start_tv.type == RELATIVE_TO_END_TIME ||
+        start_tv.type == RELATIVE_TO_START_TIME) {
+        fprintf( stderr, "ERROR: specifying time relative to the 'start' "
+                      "or 'end' makes no sense here\n");
+        return(-1);
+    }
+    if (!start_tmp_is_ok)
+        start_tmp = mktime(&start_tv.tm) + start_tv.offset;
+    }/* this is for the entire block */
+
+#else
+    start_tmp = atol(av[1]);
+#endif
+CheckRelative:
+    if (start_tmp < 0) /* if time is negative this means go back from now. */
+      start_tmp = time(NULL)+start_tmp;
+
+    {
+    ct = ctime(&start_tmp);
+    ct[24] = '\0'; /* zap that nasty embedded'\n' */
+    printf( "You specified the following: '%s',\n"
+	     "for me this means: %s (or %ld sec since epoch)\n\n", 
+              av[1], ct, start_tmp );
+
+    }
+    exit(0);
+    }/* if( av[1][0]... */
+
+  while(1)
+    {
+    opt = getopt_long(ac, av, "s:e:", long_options, &option_index);
+
+    if (opt == EOF)  
+       break;
+    
+    switch(opt)
+      {
+      case 's': 
+	 strncpy( soption, optarg, BUF_LEN );
+#ifdef WANT_AT_STYLE_TIMESPEC
+	    {
+	    char *endp;
+	    start_tmp_is_ok = 0;
+	    start_tmp = strtol(optarg, &endp, 0);
+	    if (*endp == '\0') /* it was a valid number */
+	        if (start_tmp > 31122038 || /* 31 Dec 2038 in DDMMYYYY */
+		    start_tmp < 0) {
+		    start_tmp_is_ok = 1;
+		    break;
+		}
+	    if ((parsetime_error = parsetime(optarg, &start_tv))) {
+	        fprintf( stderr, "ERROR: start time: %s\n", parsetime_error );
+		return -1;
+	     }
+	    }
+#else
+	    start_tmp = atol(optarg);
+#endif
+	    break;
+      case 'e': 
+	 strncpy( eoption, optarg, BUF_LEN );
+#ifdef WANT_AT_STYLE_TIMESPEC
+	    {
+	    char *endp;
+	    end_tmp_is_ok = 0;
+	    end_tmp = strtol(optarg, &endp, 0);
+	    if (*endp == '\0') /* it was a valid number */
+	        if (end_tmp > 31122038) { /* 31 Dec 2038 in DDMMYYYY */
+		    end_tmp_is_ok = 1;
+		    break;
+		}
+	    if ((parsetime_error = parsetime(optarg, &end_tv))) {
+	        fprintf( stderr, "ERROR: end time: %s\n", parsetime_error );
+		return -1;
+	     }
+	    }
+#else
+ 	    end_tmp = atol(optarg);
+#endif
+ 	    break;
+      }
+    }
+
+#ifdef WANT_AT_STYLE_TIMESPEC
+    if ((start_tv.type == RELATIVE_TO_END_TIME ||
+	   (start_tmp_is_ok && start_tmp < 0)) && /* same as the line above */
+           end_tv.type == RELATIVE_TO_START_TIME) {
+	fprintf( stderr, "the start and end times cannot be specified "
+		      "relative to each other\n");
+	return(-1);
+    }
+
+    if (start_tv.type == RELATIVE_TO_START_TIME) {
+	fprintf( stderr, "the start time cannot be specified relative to itself\n");
+	return(-1);
+    }
+
+    if (end_tv.type == RELATIVE_TO_END_TIME) {
+	fprintf( stderr, "the end time cannot be specified relative to itself\n");
+	return(-1);
+    }
+
+    /* We don't care to keep all the values in their range,
+       mktime will do this for us */
+    if (start_tv.type == RELATIVE_TO_END_TIME) {
+	if (end_tmp_is_ok)
+	    end_tv.tm = *localtime( &end_tmp );
+	start_tv.tm.tm_sec  += end_tv.tm.tm_sec; 
+	start_tv.tm.tm_min  += end_tv.tm.tm_min; 
+	start_tv.tm.tm_hour += end_tv.tm.tm_hour; 
+	start_tv.tm.tm_mday += end_tv.tm.tm_mday; 
+	start_tv.tm.tm_mon  += end_tv.tm.tm_mon; 
+	start_tv.tm.tm_year += end_tv.tm.tm_year; 
+    }
+    if (end_tv.type == RELATIVE_TO_START_TIME) {
+	if (start_tmp_is_ok)
+	    start_tv.tm = *localtime( &start_tmp );
+	end_tv.tm.tm_sec  += start_tv.tm.tm_sec; 
+	end_tv.tm.tm_min  += start_tv.tm.tm_min; 
+	end_tv.tm.tm_hour += start_tv.tm.tm_hour; 
+	end_tv.tm.tm_mday += start_tv.tm.tm_mday; 
+	end_tv.tm.tm_mon  += start_tv.tm.tm_mon; 
+	end_tv.tm.tm_year += start_tv.tm.tm_year; 
+    }
+    if (!start_tmp_is_ok)
+        start_tmp = mktime(&start_tv.tm) + start_tv.offset;
+    if (!end_tmp_is_ok)
+        end_tmp = mktime(&end_tv.tm) + end_tv.offset;
+#endif
+
+    if (start_tmp < 0) 
+ 	start_tmp = end_tmp + start_tmp;
+     
+    ct = ctime(&start_tmp);
+    ct[24] = '\0'; /* zap that nasty embedded'\n' */
+    if( *soption )
+      printf( "Start time was specified as: '%s',\n"
+	      "for me this means: %s (or %ld sec since epoch)\n\n", 
+              soption, ct, start_tmp );
+    else
+      printf( "Start time was not specified, default value will be used (-86400)\n"
+	      "for me this means: %s (or %ld sec since epoch)\n\n",
+	      ct, start_tmp );
+    
+    ct = ctime(&end_tmp);
+    ct[24] = '\0';
+    if( *eoption )
+      printf( "End time was specified as: '%s',\n"
+	      "for me this means: %s (or %ld sec since epoch)\n", 
+              eoption, ct, end_tmp );
+    else
+      printf( "End time was not specified, default value will be used (now)\n"
+	      "for me this means: %s (or %ld sec since epoch)\n\n",
+	      ct, start_tmp );
+
+  exit(0);
+}
+
+

Added: trunk/orca/packages/rrdtool-0.99.29.1/perl-piped/RRDp.pm
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/perl-piped/RRDp.pm	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/perl-piped/RRDp.pm	Sat Jul 13 18:46:06 2002
@@ -0,0 +1,188 @@
+package RRDp;
+
+=head1 NAME
+
+RRDp - Attach rrdtool from within a perl script via a set of pipes;
+
+=head1 SYNOPSIS
+
+use B<RRDp>
+
+B<RRDp::start> I<path to rrdtool executable>
+
+B<RRDp::cmd>  I<rrdtool commandline>
+
+$answer = B<RRD::read>
+
+$status = B<RRD::end>
+
+B<$RRDp::user>,  B<$RRDp::sys>, B<$RRDp::real>
+
+=head1 DESCRIPTION
+
+With this module you can safely communicate with the rrdtool. 
+
+After every B<RRDp::cmd> you have to issue an B<RRDp::read> command to get
+B<rrdtool>s answer to your command. The answer is returned as a pointer,
+in order to speed things up. If the last command did not return any
+data, B<RRDp::read> will return an undefined variable. 
+
+If you import the PERFORMANCE variables into your namespace, 
+you can access rrdtools internal performance measurements.
+
+=over 8
+
+=item  use B<RRDp>
+
+Load the RRDp::pipe module.
+
+=item B<RRDp::start> I<path to rrdtool executable>
+
+start rrdtool. The argument must be the path to the rrdtool executable
+
+=item B<RRDp::cmd> I<rrdtool commandline>
+
+pass commands on to rrdtool. check the rrdtool documentation for
+more info on the rrdtool commands.
+
+=item $answer = B<RRDp::read>
+
+read rrdtools response to your command. Note that the $answer variable will
+only contain a pointer to the returned data. The reason for this is, that
+rrdtool can potentially return quite excessive amounts of data
+and we don't want to copy this around in memory. So when you want to 
+access the contents of $answer you have to use $$answer which dereferences
+the variable.
+
+=item $status = B<RRDp::end>
+
+terminates rrdtool and returns rrdtools status ... 
+
+=item B<$RRDp::user>,  B<$RRDp::sys>, B<$RRDp::real>
+
+these variables will contain totals of the user time, system time and
+real time as seen by rrdtool.  User time is the time rrdtool is
+running, System time is the time spend in system calls and real time
+is the total time rrdtool has been running.
+
+The difference between user + system and real is the time spent
+waiting for things like the hard disk and new input from the perl
+script.
+
+=back
+
+
+=head1 EXAMPLE
+
+ use RRDp;
+ RRDp::start "/usr/local/bin/rrdtool";
+ RRDp::cmd   qw(create demo.rrd --step 100 
+               DS:in:GAUGE:100:U:U
+	       RRA:AVERAGE:0.5:1:10);
+ $answer = RRDp::read;
+ print $$answer;
+ ($usertime,$systemtime,$realtime) =  ($RRDp::user,$RRDp::sys,$RRDp::real);
+
+=head1 SEE ALSO
+
+For more information on how to use rrdtool, check the manpages.
+
+=head1 AUTHOR
+
+Tobias Oetiker <oetiker at ee.ethz.ch>
+
+=cut
+#'  this is to make cperl.el happy
+
+use strict;
+use Fcntl;
+use Carp;
+use IO::Handle;
+use IPC::Open2;
+use vars qw($Sequence $RRDpid $VERSION);
+my $Sequence;
+my $RRDpid;
+
+# Prototypes
+
+sub start ($);
+sub cmd (@);
+sub end ();
+sub read ();
+
+$VERSION = 0.99029                                 ;
+
+sub start ($){
+  croak "rrdtool is already running"
+    if defined $Sequence;
+  $Sequence = 'S';    
+  my $rrdtool = shift @_;    
+  $RRDpid = open2 \*RRDreadHand,\*RRDwriteHand, $rrdtool,"-" 
+    or croak "Can't Start rrdtool: $!";
+  RRDwriteHand->autoflush(); #flush after every write    
+  fcntl RRDreadHand, F_SETFL,O_NONBLOCK|O_NDELAY; #make readhandle NON BLOCKING
+  return $RRDpid;
+}
+
+
+sub read () {
+  croak "RRDp::read can only be called after RRDp::cmd" 
+    unless $Sequence eq 'C';
+  $Sequence = 'R';
+  my $inmask = 0;
+  my $srbuf;
+  my $minibuf;
+  my $buffer;
+  my $nfound;
+  my $timeleft;
+  my $ERR = 0;
+  vec($inmask,fileno(RRDreadHand),1) = 1; # setup select mask for Reader
+  while (1) {
+    my $rout;    
+    $nfound = select($rout=$inmask,undef,undef,2);
+    if ($nfound == 0 ) {
+      # here, we could do something sensible ...
+      next;
+    }
+    sysread(RRDreadHand,$srbuf,4096);
+    $minibuf .= $srbuf;
+    while ($minibuf =~ s|^(.+?)\n||s) {
+      my $line = $1;
+      # print $line,"\n";
+      if ($line =~  m|^ERROR|) {
+	croak $line;
+	$ERR = 1;
+      } 
+      elsif ($line =~ m|^OK u:([\d\.]+) s:([\d\.]+) r:([\d\.]+)|){
+	($RRDp::sys,$RRDp::user,$RRDp::real)=($1,$2,$3);
+	return $ERR == 1 ? undef : \$buffer;
+      } else {
+	$buffer .= $line. "\n";
+      }
+    }
+  }
+}
+
+sub cmd (@){
+  croak "RRDp::cmd can only be called after RRDp::read or RRDp::start"
+    unless $Sequence eq 'R' or $Sequence eq 'S';
+  $Sequence = 'C';
+  my $cmd = join " ", @_;
+  if ($Sequence ne 'S') {
+  }
+  $cmd =~ s/\n/ /gs;
+  $cmd =~ s/\s/ /gs;
+  print RRDwriteHand "$cmd\n";
+}
+
+sub end (){
+  croak "RRDp::end can only be called after RRDp::start"
+    unless $Sequence;
+  close RRDwriteHand;
+  close RRDreadHand;
+  $Sequence = undef;
+  waitpid $RRDpid,0;
+  return $?
+}
+
+1;

Added: trunk/orca/packages/rrdtool-0.99.29.1/perl-piped/t/base.t
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/perl-piped/t/base.t	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/perl-piped/t/base.t	Sat Jul 13 18:46:06 2002
@@ -0,0 +1,42 @@
+#! /usr/bin/perl 
+
+# this exercises just the perl module .. not rrdtool as such ... 
+
+BEGIN { $| = 1; print "1..5\n"; }
+END {
+  print "not ok 1\n" unless $loaded;
+  unlink "demo.rrd";
+}
+
+sub ok
+{
+    $ok_count++;
+    my($what, $result) = @_ ;
+    print "not " unless $result;
+    print "ok $ok_count $what\n";
+}
+
+use RRDp;
+
+$loaded = 1;
+$ok_count = 1;
+
+print "ok 1 module load\n";
+
+ok("RRDp::start", RRDp::start "../src/rrdtool" > 0);
+
+$now=time();
+RRDp::cmd qw(create demo.rrd --start ), $now, qw(--step 100 ),
+  qw( DS:in:GAUGE:100:U:U RRA:AVERAGE:0.5:1:10 );
+
+$answer = RRDp::read;
+ok("RRDp::cmd",  -s "demo.rrd" );
+
+RRDp::cmd qw(last demo.rrd);
+$answer = RRDp::read;
+
+ok("RRDp::read", $$answer =~ /$now/);
+
+$status = RRDp::end;
+
+ok("RRDp::end", $status == 0);

Added: trunk/orca/packages/rrdtool-0.99.29.1/perl-piped/MANIFEST
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/perl-piped/MANIFEST	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/perl-piped/MANIFEST	Sat Jul 13 18:46:06 2002
@@ -0,0 +1,6 @@
+MANIFEST
+README
+Makefile.PL
+RRDp.pm
+t/base.t
+examples/piped-demo.pl

Added: trunk/orca/packages/rrdtool-0.99.29.1/perl-piped/Makefile.PL
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/perl-piped/Makefile.PL	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/perl-piped/Makefile.PL	Sat Jul 13 18:46:06 2002
@@ -0,0 +1,10 @@
+use ExtUtils::MakeMaker;
+
+# See lib/ExtUtils/MakeMaker.pm for details of how to influence
+# the contents of the Makefile that is written.
+WriteMakefile(
+    'NAME'         => 'RRDp',
+    'VERSION'      => '0.99.0', # finds $VERSION
+    'linkext'   => {LINKTYPE => ''},
+    'dist'    =>    {COMPRESS=>'gzip', SUFFIX=>'gz'},
+);

Added: trunk/orca/packages/rrdtool-0.99.29.1/perl-piped/README
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/perl-piped/README	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/perl-piped/README	Sat Jul 13 18:46:06 2002
@@ -0,0 +1,5 @@
+This is a Perl module for using rrdtool process via a set of pipes.
+
+perl Makefile.PL
+make test
+make install

Added: trunk/orca/packages/rrdtool-0.99.29.1/perl-piped/examples/piped-demo.pl.in
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/perl-piped/examples/piped-demo.pl.in	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/perl-piped/examples/piped-demo.pl.in	Sat Jul 13 18:46:06 2002
@@ -0,0 +1,177 @@
+#! @PERL@ 
+
+=head1 NAME
+
+rrd_demo.pl - exercise rrdtool
+
+=head1 SYNOPSIS
+ 
+rrd_demo.pl
+
+=head1 DESCRIPTION
+
+The purpose of this script is to exercise rrdtool.
+First it will create an rrd file and fill it with data. 
+Then it will use the graphing function to generate some gifs ...
+
+=head1 AUTHOR 
+
+Tobias Oetiker <oetiker at ee.ethz.ch>
+
+=cut
+
+BEGIN { unshift @INC, "../blib/lib"; }
+
+use RRDp;
+
+
+$main::DEBUG=0;
+$STEP1 = 200;
+$STEP2 = 300;
+$RUNS1 = 3000;
+$RUNS2 = 3000;
+$GRUNS = 20;
+$RRD1 = "demo1.rrd";
+$RRD2 = "demo2.rrd";
+$GIF = "demo.gif";
+
+
+RRDp::start "../../src/rrdtool";
+
+print "* Creating First RRD $RRD1\n\n";
+
+$START1 = time()-$RUNS1*$STEP1;
+
+RRDp::cmd "create $RRD1 -b $START1 -s $STEP1 
+	DS:in:GAUGE:400:U:U
+	DS:out:GAUGE:400:U:U
+	RRA:AVERAGE:0.5:1:5000
+	RRA:AVERAGE:0.5:8:5000";
+
+$answer = RRDp::read;
+
+print "* Creating Second RRD $RRD2\n\n";
+
+$START2 = time()-$RUNS2*$STEP2;
+
+RRDp::cmd "create $RRD2 -b $START2 -s $STEP2 
+	DS:in:GAUGE:400:U:U
+	DS:out:GAUGE:400:U:U
+	RRA:AVERAGE:0.5:1:4000
+	RRA:AVERAGE:0.5:8:5000";
+
+$answer = RRDp::read;
+($user,$sys,$real) =  ($RRDp::user,$RRDp::sys,$RRDp::real);
+    
+print "* Filling both RRDs with ".(($RUNS1+$RUNS2)*2)." Values. One moment please ...\n";
+print "  If you are running over NFS this will take *MUCH* longer\n\n"; 
+
+for ($i=$START1+1;
+     $i<$START1+$STEP1*$RUNS1;
+     $i+=$STEP1+int((rand()-0.5)*7)){
+
+  $line = "update $RRD1 $i:".
+	(2000*cos($i/1550)).":".
+	  (3220*sin($i/3420));
+  
+  RRDp::cmd $line;
+  $answer = RRDp::read;
+}
+
+for ($i=$START2+1;
+     $i<$START2+$STEP2*$RUNS2;
+     $i+=$STEP2+int((rand()-0.5)*7)){
+
+  $line = "update $RRD2 $i:".
+    (1000+500*sin($i/1000)).":".
+      (1000+900*sin($i/2330));
+
+  RRDp::cmd $line;
+
+  $answer = RRDp::read;
+}
+($user1,$sys1,$real1) =  ($RRDp::user,$RRDp::sys,$RRDp::real);
+
+printf "-- Average Time for one Update (2 RRD 2 DS 2 RRA)\n".
+       "   usr: %1.4fs sys: %1.4fs real: %1.4fs logs/s: %1.4f\n",
+  ($user1-$user)/($RUNS1+$RUNS2), ($sys1-$sys)/($RUNS1+$RUNS2), 
+  ($real1-$real)/($RUNS1+$RUNS2), ($RUNS1+$RUNS2)/($real1-$real);
+print "\n";
+# creating some graphs
+
+print "* Creating $GRUNS graphs: $GIF\n\n";
+$now = time;
+for ($i=0;$i<$GRUNS;$i++) {
+RRDp::cmd "graph $GIF ", "--title 'Test GRAPH' ",
+	"--height 100 --vertical-label 'Dummy Units' --start ".(-$RUNS1*$STEP1/10),
+	"--color ARROW#bfbfbf",
+        "DEF:alpha=$RRD1:in:AVERAGE",
+        "DEF:beta=$RRD1:out:AVERAGE",
+        "DEF:gamma=$RRD2:in:AVERAGE",
+        "DEF:delta=$RRD2:out:AVERAGE",
+        "CDEF:calc=alpha,beta,+,1.5,/",
+        "AREA:alpha#0022e9:Alpha",
+        "STACK:beta#00b871:'Beta Text\\j'",
+        "LINE1:gamma#ff0000:'Gamma 1'",
+        "LINE2:delta#888800:'Delta 2\\c'",
+        "LINE3:calc#00ff44:'calc 3'",
+        "HRULE:2300#ff8800:'Horizontal Line at 2300'",
+	"PRINT:alpha:AVERAGE:'Average Alpha\\: %1.2f'",
+	"PRINT:alpha:MIN:'Min Alpha\\: %1.2f'",
+	"PRINT:alpha:MAX:'Max Alpha\\: %1.2f'",
+	"GPRINT:calc:AVERAGE:'Average calc\\: %1.2f\\r'",
+	"GPRINT:calc:MAX:'Max calc\\: %1.2f'",
+	"GPRINT:calc:MIN:'Min calc\\: %1.2f'",
+        "VRULE:".($now-3600)."#008877:'60 Minutes ago'",
+        "VRULE:".($now-4600)."#ff8877:",
+        "VRULE:".($now-7200)."#ffff00",
+        "COMMENT:'\\s'",
+        "COMMENT:'a last one centered with some more space aboce\\c'";
+
+$answer = RRDp::read;
+}
+($user2,$sys2,$real2) =  ($RRDp::user,$RRDp::sys,$RRDp::real);
+
+print "ANSWER:\n$$answer";
+
+printf "\n-- average Time for one Graph (5 graph, 8 print)\n".
+       "   usr: %1.4fs sys: %1.4fs real: %1.4fs   graphs/sec: %1.4f\n",
+  ($user2-$user1)/$GRUNS, 
+  ($sys2-$sys1)/$GRUNS, 
+  ($real2-$real1)/$GRUNS, 
+  $GRUNS/($real2-$real1);
+
+RRDp::cmd  "graph log$GIF ", "--title 'Log Test GRAPH' ",
+	"--logarithmic --lower-limit 10 --height 200 --vertical-label 'Dummy Units' --start ".(-$RUNS1*$STEP1/10),
+        "DEF:alpha=$RRD1:in:AVERAGE",
+        "DEF:beta=$RRD1:out:AVERAGE",
+        "DEF:gamma=$RRD2:in:AVERAGE",
+        "DEF:delta=$RRD2:out:AVERAGE",
+        "CDEF:calc=alpha,beta,+,1.5,/",
+        "AREA:alpha#0022e9:Alpha",
+        "STACK:beta#00b871:'Beta Text'",
+        "LINE1:gamma#ff0000:'Gamma 1'",
+        "LINE2:delta#888800:'Delta 2'",
+        "LINE3:calc#00ff44:'calc 3'",
+	"GPRINT:calc:AVERAGE:'Average calc\\: %1.2f'",
+	"GPRINT:calc:MAX:'Max calc\\: %1.2f'",
+	"GPRINT:calc:MIN:'Min calc\\: %1.2f'";
+
+$answer = RRDp::read;
+
+print "\n* Created log$GIF to demonstrate logarithmic scaling\n\n";
+
+RRDp::end;
+
+
+
+
+
+
+
+
+
+
+
+
+

Added: trunk/orca/packages/rrdtool-0.99.29.1/TODO
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/TODO	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/TODO	Sat Jul 13 18:46:06 2002
@@ -0,0 +1,9 @@
+let the user define the base resolution of the
+graph independantly of the pixle resolution. If it is smaller than one
+pixle it will simply be ignored
+
+do not fail if the same DEF gets stacked twice 
+im->gdes[ii].p_data = im->gdes[vidx].p_data;
+is a bad idea ... 
+
+get 1.0 out ...

Added: trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdtool.1
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdtool.1	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdtool.1	Sat Jul 13 18:46:06 2002
@@ -0,0 +1,366 @@
+.rn '' }`
+''' $RCSfile$$Revision$$Date$
+'''
+''' $Log$
+'''
+.de Sh
+.br
+.if t .Sp
+.ne 5
+.PP
+\fB\\$1\fR
+.PP
+..
+.de Sp
+.if t .sp .5v
+.if n .sp
+..
+.de Ip
+.br
+.ie \\n(.$>=3 .ne \\$3
+.el .ne 3
+.IP "\\$1" \\$2
+..
+.de Vb
+.ft CW
+.nf
+.ne \\$1
+..
+.de Ve
+.ft R
+
+.fi
+..
+'''
+'''
+'''     Set up \*(-- to give an unbreakable dash;
+'''     string Tr holds user defined translation string.
+'''     Bell System Logo is used as a dummy character.
+'''
+.tr \(*W-|\(bv\*(Tr
+.ie n \{\
+.ds -- \(*W-
+.ds PI pi
+.if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
+.if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
+.ds L" ""
+.ds R" ""
+'''   \*(M", \*(S", \*(N" and \*(T" are the equivalent of
+'''   \*(L" and \*(R", except that they are used on ".xx" lines,
+'''   such as .IP and .SH, which do another additional levels of
+'''   double-quote interpretation
+.ds M" """
+.ds S" """
+.ds N" """""
+.ds T" """""
+.ds L' '
+.ds R' '
+.ds M' '
+.ds S' '
+.ds N' '
+.ds T' '
+'br\}
+.el\{\
+.ds -- \(em\|
+.tr \*(Tr
+.ds L" ``
+.ds R" ''
+.ds M" ``
+.ds S" ''
+.ds N" ``
+.ds T" ''
+.ds L' `
+.ds R' '
+.ds M' `
+.ds S' '
+.ds N' `
+.ds T' '
+.ds PI \(*p
+'br\}
+.\"	If the F register is turned on, we'll generate
+.\"	index entries out stderr for the following things:
+.\"		TH	Title 
+.\"		SH	Header
+.\"		Sh	Subsection 
+.\"		Ip	Item
+.\"		X<>	Xref  (embedded
+.\"	Of course, you have to process the output yourself
+.\"	in some meaninful fashion.
+.if \nF \{
+.de IX
+.tm Index:\\$1\t\\n%\t"\\$2"
+..
+.nr % 0
+.rr F
+.\}
+.TH RRDTOOL 1 "19990426.22" "12/Feb/99" "rrdtool"
+.UC
+.if n .hy 0
+.if n .na
+.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
+.de CQ          \" put $1 in typewriter font
+.ft CW
+'if n "\c
+'if t \\&\\$1\c
+'if n \\&\\$1\c
+'if n \&"
+\\&\\$2 \\$3 \\$4 \\$5 \\$6 \\$7
+'.ft R
+..
+.\" @(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2
+.	\" AM - accent mark definitions
+.bd B 3
+.	\" fudge factors for nroff and troff
+.if n \{\
+.	ds #H 0
+.	ds #V .8m
+.	ds #F .3m
+.	ds #[ \f1
+.	ds #] \fP
+.\}
+.if t \{\
+.	ds #H ((1u-(\\\\n(.fu%2u))*.13m)
+.	ds #V .6m
+.	ds #F 0
+.	ds #[ \&
+.	ds #] \&
+.\}
+.	\" simple accents for nroff and troff
+.if n \{\
+.	ds ' \&
+.	ds ` \&
+.	ds ^ \&
+.	ds , \&
+.	ds ~ ~
+.	ds ? ?
+.	ds ! !
+.	ds /
+.	ds q
+.\}
+.if t \{\
+.	ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
+.	ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
+.	ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
+.	ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
+.	ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
+.	ds ? \s-2c\h'-\w'c'u*7/10'\u\h'\*(#H'\zi\d\s+2\h'\w'c'u*8/10'
+.	ds ! \s-2\(or\s+2\h'-\w'\(or'u'\v'-.8m'.\v'.8m'
+.	ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
+.	ds q o\h'-\w'o'u*8/10'\s-4\v'.4m'\z\(*i\v'-.4m'\s+4\h'\w'o'u*8/10'
+.\}
+.	\" troff and (daisy-wheel) nroff accents
+.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
+.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
+.ds v \\k:\h'-(\\n(.wu*9/10-\*(#H)'\v'-\*(#V'\*(#[\s-4v\s0\v'\*(#V'\h'|\\n:u'\*(#]
+.ds _ \\k:\h'-(\\n(.wu*9/10-\*(#H+(\*(#F*2/3))'\v'-.4m'\z\(hy\v'.4m'\h'|\\n:u'
+.ds . \\k:\h'-(\\n(.wu*8/10)'\v'\*(#V*4/10'\z.\v'-\*(#V*4/10'\h'|\\n:u'
+.ds 3 \*(#[\v'.2m'\s-2\&3\s0\v'-.2m'\*(#]
+.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
+.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
+.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
+.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
+.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
+.ds ae a\h'-(\w'a'u*4/10)'e
+.ds Ae A\h'-(\w'A'u*4/10)'E
+.ds oe o\h'-(\w'o'u*4/10)'e
+.ds Oe O\h'-(\w'O'u*4/10)'E
+.	\" corrections for vroff
+.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
+.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
+.	\" for low resolution devices (crt and lpr)
+.if \n(.H>23 .if \n(.V>19 \
+\{\
+.	ds : e
+.	ds 8 ss
+.	ds v \h'-1'\o'\(aa\(ga'
+.	ds _ \h'-1'^
+.	ds . \h'-1'.
+.	ds 3 3
+.	ds o a
+.	ds d- d\h'-1'\(ga
+.	ds D- D\h'-1'\(hy
+.	ds th \o'bp'
+.	ds Th \o'LP'
+.	ds ae ae
+.	ds Ae AE
+.	ds oe oe
+.	ds Oe OE
+.\}
+.rm #[ #] #H #V #F C
+.SH "NAME"
+rrdtool \- round robin database tool
+.SH "SYNOPSIS"
+\fBrrdtool\fR \fB\-\fR | \fIfunction\fR
+.SH "DESCRIPTION"
+.Sh "\s-1OVERVIEW\s0"
+It is pretty easy to gather status information from all sorts of
+things, ranging from the temperature in your office to the number of
+octets which have passed through the \s-1FDDI\s0 interface of your
+router. But it is not so trivial to store this data in a efficient and
+systematic manner. This is where \fBrrdtool\fR kicks in. It lets you
+\fIlog and analyze\fR the data you gather from all kinds of data-sources
+(\fB\s-1DS\s0\fR). The data analysis part of rrdtool is based on the ability to
+quickly generate graphical representations of the data values
+collected over a definable time period.
+.PP
+In this man page you will find general information on the design and
+functionality of the Round Robin Database Tool (rrdtool). For a more
+detailed description of how to use the individual functions of the
+\fBrrdtool\fR check the corresponding man page.
+.Sh "\s-1FUNCTIONS\s0"
+While the man pages talk of command line switches you have to set in order to
+make \fBrrdtool\fR work it is important to note that the \fBrrdtool\fR can be
+\&'remote controlled\*(R' through a set of pipes. This saves a considerable
+amount of startup time when you plan to make \fBrrdtool\fR do a lot of
+things quickly. Check the section on the section on \fIRemote Control\fR further down.
+.Ip "\fBcreate\fR" 8
+Set up a new Round Robin Database (\s-1RRD\s0). Check rrdcreate
+.Ip "\fBupdate\fR" 8
+Store new data values into an \s-1RRD\s0. Check rrdupdate
+.Ip "\fBgraph\fR" 8
+Create a graph from data stored in one or several \s-1RRD\s0. Apart from
+generating graphs, data can also be extracted to stdout. Check rrdgraph
+.Ip "\fBdump\fR" 8
+Dump the contents of an \s-1RRD\s0 in plain \s-1ASCII\s0. This is manly used for
+debugging. Check rrddump
+.Ip "\fBfetch\fR" 8
+Get data for a certain time period from a \s-1RRD\s0. The graph function
+uses fetch to retrieve its data from an rrd. Check rrdfetch
+.Ip "\fBtune\fR" 8
+Alter setup of an \s-1RRD\s0
+.Ip "\fBlast\fR" 8
+Find last update time of an \s-1RRD\s0
+.Sh "\s-1HOW\s0 \s-1DOES\s0 \s-1RRDTOOL\s0 \s-1WORK\s0?"
+.Ip "Data acquisition" 8
+When monitoring the state of a system, it is convenient to have the
+data available at a constant interval. Unfortunately you may not
+always be able to fetch data at exactly the time you want
+to. Therefore \fBrrdtool\fR lets you update the logfile at any time you
+want. It will automatically interpolate the value of the data-source
+(\fB\s-1DS\s0\fR) at the latest official time-slot and write this value to the
+log. The value you have supplied is stored as well and is also taken
+into account when interpolating the next log entry.
+.Ip "Consolidation" 8
+You may log data at a 1 minute interval, but you are also be
+interested to know the development of the data over the last year. You
+could do this by simply storing the data in 1 minute interval, for one
+year. While this would take considerable disk space it would also take
+a lot of time to analyze the data when you wanted to create a graph
+covering the whole year. \fBrrdtool\fR offers a solution to this of this
+problem through its data consolidation feature. When setting up
+an Round Robin Database (\fB\s-1RRD\s0\fR), you can define at which interval
+this consolidation should occur, and what consolidation function
+(\fB\s-1CF\s0\fR) (average, minimum, maximum, total, last) should be used to
+build the consolidated values (see rrdcreate). You can define any
+number of different consolidation setups within one \fB\s-1RRD\s0\fR. They will
+all be maintained on the fly when new data is loaded into the \fB\s-1RRD\s0\fR.
+.Ip "Round Robin Archives" 8
+Data values of the same consolidation setup are stored into Round
+Robin Archives (\fB\s-1RRA\s0\fR). This is a very efficient manner to store data
+for a certain amount of time, while using a known amount of storage
+space. 
+.Sp
+It works like this: If you want to store 1000 values in 5 minute
+interval, \fBrrdtool\fR will allocate space for 1000 data values and a
+header area. In the header it will store a pointer telling
+which one of the values in the storage area was last written to. New
+values are written to the Round Robin Archive in a ...  you guess it
+\&... round robin manner. This automatically limits the history to the last
+1000 values. Because you can define several \fB\s-1RRA\s0\fRs within a single \fB\s-1RRD\s0\fR,
+you can setup another one, storing 750 data values at a 2 hour interval
+and thus keeping a log for the last two months although at a lower
+resolution.
+.Sp
+The use of \fB\s-1RRA\s0\fRs guarantees that the \fB\s-1RRD\s0\fR does not grow over
+time and that old data is automatically eliminated. By using the
+consolidation feature, you can still keep data for a very long time,
+while gradually reducing the resolution of the data along the time
+axis. Using different consolidation functions (\fB\s-1CF\s0\fR) allows you to
+store exactly the type of information that actually interests
+you. (Maximum one minute traffic on the \s-1LAN\s0, minimum temperature of
+the wine cellar, total minutes down time ...)
+.Ip "Unknown Data" 8
+As mentioned earlier, the \fB\s-1RRD\s0\fR stores data at a constant
+interval. Now it may happen that no new data is available when a
+value has to be written to the \fB\s-1RRD\s0\fR. Data acquisition may not be
+possible for one reason or an other. The \fBrrdtool\fR handles these
+situations by storing an \fI*\s-1UNKNOWN\s0*\fR value into the database. The
+value \*(L'\fI*\s-1UNKNOWN\s0*\fR\*(R' is supported through all the functions of the
+database. When consolidating the amount of \fI*\s-1UNKNOWN\s0*\fR data is
+accumulated and when a new consolidated value is ready to be written
+to its Round Robin Archive (\fB\s-1RRA\s0\fR) a validity check is performed to
+make sure that the percentage of unknown data in the new value is
+below a configurable level. If so, an \fI*\s-1UNKNOWN\s0*\fR value will be
+written to the \fB\s-1RRA\s0\fR.
+.Ip "Graphing" 8
+The \fBrrdtool\fR also allows one to generate reports in numerical and
+graphical form based on the data stored in one or several
+\fB\s-1RRD\s0\fRs. The graphing feature is fully configurable. Size, color and
+contents of the graph can be defined freely. Check rrdgraph
+for more information on this.
+.Sh "\s-1REMOTE\s0 \s-1CONTROL\s0"
+When you start \fBrrdtool\fR with the command line option \*(L'\fB\-\fR\*(R', it waits
+for input via standard in. With this feature you can improve
+performance by attaching \fBrrdtool\fR to another process (mrtg is one
+example) through a set of pipes. Over the pipes \fBrrdtool\fR accepts the
+same arguments as on the command line. When a command is completed, 
+rrdtool will print the string  \*(L'\f(CWOK\fR\*(R', followed by timing information of
+the form \fBu:\fR\fIusertime\fR \fBs:\fR\fIsystemtime\fR both values are running
+totals of seconds since rrdtool was started. If an error occurs, a line 
+of the form \*(L'\f(CWERROR:\fR \fIDescription of error\fR\*(R' will be printed. \fBrrdtool\fR
+will not abort if possible, but follow the \s-1ERROR\s0 line with an \s-1OK\s0 line.
+.SH "SEE ALSO"
+rrdcreate, rrdupdate, rrdgraph, rrddump, rrdfetch, rrdtune, rrdlast
+.SH "BUGS"
+There must be plenty ... this is alpha code ;\-) ...
+.SH "AUTHOR"
+Tobias Oetiker <oetiker at ee.ethz.ch>
+
+.rn }` ''
+.IX Title "RRDTOOL 1"
+.IX Name "rrdtool - round robin database tool"
+
+.IX Header "NAME"
+
+.IX Header "SYNOPSIS"
+
+.IX Header "DESCRIPTION"
+
+.IX Subsection "\s-1OVERVIEW\s0"
+
+.IX Subsection "\s-1FUNCTIONS\s0"
+
+.IX Item "\fBcreate\fR"
+
+.IX Item "\fBupdate\fR"
+
+.IX Item "\fBgraph\fR"
+
+.IX Item "\fBdump\fR"
+
+.IX Item "\fBfetch\fR"
+
+.IX Item "\fBtune\fR"
+
+.IX Item "\fBlast\fR"
+
+.IX Subsection "\s-1HOW\s0 \s-1DOES\s0 \s-1RRDTOOL\s0 \s-1WORK\s0?"
+
+.IX Item "Data acquisition"
+
+.IX Item "Consolidation"
+
+.IX Item "Round Robin Archives"
+
+.IX Item "Unknown Data"
+
+.IX Item "Graphing"
+
+.IX Subsection "\s-1REMOTE\s0 \s-1CONTROL\s0"
+
+.IX Header "SEE ALSO"
+
+.IX Header "BUGS"
+
+.IX Header "AUTHOR"
+

Added: trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdintro.pod
==============================================================================
--- trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdintro.pod	(original)
+++ trunk/orca/packages/rrdtool-0.99.29.1/doc/rrdintro.pod	Sat Jul 13 18:46:06 2002
@@ -0,0 +1,1391 @@
+
+From alex at slot.hollandcasino.nl Tue May  4 23:16:13 1999
+Date: Sun, 2 May 1999 15:03:21 +0200 (MET DST)
+From: Alex van den Bogaerdt <alex at slot.hollandcasino.nl>
+To: Tobias Oetiker <oetiker at ee.ethz.ch>
+Subject: Corrected document
+
+Hi Tobi,
+
+Here are the two files again. I implemented the changes you suggested
+and made some minor changes myself.
+
+We both agree that a native English speaker should correct it before
+it goes online and do so for the same reason. I know that some parts may
+sound odd. I think it may be wise to have two or even more people look
+at it, at least one beginner and one experienced RRDtool user.
+
+You offered to convert it into the POD format, I suggest you do this
+and then ask some people to look it over.
+
+I'm still looking for a document I once read about color usage. It
+described a set of colors that are safe to use in an HTML document.
+You once suggested to look at /usr/X11/lib/X11/rgb.txt but this contains
+over 500 different colors (so: after removing descriptive labels and
+going trough sort -u) and I know for sure that the document I talk about
+describes about 240 different colors. I think it will be a valuable
+addition to both MRTG and RRDtool.
+
+Regards,
+Alex
+
+#!/bin/sh
+# This is RRDbeginnersGuide, a shell archive (produced by GNU sharutils 4.2)
+# To extract the files from this archive, save it to some FILE, remove
+# everything before the `!/bin/sh' line above, then type `sh FILE'.
+#
+# Made on 1999-05-02 14:44 MET DST by <alex at ergens.op.Het.Net>.
+# Source directory was `/mnt/sdb1/RrdDummy/workdir'.
+#
+# Existing files will *not* be overwritten unless `-c' is specified.
+# This format requires very little intelligence at unshar time.
+# "if test", "echo", "mkdir", and "sed" may be needed.
+#
+# This shar contains:
+# length mode       name
+# ------ ---------- ------------------------------------------
+#  47151 -rw-r--r-- RRDbeginner
+#  12288 -rw-r--r-- binhex
+#
+echo=echo
+if mkdir _sh06095; then
+  $echo 'x -' 'creating lock directory'
+else
+  $echo 'failed to create lock directory'
+  exit 1
+fi
+# ============= RRDbeginner ==============
+if test -f 'RRDbeginner' && test "$first_param" != -c; then
+  $echo 'x -' SKIPPING 'RRDbeginner' '(file already exists)'
+else
+  $echo 'x -' extracting 'RRDbeginner' '(text)'
+  sed 's/^X//' << 'SHAR_EOF' > 'RRDbeginner' &&
+XNot so technical explanation of RRDtool (c) by Alex van den Bogaerdt
+X
+XRRDtool (c) 1999 by Tobias Oetiker
+X
+XRRDtool is written by Tobias Oetiker <oetiker at ee.ethz.ch> with
+Xcontributions from many people all around the world. This document is
+Xwritten by Alex van den Bogaerdt <alex at ergens.op.het.net> to help you
+Xunderstand what RRDtool is and what it can do for you.
+X
+XThe documentation provided with RRDtool can be too technical for some
+Xpeople and here we help you to understand the basics in order to
+Xprepare you to read the documentation yourself. It also explains the
+Xgeneral things about statistics with a focus on networking.
+X
+XThis document may not be redistributed by any means without prior
+Xwritten permission from the author.
+XPermission to distribute copies of this document for non-commercial
+Xpurposes is hereby granted provided that the document is kept intact
+Xincluding this copyright message and disclamer, and provided that
+Xit comes together with the documentation for RRDtool.
+X
+XVersion: may 1999.
+X
+XPlease make sure you have a reasonable recent copy. If you do and you
+Xfeel this document contains errors or is incomplete, please mail me
+Xwith a description of the error/missing part, and why you think so.
+XThis will help me to improve it. Your help is appreciated.
+XPlease note that I will ignore request like
+X"my copy is from may 1999, could you mail me a more recent one ?"
+XIf there is a newer version, it will come with the RRDtool release.
+X
+XChange history:
+X199903xx: Alex van den Bogaerdt
+X          Initial draft
+X19990502: Alex van den Bogaerdt
+X          Made some textual improvements as suggested by Tobias Oetiker
+X199905xx: Tobias Oetiker
+X          Converted document to POD format
+X
+X ============================== do not cut here ===============================
+X
+X0 IMPORTANT
+X
+XWe first have to do some uninteresting reading folks, don't skip this
+Xpart! Later on, in the examples, you need to know the basics.
+X
+X1 What is RRDtool ?
+X
+XRRDtool means Round Robin Database tool.
+XRound robin is a technique that works with a fixed amount of data, and a
+Xpointer to the current element. Think of a circle with some dots plotted
+Xon the edge, these dots are the places where data can be stored. Draw an
+Xarrow from the center of the circle to one of the dots, this is the pointer.
+XWhen the current data is read or written, the pointer moves to the next
+Xelement. As we are on a circle there is no beginning nor an end, you can
+Xgo on and on. After a while, all the available places will be used and
+Xthe process automatically reuses old locations.
+XRRDtool works with with Round Robin Databases (RRDs). It stores and retrieves
+Xdata from them.
+X
+X2 What data can be put into an RDD ?
+X
+XYou name it, it will probably fit. You should be able to measure some value
+Xat several points in time and provide this to RRDtool. If you can do this,
+XRRDtool will probably be able to store it.
+X
+XMany examples talk about SNMP which is an acronym for
+XSimple Network Management Protocol. The "simple" is about the protocol,
+Xit does not mean it is simple to manage a network. After working your
+Xway through this document, you will know enough to be able to understand
+Xwhat people are talking about. For now, just assume SNMP is a way to
+Xtalk to devices and ask those devices about counters they keep.
+XIt is the value from those counters that are kept in the RRD.
+X
+X3 What can I do with this tool ?
+X
+XRRDtool originated from MRTG (multi router traffic grapher) which itself
+Xcame from a tiny little script to monitor the performance of a connection
+Xto the Internet. Since then, MRTG has also been used for several other
+Xpurposes including temperature, speed, voltage, number of printouts and
+Xmany other things. Most likely you will start to use the RRDtool to store
+Xand process data collected via SNMP. The data will most likely be bytes
+X(or bits) transfered from and to a network or a computer.
+XRRDtool lets you create a database, store data in it, retrieve that data
+Xand create graphs in GIF format for display on a web browser. Those GIF
+Ximages are dependant on the data you collected and could be, for instance,
+Xan overview of the average network usage, or rather the peaks that occurred.
+XIt can also be used to display tidal waves, solar radiation, power
+Xconsumption, number of visitors at an exibition, noise levels near an
+Xairport, temperature on your favorite holiday location, temperature in the
+Xfridge and whatever you imagination can come up with. You need a sensor to
+Xmeasure the data and be able to feed the numbers to RRDtool. Many devices
+Xhave such a sensor.
+X
+X4 What if I still have problems after reading this document ?
+X
+XMore exact, after re-reading this document :)
+XIt all depends on the kind of problems you have. If you are unable to
+Xcompile the sources and you have a fairly common OS, it will probably
+Xnot be the fault of RRDtool. There may be precompiled versions around
+Xon the Internet. If they come from trusted sources, get one of those.
+XIf on the other hand the program works but does not give you the
+Xexpected results, it will be a problem with configuring it. Review
+Xyour configuration and compare it with the examples that follow.
+X
+XThere is a mailing list and an archive of it. Read the list for a few
+Xweeks and search the archive. It is considered rude to just ask
+Xa question without reading the list, your problem may already have been
+Xsolved for somebody else and you will be helped without writing a new
+Xa message at all ... This is true for most, if not all, mailing lists
+Xand not only for this particular list! Look in the documentation that
+Xcame with RRDtool for the location and usage of the list.
+X
+XI suggest you take a moment to subscribe to the mailing list right now
+Xby sending an email to <rrdtool-users-request at list.ee.ethz.ch> with a
+Xsubject of "subscribe". If you ever want to leave this list, you write
+Xan email to the same address but now with a subject of "unsubscribe".
+X
+X5 How will you help me ?
+X
+XBy giving you some detailed descriptions with detailed examples. 
+XIt is assumed that following the instructions in the order presented
+Xwill build up enough knowledge of the program to experiment for yourself.
+XIf it doesn't work the first time, don't give up. Reread the stuff that
+Xyou did understand, you may have missed something.
+XBy following the examples you get some hands-on experience and, even
+Xmore important, some background information of how it works.
+X
+XYou will need to know something about hexadecimal numbers. If you don't
+Xthen start with reading "binhex" before you continue here.
+X
+XIn my opinion the best way to learn something is to actually do it.
+XWhy not start right now. We will create a database, put some values in
+Xit and extract this data again. It is expected that you get the same
+Xresults when you try these examples yourself so do that.
+XWe will start with some easy stuff and compare a car with a router,
+Xor compare kilometers (miles if you wish) with bits and bytes. It's
+Xall the same: Some number over some time.
+X
+XAssume we have a device that transfers bytes to and from the Internet.
+XThis device keeps a counter that starts at zero when it is turned on,
+Xincreasing with every byte that is transfered. This counter will have
+Xa maximum value, if that value is reached and an extra byte is counted,
+Xthe counter starts all over at zero. This is the same as many counters
+Xin the world such as the mileage counter in a car.
+XMost discussions about networking talk about bits per second so lets
+Xget used to that right away. Assume a byte is eight bits and start to
+Xthink in bits not bytes. The counter however still counts bytes !
+XIn the SNMP world most of the counters are 32 bits. That means they are
+Xcounting from 0 to 4294967295. We will use these values in the examples.
+XThe device, when asked, returns the current value of the counter. We
+Xknow the time that has passes since we last asked so we now know how
+Xmany bytes have been transfered ***on average*** per second. This is
+Xnot very hard to calculate. First in words, then in calculi:
+X  1) Take the current counter, subtract the previous value from it.
+X  2) Do the same with the current time and the previous time.
+X  3) Divide the outcome of (1) by the outcome of (2), the result is
+X     the amount of bytes per second. Multiply by eight to get the
+X     number of bits per second (bps).
+X  bps = (counter_now - counter_before) / (time_now - time_before) * 8
+X
+XFor some people it may help to translate this to a automobile example:
+XDo not try this example, and if you do, don't blame me for the results.
+X
+XPeople who are not used to think in kilometers per hour can translate
+Xmost into miles per hour by dividing km by 1.6 (close enough).
+XI will use the following abbreviations:
+XM:    meter
+XKM:   kilometer (= 1000 meters).
+XH:    hour
+XS:    second
+XKM/H: kilometers per hour
+XM/S:  meters per second
+X
+XYou're driving a car. At 12:05 you read the counter in the dashboard
+Xand it tells you that the car has moved 12345 KM until that moment.
+XAt 12:10 you look again, it reads 12357 KM. This means you have
+Xtraveled 12 KM in five minutes. A scientist would translate that
+Xinto meters per second and this makes a nice comparison towards the
+Xproblem of (bytes per five minutes) versus (bits per second).
+X
+XWe traveled 12 kilometers which is 12000 meters. We did that in five
+Xminutes which translates into 300 seconds. Our speed is 12000M / 300S
+Xequals 40 M/S. 
+X
+XWe could also calculate the speed in KM/H: twelve times five minutes
+Xis an hour so we have to multiply 12 KM by 12 to get 144 KM/H.
+XFor our native English speaking friends: this is ninety MPH and
+Xtherefore not recommended to try for yourself where I live :)
+X
+XRemember: these numbers are averages and there is no way to figure out
+Xfrom the numbers we got that you drove at a constant speed.
+X
+XI hope you understand that there is no difference in calculating M/S or
+Xbps, only the way we collect the data is different. Even the K from kilo
+Xis the same as in networking terms k also means 1000.
+X
+XWe will now create a database where we can keep all these interesting
+Xnumbers. The method used to start the program may differ slightly from
+XOS to OS but I assume you can figure it out if it works different on
+Xyour OS. Make sure you do not overwrite any file on your system when
+Xexecuting the following command (so: first look if it's safe!) and type
+Xthe whole line as one long line (I had to split it for readability)
+Xand skip all of the '\' characters.
+X
+X   rrdtool create test.rrd             \
+X            --start 920804400          \
+X            DS:speed:COUNTER:600:U:U   \
+X            RRA:AVERAGE:0.5:1:24       \
+X            RRA:AVERAGE:0.5:6:10 
+X
+X (So enter: rrdtool create test.rrd --start 920804400 DS ...)
+X
+XWhat has been created ?
+XWe created the round robin database called test (test.rrd)
+Xwhich starts at noon the day I started (7th of march, 1999) writing
+Xthis document. It holds one data source (DS) named "speed" that gets
+Xbuilt from a counter. This counter is read every five minutes (default)
+XIn the same database two round robin archives (RRAs) are kept, one
+Xaverages the data every time it is read (so: there's nothing to average)
+Xand keeps 24 samples (24 times 5 minutes is 2 hours). The other averages
+X6 values (half hour) and contains 10 of such averages (so: 5 hours)
+XThe remaining options will be discussed later on.
+XChances are that you are not in the same part of the world as I am.
+XThis means your time zone is different. In all examples where I talk
+Xabout time, the hours may be wrong for you. This has little effect on
+Xthe results of the examples, just correct the hours while reading.
+X
+XWe now have to fill our database with some numbers. We'll pretend to
+Xhave read the following numbers:
+X
+X12:05	12345 KM
+X12:10	12357 KM
+X12:15	12363 KM
+X12:20	12363 KM
+X12:25	12363 KM
+X12:30	12373 KM
+X12:35	12383 KM
+X12:40	12393 KM
+X12:45	12399 KM
+X12:50	12405 KM
+X12:55	12411 KM
+X13:00	12415 KM
+X13:05	12420 KM
+X13:10	12422 KM
+X13:15	12423 KM
+X
+XWe fill the database as follows:
+X
+X   rrdtool update test.rrd 920804700:12345 920805000:12357 920805300:12363
+X   rrdtool update test.rrd 920805600:12363 920805900:12363 920806200:12373
+X   rrdtool update test.rrd 920806500:12383 920806800:12393 920807100:12399
+X   rrdtool update test.rrd 920807400:12405 920807700:12411 920808000:12415
+X   rrdtool update test.rrd 920808300:12420 920808600:12422 920808900:12423
+X
+XThis reads: update our test database with the following numbers
+X    time 920804700, value 12345
+X    time 920805000, value 12357
+X   etcetera.
+X
+XAs you can see, it is possible to feed more than one value into the
+Xdatabase in one command. I had to stop at three for readability but
+Xthe real maximum will be OS dependent.
+X
+XThe time value may look strange to you, it is written in seconds since
+Xthe first of January, 1970, midnight. Don't worry about this yet, just
+Xnotice that there is a difference of 300 in between all values.
+X
+XIt is time to do some graphics now:
+X
+X   rrdtool graph speed.gif                            \
+X      --start 920804400 --end 920808000               \
+X      DEF:myspeed=test.rrd:speed:AVERAGE              \
+X      LINE2:myspeed#FF0000
+X
+XThis will create speed.gif which starts at 12:00 and ends at 13:00.
+XThere is a definition of variable myspeed, it is the data from RRA
+X"speed" out of database "test.rrd". The line drawn is 2 pixels high,
+Xand comes from variable myspeed. The color is red.
+XYou'll notice that the start of the graph is not at 12:00 but at 12:05
+Xand this is because we have insufficient data to tell the average before
+Xthat time. This will only happen when you miss some samples, this will
+Xnot happen a lot, hopefully.
+X
+XIf this has worked: Congratulations. If not, check what went wrong.
+X
+X
+XThe colors are built up from red, green and blue. For each of the
+Xcomponents, you specify how much to use in hexadecimal where 00 means
+Xnot included and FF means fully included.
+XThe color white is a mixture of red, green and blue: FFFFFF
+XThe color black is all colors off: 000000
+X(Please, no discussions if black and white can be called colors)
+X
+X   red    #FF0000
+X   green  #00FF00
+X   blue   #0000FF
+X   purple #FF00FF     (mixed red with blue)
+X   gray   #555555     (one third of all components)
+X
+X
+X
+XThe GIF you just created can be displayed using a web browser or other
+Xsoftware you like. I can not provide you with an example of that, there
+Xare too many different setups, possibilities etc.
+X
+XWhen looking at the image, you notice that the horizontal axis displays
+X12:10, 12:20, 12:30, 12:40 and 12:50. The two remaining times (12:00 and
+X13:00) would not be displayed nicely so they are skipped.
+XThe vertical axis displays the range we entered. We provided kilometers
+Xand when divided by 300 seconds, we get very small numbers. To be exact,
+Xthe first value was 12 (12357-12345) and divided by 300 this makes 0.04
+XRRDtool displays this as 40 m which means 40 mili (so: NOT meters).
+XWhat we did wrong was that we should have measured in meters, this would
+Xhave been (12357000-12345000)/300 = 12000/300 = 40.
+X
+XLet's correct that. We could recreate our database and store the correct
+Xdata but there is another way: do some calculations while creating the
+Xgif file !
+X
+X   rrdtool graph speed2.gif                           \
+X      --start 920804400 --end 920808000               \
+X      --vertical-label m/s                            \
+X      DEF:myspeed=test.rrd:speed:AVERAGE              \
+X      CDEF:realspeed=myspeed,1000,*                   \
+X      LINE2:realspeed#FF0000
+X
+XAfter viewing this GIF, you notice the "m" has disappeared. This it what
+Xthe correct result would be. Also, a label has been added to the image.
+XApart from the things mentioned above, the GIF should be the same.
+X
+XThe calculations are done with the CDEF part. What it says is: take the
+Xdata source myspeed and the number 1000, multiply those. The calculations
+Xare done using Reverse Polish Notation. It is an easy way of performing
+Xcalculations after you understand it. You will, eventually but for now
+Xassume it is correct what I write and just keep to the examples in this
+Xfile. Read the documentation that came with RRDtool (look in rrdgraph.doc)
+Xwhen you're ready for it.
+X
+XHang on! If we can multiply values with 1000, it should also be possible
+Xto display kilometers per hour from the same data !
+XWhat do we need to do ? If we have meters per second, we can make this
+Xmeters per hour by multiplying the value with 3600 (there go 3600 seconds
+Xin one hour). To get kilometers per hour, we need to divide by 1000.
+XWe end up with: value * 3600 / 1000 = value * 3.6 . Remember we also have
+Xto correct our mistake, so it is value * 3600 for us.
+X
+XNow lets create this GIF, and add some more magic ...
+X
+X   rrdtool graph speed3.gif                           \
+X      --start 920804400 --end 920808000               \
+X      --vertical-label km/h                           \
+X      DEF:myspeed=test.rrd:speed:AVERAGE              \
+X      CDEF:kmh=myspeed,3600,*                         \
+X      CDEF:fast=0,kmh,kmh,100,GT,IF                   \
+X      CDEF:good=kmh,0,kmh,100,GT,IF                   \
+X      HRULE:100#0000FF:"Maximum allowed"              \
+X      AREA:good#00FF00:"Good speed"                   \
+X      AREA:fast#FF0000:"Too fast"
+X
+XThis looks much better. Speed in KM/H and even an extra line with the
+Xmaximum allowed speed (on the road I travel at). I also changed the
+Xcolors used to display speed and changed it from a line into an area.
+X
+XThe calculations are more complex now. For the "good" speed they are:
+X- Check if kmh is greater than 100    ( kmh,100 ) GT
+X- If so, return 0, else kmh           ( kmh,0, (( kmh,100 ) GT ) IF
+XFor the other speed:
+X- Check if kmh is greater than 100    ( kmh,100 ) GT
+X- If so, return kmh, else return 0    ( 0,kmh, (( kmh,100) GT ) IF
+X
+X
+XI like to believe there are virtually no limits about what RRDtool
+Xcan do. I will not explain how it works, but look at the following
+XGIF:
+X
+X   rrdtool graph speed4.gif                           \
+X      --start 920804400 --end 920808000               \
+X      --vertical-label km/h                           \
+X      DEF:myspeed=test.rrd:speed:AVERAGE              \
+X      CDEF:kmh=myspeed,3600,*                         \
+X      CDEF:fast=0,100,kmh,100,GT,IF                   \
+X      CDEF:over=0,kmh,100,-,kmh,100,GT,IF             \
+X      CDEF:good=kmh,0,kmh,100,GT,IF                   \
+X      HRULE:100#0000FF:"Maximum allowed"              \
+X      AREA:good#00FF00:"Good speed"                   \
+X      AREA:fast#550000:"Too fast"                     \
+X      STACK:over#FF0000:"Over speed"
+X
+XLet's create a quick and dirty HTML page to view three GIFs:
+X
+X   <HTML><HEAD><TITLE>Speed</TITLE></HEAD><BODY>
+X   <IMG src="speed2.gif" alt="Speed in meters per second">
+X   <BR>
+X   <IMG src="speed3.gif" alt="Speed in kilometers per hour">
+X   <BR>
+X   <IMG src="speed4.gif" alt="Traveled too fast?">
+X   </BODY></HTML>
+X
+XName the file "speed.html" or similar, and view it.
+X
+XNow, all you have to do is measure the values regularly and update the
+Xdatabase. Every time you create these three GIFs and reload the page
+Xand the GIFs (better reread this last three words!) you know how fast
+Xyou traveled.
+X
+XYou already looked at the "update" tool. It took one or more parameters
+Xin the form of "<time>:<value>". You'll be glad to know that you can
+Xget the current time by filling in a "N" as the time.
+XIf you wish, you can also use the "time" function in perl.
+XThe shortest example in this doc :)
+X
+X   perl -e 'print time, "\n" '
+X
+XHow you can run a program on regular intervals is OS specific, so I just
+Xgive you an example script in a sort of pseudo code:
+X(Do not try this with our test database, it is used in further examples)
+X
+X   Get the value, put it in variable "$speed"
+X   rrdtool update speed.rrd N:$speed
+X
+XThis is all. Run this script every five minutes. When you need to know
+Xwhat the graphics look like, run the examples above. You could put them
+Xin a script. After running that script, view index.html
+X
+XI can imagine very few people will be able to get real data from their
+Xcar every five minutes, all other people will have to settle for some
+Xother kind of counter. You could measure the number of pages printed by
+Xthe laser-jet printer, the coffee made by the coffee machine, a device
+Xthat counts the electricity used, whatever.