[Orca-checkins] rev 122 - in trunk/orca: . orcallator lib lib/Orca src docs packages packages/Storable-0.6.9 packages/Storable-0.6.9/t packages/rrdtool-1.0.13 packages/rrdtool-1.0.13/src packages/rrdtool-1.0.13/cgilib-0.4 packages/rrdtool-1.0.13/zlib-1.1.3 packages/rrdtool-1.0.13/contrib packages/rrdtool-1.0.13/contrib/rrdlastds packages/rrdtool-1.0.13/contrib/rrdfetchnames packages/rrdtool-1.0.13/contrib/killspike packages/rrdtool-1.0.13/contrib/rrd-file-icon packages/rrdtool-1.0.13/contrib/rrdproc packages/rrdtool-1.0.13/contrib/log2rrd packages/rrdtool-1.0.13/contrib/trytime packages/rrdtool-1.0.13/contrib/add_ds packages/rrdtool-1.0.13/perl-piped packages/rrdtool-1.0.13/config packages/rrdtool-1.0.13/doc packages/rrdtool-1.0.13/perl-shared packages/rrdtool-1.0.13/perl-shared/t packages/rrdtool-1.0.13/libpng-1.0.3 packages/rrdtool-1.0.13/gd1.3 packages/rrdtool-1.0.13/examples

blair at orcaware.com blair at orcaware.com
Sat Jul 13 21:09:02 PDT 2002


Author: blair
Date: Fri, 28 Jun 2002 22:08:15 -0700
New Revision: 122

Added:
   trunk/orca/lib/Orca/
   trunk/orca/lib/Orca/Config.pm
   trunk/orca/lib/Orca/Constants.pm
   trunk/orca/lib/Orca/DataFile.pm
   trunk/orca/lib/Orca/HTMLFile.pm
   trunk/orca/lib/Orca/ImageFile.pm
   trunk/orca/lib/Orca/NewState.pm
   trunk/orca/lib/Orca/OldState.pm
   trunk/orca/lib/Orca/OpenFileHash.pm
   trunk/orca/lib/Orca/RRDFile.pm
   trunk/orca/lib/Orca/SourceFile.pm
   trunk/orca/lib/Orca/SourceFileIDs.pm
   trunk/orca/lib/Orca/Utils.pm
   trunk/orca/packages/rrdtool-1.0.13/contrib/add_ds/
   trunk/orca/packages/rrdtool-1.0.13/contrib/add_ds/Makefile.am
   trunk/orca/packages/rrdtool-1.0.13/contrib/add_ds/Makefile.in
   trunk/orca/packages/rrdtool-1.0.13/contrib/add_ds/README
   trunk/orca/packages/rrdtool-1.0.13/contrib/add_ds/add_ds.pl.in
   trunk/orca/packages/rrdtool-1.0.13/contrib/add_ds/batch.pl.in
   trunk/orca/packages/rrdtool-1.0.13/contrib/killspike/
   trunk/orca/packages/rrdtool-1.0.13/contrib/killspike/Makefile.am
   trunk/orca/packages/rrdtool-1.0.13/contrib/killspike/Makefile.in
   trunk/orca/packages/rrdtool-1.0.13/contrib/killspike/README
   trunk/orca/packages/rrdtool-1.0.13/contrib/killspike/killspike.pl.in
   trunk/orca/packages/rrdtool-1.0.13/contrib/rrdfetchnames/
   trunk/orca/packages/rrdtool-1.0.13/contrib/rrdfetchnames/Makefile.am
   trunk/orca/packages/rrdtool-1.0.13/contrib/rrdfetchnames/Makefile.in
   trunk/orca/packages/rrdtool-1.0.13/contrib/rrdfetchnames/README
   trunk/orca/packages/rrdtool-1.0.13/contrib/rrdfetchnames/rrdfetchnames.pl.in
   trunk/orca/packages/rrdtool-1.0.13/contrib/rrdlastds/
   trunk/orca/packages/rrdtool-1.0.13/contrib/rrdlastds/Makefile.am
   trunk/orca/packages/rrdtool-1.0.13/contrib/rrdlastds/Makefile.in
   trunk/orca/packages/rrdtool-1.0.13/contrib/rrdlastds/README
   trunk/orca/packages/rrdtool-1.0.13/contrib/rrdlastds/rrdlastds.pl.in
   trunk/orca/packages/rrdtool-1.0.13/contrib/rrdproc/
   trunk/orca/packages/rrdtool-1.0.13/contrib/rrdproc/Makefile.am
   trunk/orca/packages/rrdtool-1.0.13/contrib/rrdproc/Makefile.in
   trunk/orca/packages/rrdtool-1.0.13/contrib/rrdproc/README
   trunk/orca/packages/rrdtool-1.0.13/contrib/rrdproc/rrdproc.c
   trunk/orca/packages/rrdtool-1.0.13/doc/cdeftutorial.html
   trunk/orca/packages/rrdtool-1.0.13/doc/cdeftutorial.pod
   trunk/orca/packages/rrdtool-1.0.13/doc/cdeftutorial.txt
   trunk/orca/packages/rrdtool-1.0.13/doc/rpntutorial.html
   trunk/orca/packages/rrdtool-1.0.13/doc/rpntutorial.pod
   trunk/orca/packages/rrdtool-1.0.13/doc/rpntutorial.txt
Modified:
   trunk/orca/CHANGES
   trunk/orca/INSTALL
   trunk/orca/Makefile.in
   trunk/orca/NEWS
   trunk/orca/README
   trunk/orca/TODO
   trunk/orca/configure
   trunk/orca/configure.in
   trunk/orca/docs/Makefile.in
   trunk/orca/lib/Makefile.in
   trunk/orca/lib/homesteaders.cfg
   trunk/orca/orcallator/orcallator.cfg.in
   trunk/orca/orcallator/orcallator.se
   trunk/orca/orcallator/start_orcallator.sh.in
   trunk/orca/packages/Makefile.in
   trunk/orca/packages/Storable-0.6.9/ChangeLog
   trunk/orca/packages/Storable-0.6.9/README
   trunk/orca/packages/Storable-0.6.9/Storable.pm
   trunk/orca/packages/Storable-0.6.9/Storable.xs
   trunk/orca/packages/Storable-0.6.9/patchlevel.h
   trunk/orca/packages/Storable-0.6.9/t/canonical.t
   trunk/orca/packages/Storable-0.6.9/t/dclone.t
   trunk/orca/packages/Storable-0.6.9/t/retrieve.t
   trunk/orca/packages/rrdtool-1.0.13/CHANGES
   trunk/orca/packages/rrdtool-1.0.13/CONTRIBUTORS
   trunk/orca/packages/rrdtool-1.0.13/COPYING
   trunk/orca/packages/rrdtool-1.0.13/COPYRIGHT
   trunk/orca/packages/rrdtool-1.0.13/Makefile.am
   trunk/orca/packages/rrdtool-1.0.13/Makefile.in
   trunk/orca/packages/rrdtool-1.0.13/README
   trunk/orca/packages/rrdtool-1.0.13/cgilib-0.4/Makefile.in
   trunk/orca/packages/rrdtool-1.0.13/config/Makefile.in
   trunk/orca/packages/rrdtool-1.0.13/config/acconfig.h
   trunk/orca/packages/rrdtool-1.0.13/config/config.h.in
   trunk/orca/packages/rrdtool-1.0.13/configure
   trunk/orca/packages/rrdtool-1.0.13/configure.in
   trunk/orca/packages/rrdtool-1.0.13/contrib/Makefile.am
   trunk/orca/packages/rrdtool-1.0.13/contrib/Makefile.in
   trunk/orca/packages/rrdtool-1.0.13/contrib/README
   trunk/orca/packages/rrdtool-1.0.13/contrib/log2rrd/Makefile.in
   trunk/orca/packages/rrdtool-1.0.13/contrib/rrd-file-icon/Makefile.in
   trunk/orca/packages/rrdtool-1.0.13/contrib/trytime/Makefile.am
   trunk/orca/packages/rrdtool-1.0.13/contrib/trytime/Makefile.in
   trunk/orca/packages/rrdtool-1.0.13/contrib/trytime/trytime.c
   trunk/orca/packages/rrdtool-1.0.13/doc/Makefile.am
   trunk/orca/packages/rrdtool-1.0.13/doc/Makefile.in
   trunk/orca/packages/rrdtool-1.0.13/doc/RRDp.html
   trunk/orca/packages/rrdtool-1.0.13/doc/RRDp.txt
   trunk/orca/packages/rrdtool-1.0.13/doc/RRDs.html
   trunk/orca/packages/rrdtool-1.0.13/doc/RRDs.txt
   trunk/orca/packages/rrdtool-1.0.13/doc/bin_dec_hex.html
   trunk/orca/packages/rrdtool-1.0.13/doc/bin_dec_hex.pod
   trunk/orca/packages/rrdtool-1.0.13/doc/bin_dec_hex.txt
   trunk/orca/packages/rrdtool-1.0.13/doc/rrdcgi.html
   trunk/orca/packages/rrdtool-1.0.13/doc/rrdcgi.pod
   trunk/orca/packages/rrdtool-1.0.13/doc/rrdcgi.txt
   trunk/orca/packages/rrdtool-1.0.13/doc/rrdcreate.html
   trunk/orca/packages/rrdtool-1.0.13/doc/rrdcreate.pod
   trunk/orca/packages/rrdtool-1.0.13/doc/rrdcreate.txt
   trunk/orca/packages/rrdtool-1.0.13/doc/rrddump.html
   trunk/orca/packages/rrdtool-1.0.13/doc/rrddump.txt
   trunk/orca/packages/rrdtool-1.0.13/doc/rrdfetch.html
   trunk/orca/packages/rrdtool-1.0.13/doc/rrdfetch.txt
   trunk/orca/packages/rrdtool-1.0.13/doc/rrdgraph.html
   trunk/orca/packages/rrdtool-1.0.13/doc/rrdgraph.pod
   trunk/orca/packages/rrdtool-1.0.13/doc/rrdgraph.txt
   trunk/orca/packages/rrdtool-1.0.13/doc/rrdlast.html
   trunk/orca/packages/rrdtool-1.0.13/doc/rrdlast.txt
   trunk/orca/packages/rrdtool-1.0.13/doc/rrdresize.html
   trunk/orca/packages/rrdtool-1.0.13/doc/rrdresize.txt
   trunk/orca/packages/rrdtool-1.0.13/doc/rrdrestore.html
   trunk/orca/packages/rrdtool-1.0.13/doc/rrdrestore.txt
   trunk/orca/packages/rrdtool-1.0.13/doc/rrdtool.html
   trunk/orca/packages/rrdtool-1.0.13/doc/rrdtool.txt
   trunk/orca/packages/rrdtool-1.0.13/doc/rrdtune.html
   trunk/orca/packages/rrdtool-1.0.13/doc/rrdtune.txt
   trunk/orca/packages/rrdtool-1.0.13/doc/rrdtutorial.html
   trunk/orca/packages/rrdtool-1.0.13/doc/rrdtutorial.pod
   trunk/orca/packages/rrdtool-1.0.13/doc/rrdtutorial.txt
   trunk/orca/packages/rrdtool-1.0.13/doc/rrdupdate.html
   trunk/orca/packages/rrdtool-1.0.13/doc/rrdupdate.txt
   trunk/orca/packages/rrdtool-1.0.13/examples/Makefile.in
   trunk/orca/packages/rrdtool-1.0.13/examples/cgi-demo.cgi.in
   trunk/orca/packages/rrdtool-1.0.13/examples/piped-demo.pl.in
   trunk/orca/packages/rrdtool-1.0.13/examples/shared-demo.pl.in
   trunk/orca/packages/rrdtool-1.0.13/gd1.3/Makefile.in
   trunk/orca/packages/rrdtool-1.0.13/gd1.3/README.rrdtool
   trunk/orca/packages/rrdtool-1.0.13/gd1.3/gd.c
   trunk/orca/packages/rrdtool-1.0.13/gd1.3/gd.h
   trunk/orca/packages/rrdtool-1.0.13/libpng-1.0.3/Makefile.in
   trunk/orca/packages/rrdtool-1.0.13/perl-piped/RRDp.pm
   trunk/orca/packages/rrdtool-1.0.13/perl-shared/RRDs.pm
   trunk/orca/packages/rrdtool-1.0.13/perl-shared/RRDs.xs
   trunk/orca/packages/rrdtool-1.0.13/perl-shared/t/base.t
   trunk/orca/packages/rrdtool-1.0.13/src/Makefile.in
   trunk/orca/packages/rrdtool-1.0.13/src/gdpng.c
   trunk/orca/packages/rrdtool-1.0.13/src/gifsize.c
   trunk/orca/packages/rrdtool-1.0.13/src/ntconfig.h
   trunk/orca/packages/rrdtool-1.0.13/src/parsetime.c
   trunk/orca/packages/rrdtool-1.0.13/src/pngsize.c
   trunk/orca/packages/rrdtool-1.0.13/src/rrd_cgi.c
   trunk/orca/packages/rrdtool-1.0.13/src/rrd_create.c
   trunk/orca/packages/rrdtool-1.0.13/src/rrd_diff.c
   trunk/orca/packages/rrdtool-1.0.13/src/rrd_dump.c
   trunk/orca/packages/rrdtool-1.0.13/src/rrd_error.c
   trunk/orca/packages/rrdtool-1.0.13/src/rrd_fetch.c
   trunk/orca/packages/rrdtool-1.0.13/src/rrd_format.c
   trunk/orca/packages/rrdtool-1.0.13/src/rrd_format.h
   trunk/orca/packages/rrdtool-1.0.13/src/rrd_graph.c
   trunk/orca/packages/rrdtool-1.0.13/src/rrd_last.c
   trunk/orca/packages/rrdtool-1.0.13/src/rrd_open.c
   trunk/orca/packages/rrdtool-1.0.13/src/rrd_resize.c
   trunk/orca/packages/rrdtool-1.0.13/src/rrd_restore.c
   trunk/orca/packages/rrdtool-1.0.13/src/rrd_tool.c
   trunk/orca/packages/rrdtool-1.0.13/src/rrd_tool.h
   trunk/orca/packages/rrdtool-1.0.13/src/rrd_tune.c
   trunk/orca/packages/rrdtool-1.0.13/src/rrd_update.c
   trunk/orca/packages/rrdtool-1.0.13/zlib-1.1.3/Makefile.in
   trunk/orca/packages/rrdtool-1.0.13/zlib-1.1.3/zconf.h
   trunk/orca/src/orca.pl.in
Log:
Load orca-0.26 into trunk/orca.


Modified: trunk/orca/configure
==============================================================================
--- trunk/orca/configure	(original)
+++ trunk/orca/configure	Sat Jul 13 21:07:49 2002
@@ -654,8 +654,8 @@
 DATA_DUMPER_DIR=Data-Dumper-2.101
 DIGEST_MD5_DIR=Digest-MD5-2.09
 MATH_INTERPOLATE_DIR=Math-Interpolate-1.05
-RRDTOOL_DIR=rrdtool-1.0.7.2
-STORABLE_DIR=Storable-0.6.7
+RRDTOOL_DIR=rrdtool-1.0.13
+STORABLE_DIR=Storable-0.6.9
 
 
 
@@ -1398,7 +1398,7 @@
   echo "$ac_t""no" 1>&6
 fi
 
-if test "x$PERL" = "xNOT_FOUND"; then
+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
   
@@ -1424,10 +1424,105 @@
 PERL_HEAD="../config/$PERL_HEAD"
 
 
+# Determine the correct ps command to use to find out about process
+# information for itself.
+# Extract the first word of "ps", so it can be a program name with args.
+set dummy ps; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1433: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_PS'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$PS" in
+  /*)
+  ac_cv_path_PS="$PS" # Let the user override the test with a path.
+  ;;
+  ?:/*)			 
+  ac_cv_path_PS="$PS" # 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_PS="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  ;;
+esac
+fi
+PS="$ac_cv_path_PS"
+if test -n "$PS"; then
+  echo "$ac_t""$PS" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+case "$target" in
+  *-solaris*)
+    PS_SELF="$PS -p PID -o \'rss vsz pmem time user pid comm\'"
+    ;;
+  *-linux-*)
+    PS_SELF="$PS auxp PID"
+    ;;
+  *)
+    PS_SELF="$PS aux | grep PID"
+    echo "configure: warning: *** If you know a better PS command than" 1>&2
+    echo "configure: warning: ***   '$PS_SELF'" 1>&2
+    echo "configure: warning: *** to get process information for your host," 1>&2
+    echo "configure: warning: *** please email the command the the output from" 1>&2
+    echo "configure: warning: *** ./config/config.guess to" 1>&2
+    echo "configure: warning: *** orca-developers at onelist.com" 1>&2
+    ;;
+esac
+if test "$PS_SELF"; then
+  echo $ac_n "checking for ps command""... $ac_c" 1>&6
+echo "configure:1484: checking for ps command" >&5
+  echo "$ac_t""$PS_SELF" 1>&6
+  
+fi
+# 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:1491: 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
+  case "$SE" in
+  /*)
+  ac_cv_path_SE="$SE" # Let the user override the test with a path.
+  ;;
+  ?:/*)			 
+  ac_cv_path_SE="$SE" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH:/opt/RICHPse/bin"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_SE="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  ;;
+esac
+fi
+SE="$ac_cv_path_SE"
+if test -n "$SE"; then
+  echo "$ac_t""$SE" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
 # 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:1431: checking for $ac_word" >&5
+echo "configure:1526: 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
@@ -1463,7 +1558,7 @@
 # Extract the first word of "uncompress", so it can be a program name with args.
 set dummy uncompress; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1467: checking for $ac_word" >&5
+echo "configure:1562: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_path_UNCOMPRESS'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1513,83 +1608,31 @@
 
 
 
-# Now we check for those portions of Orca that should be built and set
-# up for installation.  The first step is to check for operating system
-# specific modules.  For Solaris hosts, orcallator.se is built and
-# installed.  This requires the additional building of a librrd.so
-# installed in libdir.  Then we check for the proper Perl modules.
-echo $ac_n "checking for solaris host for orcallator install""... $ac_c" 1>&6
-echo "configure:1523: checking for solaris host for orcallator install" >&5
-case "$target" in
-  *-solaris*)
-    BUILD_ORCALLATOR=yes
-    ORCALLATOR_SUBDIR=orcallator
-    # Add --enable-shared to the configure options for RRDtool if it is
-    # not already declared.
-    expr "$CONFIGURE_COMMAND_LINE" : "--enable-shared" >/dev/null 2>&1 || CONFIGURE_COMMAND_LINE="$CONFIGURE_COMMAND_LINE --enable-shared"
-
-    INSTALL_LIB_RRDTOOL=install_lib_rrdtool
-    MAKE_RRDTOOL=make_rrdtool
-    TEST_RRDTOOL=test_rrdtool
-    INSTALL_PERL_RRDTOOL=
-    CLEAN_RRDTOOL=clean_rrdtool
-    DISTCLEAN_RRDTOOL=distclean_rrdtool
-    ;;
-  *)
-    INSTALL_LIB_RRDTOOL=
-    BUILD_ORCALLATOR=no
-    ORCALLATOR_SUBDIR=
-    ;;
-esac
+# Always build the orcallator files regardless of the operating system.
+BUILD_ORCALLATOR=yes
+ORCALLATOR_SUBDIR=orcallator
+INSTALL_LIB_RRDTOOL=
 
 
 
-echo "$ac_t""$BUILD_ORCALLATOR" 1>&6
-if test "$BUILD_ORCALLATOR" = "yes"; then
-  # 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:1553: 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
-  case "$SE" in
-  /*)
-  ac_cv_path_SE="$SE" # Let the user override the test with a path.
-  ;;
-  ?:/*)			 
-  ac_cv_path_SE="$SE" # Let the user override the test with a dos path.
-  ;;
-  *)
-  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
-  ac_dummy="$PATH:/opt/RICHPse/bin"
-  for ac_dir in $ac_dummy; do 
-    test -z "$ac_dir" && ac_dir=.
-    if test -f $ac_dir/$ac_word; then
-      ac_cv_path_SE="$ac_dir/$ac_word"
-      break
-    fi
-  done
-  IFS="$ac_save_ifs"
-  ;;
-esac
-fi
-SE="$ac_cv_path_SE"
-if test -n "$SE"; then
-  echo "$ac_t""$SE" 1>&6
-else
-  echo "$ac_t""no" 1>&6
-fi
+# These commands can be used if the orcallator should not be built.
+# AC_MSG_CHECKING([for solaris host for orcallator install])
+# AC_MSG_RESULT($BUILD_ORCALLATOR)
+# BUILD_ORCALLATOR=no
+# ORCALLATOR_SUBDIR=
+
+# These commands can be used to force a build of the librrdtool library.
+# INSTALL_LIB_RRDTOOL=install_lib_rrdtool
+# MAKE_RRDTOOL=make_rrdtool
+# TEST_RRDTOOL=test_rrdtool
+# INSTALL_PERL_RRDTOOL=
+# CLEAN_RRDTOOL=clean_rrdtool
+# DISTCLEAN_RRDTOOL=distclean_rrdtool
+
+# This command can be used to add --enable-shared to the configure
+# options for RRDtool if it is not already declared.
+# expr "$CONFIGURE_COMMAND_LINE" : "--enable-shared" >/dev/null 2>&1 || CONFIGURE_COMMAND_LINE="$CONFIGURE_COMMAND_LINE --enable-shared"
 
-fi
-
-if test "$borp_cv_perl_compress_zlib" = no; then
-  MAKE_COMPRESS_ZLIB=make_compress_zlib
-  TEST_COMPRESS_ZLIB=test_compress_zlib
-  INSTALL_PERL_COMPRESS_ZLIB=install_perl_compress_zlib
-  CLEAN_COMPRESS_ZLIB=clean_compress_zlib
-  DISTCLEAN_COMPRESS_ZLIB=distclean_compress_zlib
-fi
 
 
 
@@ -1598,7 +1641,7 @@
 
 
   echo $ac_n "checking if Perl module Data::Dumper version 2.101 is installed""... $ac_c" 1>&6
-echo "configure:1602: checking if Perl module Data::Dumper version 2.101 is installed" >&5
+echo "configure:1645: checking if Perl module Data::Dumper version 2.101 is installed" >&5
   if $PERL ./config/check_for_perl_mod Data::Dumper 2.101; then
     borp_cv_perl_data_dumper=yes
     
@@ -1622,9 +1665,9 @@
 
 
 
-  echo $ac_n "checking if Perl module Digest::MD5 version 2.00 is installed""... $ac_c" 1>&6
-echo "configure:1627: checking if Perl module Digest::MD5 version 2.00 is installed" >&5
-  if $PERL ./config/check_for_perl_mod Digest::MD5 2.00; then
+  echo $ac_n "checking if Perl module Digest::MD5 version 2.09 is installed""... $ac_c" 1>&6
+echo "configure:1670: checking if Perl module Digest::MD5 version 2.09 is installed" >&5
+  if $PERL ./config/check_for_perl_mod Digest::MD5 2.09; then
     borp_cv_perl_digest_md5=yes
     
   else
@@ -1647,9 +1690,9 @@
 
 
 
-  echo $ac_n "checking if Perl module Math::Interpolate version 1.04 is installed""... $ac_c" 1>&6
-echo "configure:1652: checking if Perl module Math::Interpolate version 1.04 is installed" >&5
-  if $PERL ./config/check_for_perl_mod Math::Interpolate 1.04; then
+  echo $ac_n "checking if Perl module Math::Interpolate version 1.05 is installed""... $ac_c" 1>&6
+echo "configure:1695: checking if Perl module Math::Interpolate version 1.05 is installed" >&5
+  if $PERL ./config/check_for_perl_mod Math::Interpolate 1.05; then
     borp_cv_perl_math_interpolate=yes
     
   else
@@ -1672,9 +1715,9 @@
 
 
 
-  echo $ac_n "checking if Perl module RRDs version 1.000072 is installed""... $ac_c" 1>&6
-echo "configure:1677: checking if Perl module RRDs version 1.000072 is installed" >&5
-  if $PERL ./config/check_for_perl_mod RRDs 1.000072; then
+  echo $ac_n "checking if Perl module RRDs version 1.000131 is installed""... $ac_c" 1>&6
+echo "configure:1720: checking if Perl module RRDs version 1.000131 is installed" >&5
+  if $PERL ./config/check_for_perl_mod RRDs 1.000131; then
     borp_cv_perl_rdds=yes
     
   else
@@ -1697,9 +1740,9 @@
 
 
 
-  echo $ac_n "checking if Perl module Storable version 0.603 is installed""... $ac_c" 1>&6
-echo "configure:1702: checking if Perl module Storable version 0.603 is installed" >&5
-  if $PERL ./config/check_for_perl_mod Storable 0.603; then
+  echo $ac_n "checking if Perl module Storable version 0.609 is installed""... $ac_c" 1>&6
+echo "configure:1745: checking if Perl module Storable version 0.609 is installed" >&5
+  if $PERL ./config/check_for_perl_mod Storable 0.609; then
     borp_cv_perl_storable=yes
     
   else
@@ -1732,7 +1775,7 @@
 #	Generate the Makefiles and shell scripts with the
 #	variable substitutions.
 #--------------------------------------------------------------------
-if test "$BUILD_ORCALLATOR" = "yes"; then
+if test "$BUILD_ORCALLATOR" = yes; then
   ORCALLATOR_OUTPUT="orcallator/orcallator.cfg
                      orcallator/orcallator_running.pl
                      orcallator/restart_orcallator.sh
@@ -1933,13 +1976,15 @@
 s%@AWK@%$AWK%g
 s%@PERL@%$PERL%g
 s%@PERL_HEAD@%$PERL_HEAD%g
+s%@PS@%$PS%g
+s%@PS_SELF@%$PS_SELF%g
+s%@SE@%$SE%g
 s%@UNAME@%$UNAME%g
 s%@UNCOMPRESS@%$UNCOMPRESS%g
 s%@COMPRESSOR@%$COMPRESSOR%g
 s%@UNCOMPRESSOR_PIPE@%$UNCOMPRESSOR_PIPE%g
 s%@ORCALLATOR_SUBDIR@%$ORCALLATOR_SUBDIR%g
 s%@INSTALL_LIB_RRDTOOL@%$INSTALL_LIB_RRDTOOL%g
-s%@SE@%$SE%g
 s%@MAKE_COMPRESS_ZLIB@%$MAKE_COMPRESS_ZLIB%g
 s%@TEST_COMPRESS_ZLIB@%$TEST_COMPRESS_ZLIB%g
 s%@INSTALL_PERL_COMPRESS_ZLIB@%$INSTALL_PERL_COMPRESS_ZLIB%g
@@ -2088,14 +2133,17 @@
 test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
 
 
-command="(cd packages/$RRDTOOL_DIR; ./configure $CONFIGURE_COMMAND_LINE --cache-file=../../config.cache)"
-echo ""
-echo "Running configure in packages/$RRDTOOL_DIR to create RRDtool and RRDs.pm."
-echo ""
-echo $command
-echo ""
-eval $command
+# Build the RRDtool library if it is needed.
+if test "$borp_cv_perl_rdds" = no; then
+  command="(cd packages/$RRDTOOL_DIR; ./configure $CONFIGURE_COMMAND_LINE --cache-file=../../config.cache)"
+  echo ""
+  echo "Running configure in packages/$RRDTOOL_DIR to create RRDtool and RRDs.pm."
+  echo ""
+  echo $command
+  echo ""
+  eval $command
+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
+  echo "configure: warning: *** Unless you use a --with-*-log option orcallator will not gather WWW log data." 1>&2
 fi

Modified: trunk/orca/orcallator/orcallator.cfg.in
==============================================================================
--- trunk/orca/orcallator/orcallator.cfg.in	(original)
+++ trunk/orca/orcallator/orcallator.cfg.in	Sat Jul 13 21:07:50 2002
@@ -34,8 +34,21 @@
 warn_email		root at localhost
 late_interval		interval + 30
 
-# This defines where the find the source data files and the format of those
-# files.
+# This defines where the find the source data files and the format of
+# those files.  Notes about the fields:
+# find_files
+#   You'll notice that all but the first () has the form (?:...).
+#   This tells Perl to match the expression but not save the matched
+#   text in the $1, $2, variables.  Orca uses the matched text to
+#   generate a subgroup name, which is used to place files into
+#   different subgroups.  Here, only the hostname should be used to
+#   generate a subgroup name, hence all the (?:...) for matching
+#   anything else.
+# interval
+#   The interval here must match the interval used by orcallator to
+#   record data.  Do not change this, as it has an effect on the
+#   generated RRD data files.
+
 group orcallator {
 find_files		@ORCALLATOR_DIR@/(.*)/(?:(?:orcallator)|(?:percol))-\d{4}-\d{2}-\d{2}(?:\.(?:Z|gz|bz2))?
 column_description	first_line
@@ -43,6 +56,16 @@
 date_format		%s
 interval		300
 reopen			1
+filename_compare	sub {
+			  my ($ay, $am, $ad) = $a =~ /-(\d{4})-(\d\d)-(\d\d)/;
+			  my ($by, $bm, $bd) = $b =~ /-(\d{4})-(\d\d)-(\d\d)/;
+			  if (my $c = (( $ay       <=>  $by) ||
+			               ( $am       <=>  $bm) ||
+			               (($ad >> 3) <=> ($bd >> 3)))) {
+			    return 2*$c;
+			  }
+			  $ad <=> $bd;
+			}
 }
 
 html_top_title		Yahoo!/GeoCities Host Status
@@ -486,14 +509,54 @@
 }
 
 plot {
-title			%g NFS Call Rate
+title			%g NFS Server Call Rate
+source			orcallator
+data			nfss_calls
+data			v2reads
+data			v2writes
+data			v3reads
+data			v3writes
+data			nfss_bad
+data_type		counter
+line_type		area
+line_type		area
+line_type		stack
+line_type		stack
+line_type		stack
+line_type		stack
+legend			NFS server calls/s
+y_legend		NFS Server Calls/s
+data_min		0
+href			http://www.gps.caltech.edu/~blair/orca/docs/orcallator.html#NFS_server_call_rate
+}
+
+plot {
+title			%g NFS Server Call Distribution
+source			orcallator
+data			v2reads
+data			v2writes
+data			v3reads
+data			v3writes
+data_type		counter
+line_type		area
+line_type		stack
+line_type		stack
+line_type		stack
+line_type		stack
+y_legend		NFS Server Calls/s
+data_min		0
+href			http://www.gps.caltech.edu/~blair/orca/docs/orcallator.html#NFS_server_call_distribution
+}
+
+plot {
+title			%g NFS Client Call Rate
 source			orcallator
 data			nfs_call/s
 line_type		area
-legend			NFS calls/s
-y_legend		NFS Calls/s
+legend			NFS client calls/s
+y_legend		NFS Client Calls/s
 data_min		0
-href			http://www.gps.caltech.edu/~blair/orca/docs/orcallator.html#NFS_call_rate
+href			http://www.gps.caltech.edu/~blair/orca/docs/orcallator.html#NFS_client_call_rate
 }
 
 plot {
@@ -541,7 +604,7 @@
 plot {
 title			%g Disk Run Percent
 source			orcallator
-data			disk_runp_(c\d+t\d+d\d+)
+data			disk_runp_((?:c\d+t\d+d\d+)|(?:md\d+))
 line_type		line2
 legend			$1
 y_legend		Run Percent

Modified: trunk/orca/orcallator/orcallator.se
==============================================================================
--- trunk/orca/orcallator/orcallator.se	(original)
+++ trunk/orca/orcallator/orcallator.se	Sat Jul 13 21:07:51 2002
@@ -8,6 +8,33 @@
 //
 // Portions copied from percollator.se written by Adrian Cockroft.
 //
+// Version 1.23: Feb 25, 2000	When orcallator was running on a system with
+//				DiskSuite, the same physical disk was listed
+//				multiple times when it appeared in the same
+//				metadevice.  The solution to the problem is
+//				not to build the c0t0d0 name but use the long
+//				disk name provided by the long_name string.
+//				Patch contributed by Paul Haldane
+//				<Paul.Haldane at newcastle.ac.uk>.
+// Version 1.22: Jan 14, 2000	Include code to record NFS v2 and v3 server
+//				statistics.  The new statistics are: nfss_calls,
+//				the number of NFS calls to the NFS server,
+//				nfss_bad, the number of bad NFS calls per
+//				second, and v{2,3}{reads,writes}, which are
+//				nfss_calls broken down into NFS version 2 and
+//				NFS version 3 calls.  The sum of v{2,3}{reads,
+//				writes} will be less than nfss_calls as the
+//				other types of NFS calls, such as getattr and
+//				lookup, are not included.  Contributed by Paul
+//				Haldane <Paul.Haldane at newcastle.ac.uk>.  This
+//				code is enabled by the standard -DWATCH_OS or
+//				individually by -DWATCH_NFS_SERVER.  The
+//				define -DWATCH_NFS has been supperseded by
+//				-DWATCH_NFS_CLIENT, but to keep backwards
+//				compatibility, -DWATCH_NFS_CLIENT will be
+//				defined if -DWATCH_NFS is defined.
+// Version 1.21: Jan 12, 2000	Prevent core dumps on extremely long access
+//				log lines.
 // Version 1.20: Oct 20, 1999	Update my email address.
 // Version 1.19: Oct 13, 1999	Prevent a division by zero in calculating the
 //				mean_disk_busy if the number of disks on the
@@ -90,7 +117,8 @@
 #define WATCH_MUTEX		1
 #define WATCH_NET		1
 #define WATCH_TCP		1
-#define WATCH_NFS		1
+#define WATCH_NFS_CLIENT	1
+#define WATCH_NFS_SERVER	1
 #define WATCH_MOUNTS		1
 #define WATCH_DISK		1
 #define WATCH_DNLC		1
@@ -104,6 +132,13 @@
 #define WATCH_WEB		1
 #endif
 
+// Keep backwards compatibility with WATCH_NFS.
+#ifdef WATCH_NFS
+#ifndef WATCH_NFS_CLIENT
+#define WATCH_NFS_CLIENT	1
+#endif
+#endif
+
 #include <stdio.se>
 #include <stdlib.se>
 #include <unistd.se>
@@ -142,18 +177,18 @@
 // particular size.  This saves the overhead of a function call.
 #define WWW_SIZE_INDEX(size, size_index)			\
   if (size < 1024) {						\
-    size_index=0;		/* under 1KB   */		\
+    size_index=0;		/* Under 1KB   */		\
   } else {							\
     if (size < 10240) {						\
-      size_index=1;		/* under 10K   */		\
+      size_index=1;		/* Under 10K   */		\
     } else {							\
       if (size < 102400) {					\
-        size_index=2;		/* under 100KB */		\
+        size_index=2;		/* Under 100KB */		\
       } else {							\
         if (size < 1048576) {					\
-          size_index=3;		/* under 1MB   */		\
+          size_index=3;		/* Under 1MB   */		\
         } else {						\
-          size_index=4;		/* over 1MB    */		\
+          size_index=4;		/* Over 1MB    */		\
         }							\
       }								\
     }								\
@@ -162,36 +197,33 @@
 
 // Handle the reply code from the server.
 #define WWW_REPLY_CODE(word)					\
-  if (word != nil) {						\
-    if (word == "304") {					\
-      httpop_condgets++;					\
-    }								\
-    else {							\
-      first_byte = word;					\
-      if (first_byte[0] == '4' || first_byte[0] == '5') {	\
-        httpop_errors++;					\
-      }								\
+  if (word == "304") {						\
+    httpop_condgets++;						\
+  }								\
+  else {							\
+    first_byte = word;						\
+    if (first_byte[0] == '4' || first_byte[0] == '5') {		\
+      httpop_errors++;						\
     }								\
-  }
+  }								\
 
-// Handle the method of the object served.  This define only works with
-// non-proxy servers.
+// Handle the method of the object served.  This define only works
+// with non-proxy servers.
 #define WWW_METHOD1(word)					\
-  if (word != nil) {						\
-    switch (word) {						\
-      case "get":						\
-      case "GET":						\
-        httpop_gets++;						\
-        break;							\
-      case "post":						\
-      case "POST":						\
-        httpop_posts++;						\
-        break;							\
-      case "head":						\
-      case "HEAD":						\
-        ishead = 1;						\
-        httpop_condgets++;					\
-        break;
+  switch (word) {						\
+    case "get":							\
+    case "GET":							\
+      httpop_gets++;						\
+      break;							\
+    case "post":						\
+    case "POST":						\
+      httpop_posts++;						\
+      break;							\
+    case "head":						\
+    case "HEAD":						\
+      ishead = 1;						\
+      httpop_condgets++;					\
+      break;
 
 #ifdef WATCH_SQUID
 #define WWW_METHOD2						\
@@ -204,9 +236,8 @@
 #endif
 
 #define WWW_METHOD_END						\
-      default:							\
-        break; 							\
-    }								\
+    default:							\
+      break; 							\
   }
 #define WWW_METHOD(word) WWW_METHOD1(word) WWW_METHOD2 WWW_METHOD_END
 #endif
@@ -277,6 +308,15 @@
 mnttab_t	tmp_mnt;
 #endif
 
+#ifdef WATCH_NFS_SERVER
+ks_nfs_server	kstat$nfs;
+ks_nfs_server	tmp_nfs;
+ks_rfs_proc_v2	kstat$rfsproccnt_v2;
+ks_rfs_proc_v2	tmp_rfsproccnt_v2;
+ks_rfs_proc_v3	kstat$rfsproccnt_v3;
+ks_rfs_proc_v3	tmp_rfsproccnt_v3;
+#endif
+
 // Variables for handling the httpd access log.
 #ifdef WATCH_WEB
 string		www_search_url       = getenv("SEARCHURL");
@@ -289,7 +329,7 @@
 ulong		www_ino;
 long		www_size;
 
-double		www_interval;			// Hi-res interval time.
+double		www_interval;		// Hi-res interval time.
 ulonglong	www_then;
 ulonglong	www_now;
 
@@ -309,23 +349,23 @@
 long		httpop_searches;
 long		httpop_errors;
 long		dwnld_size[5]; // [0] < 1K, [1] < 10K, [2] < 100K, [3] < 1M, [4] >= 1M
-long		dwnld_totalz;  // total size counted from log
+long		dwnld_totalz;  // Total size counted from log.
 
 #if WATCH_PROXY || WATCH_SQUID || WATCH_YAHOO
 // If we're watching a Yahoo log, then take the transfer time to be the
 // processing time.
-double		www_dwnld_time_sum;	   // transfer time
-double		www_dwnld_time_by_size[5]; // mean transfer time by size bin
+double		www_dwnld_time_sum;	   // Transfer time.
+double		www_dwnld_time_by_size[5]; // Mean transfer time by size bin.
 #endif
 #if WATCH_PROXY || WATCH_SQUID
-long		prxy_squid_indirect;   // number of hits that go via PROXY,SOCKS,parent
-long		prxy_squid_cache_hits; // number of hits returned from cache
+long		prxy_squid_indirect;   // # hits that go via PROXY,SOCKS,parent
+long		prxy_squid_cache_hits; // # hits returned from cache.
 #endif
 
 #ifdef WATCH_PROXY
-long		prxy_cache_writes; // number of writes and updates to cache
-long		prxy_uncacheable;  // number of explicitly uncacheable httpops
-				   // any extra is errors or incomplete ops
+long		prxy_cache_writes; // Number of writes and updates to cache.
+long		prxy_uncacheable;  // Number of explicitly uncacheable httpops.
+				   // Any extra is errors or incomplete ops.
 #endif
 
 #ifdef WATCH_SQUID
@@ -455,21 +495,22 @@
       fprintf(stderr, "   setenv SEARCHURL   srch.cgi - match for search scripts, default is search.cgi\n");
       fprintf(stderr, "   setenv COMPRESSOR  \"gzip -9\" - compress previous day logs using this command\n");
       fprintf(stderr, "Defines:\n");
-      fprintf(stderr, "   -DWATCH_WEB    watch web server access logs\n");
-      fprintf(stderr, "   -DWATCH_PROXY  use WEB_LOG as a NCSA style proxy log\n");
-      fprintf(stderr, "   -DWATCH_SQUID  use WEB_LOG as a Squid log\n");
-      fprintf(stderr, "   -DWATCH_OS     includes all of the below:\n");
-      fprintf(stderr, "   -DWATCH_CPU    watch the cpu load, run queue, etc\n");
-      fprintf(stderr, "   -DWATCH_MUTEX  watch the number of mutex spins\n");
-      fprintf(stderr, "   -DWATCH_NET    watch all Ethernet interfaces\n");
-      fprintf(stderr, "   -DWATCH_TCP    watch all the TCP/IP stack\n");
-      fprintf(stderr, "   -DWATCH_NFS    watch NFS requests\n");
-      fprintf(stderr, "   -DWATCH_MOUNTS watch usage of mount points\n");
-      fprintf(stderr, "   -DWATCH_DISK   watch disk read/write usage\n");
-      fprintf(stderr, "   -DWATCH_DNLC   watch the directory name lookup cache\n");
-      fprintf(stderr, "   -DWATCH_INODE  watch the inode cache\n");
-      fprintf(stderr, "   -DWATCH_RAM    watch memory usage\n");
-      fprintf(stderr, "   -DWATCH_PAGES  watch where pages are allocated\n");
+      fprintf(stderr, "   -DWATCH_WEB        watch web server access logs\n");
+      fprintf(stderr, "   -DWATCH_PROXY      use WEB_LOG as a NCSA style proxy log\n");
+      fprintf(stderr, "   -DWATCH_SQUID      use WEB_LOG as a Squid log\n");
+      fprintf(stderr, "   -DWATCH_OS         includes all of the below:\n");
+      fprintf(stderr, "   -DWATCH_CPU        watch the cpu load, run queue, etc\n");
+      fprintf(stderr, "   -DWATCH_MUTEX      watch the number of mutex spins\n");
+      fprintf(stderr, "   -DWATCH_NET        watch all Ethernet interfaces\n");
+      fprintf(stderr, "   -DWATCH_TCP        watch all the TCP/IP stack\n");
+      fprintf(stderr, "   -DWATCH_NFS_CLIENT watch NFS client requests\n");
+      fprintf(stderr, "   -DWATCH_NFS_SERVER watch NFS server requests\n");
+      fprintf(stderr, "   -DWATCH_MOUNTS     watch usage of mount points\n");
+      fprintf(stderr, "   -DWATCH_DISK       watch disk read/write usage\n");
+      fprintf(stderr, "   -DWATCH_DNLC       watch the directory name lookup cache\n");
+      fprintf(stderr, "   -DWATCH_INODE      watch the inode cache\n");
+      fprintf(stderr, "   -DWATCH_RAM        watch memory usage\n");
+      fprintf(stderr, "   -DWATCH_PAGES      watch where pages are allocated\n");
       exit(1);
       break;
   }
@@ -603,24 +644,29 @@
 // Measure the system statistics all at once.
 _measure_os()
 {
-  tmp_lrcpu       = lr_cpu$cpu;
-  tmp_mutex       = lr_mutex$m;
-  tmp_nr          = lr_net$nr;
-  tmp_lrtcp       = lr_tcp$tcp;
+  tmp_lrcpu         = lr_cpu$cpu;
+  tmp_mutex         = lr_mutex$m;
+  tmp_nr            = lr_net$nr;
+  tmp_lrtcp         = lr_tcp$tcp;
 #ifdef WATCH_TCP
-  tmp_tcp         = tcp$tcp;
+  tmp_tcp           = tcp$tcp;
 #endif
-  tmp_lrpcc       = lr_rpcclient$r;
-  tmp_dr          = lr_disk$dr;
-  tmp_lrdnlc      = lr_dnlc$dnlc;
-  tmp_lrinode     = lr_inode$inode;
-  tmp_lrram       = lr_ram$ram;
+  tmp_lrpcc         = lr_rpcclient$r;
+  tmp_dr            = lr_disk$dr;
+  tmp_lrdnlc        = lr_dnlc$dnlc;
+  tmp_lrinode       = lr_inode$inode;
+  tmp_lrram         = lr_ram$ram;
 #ifdef WATCH_PAGES
-  tmp_kstat_pages = kstat$pages;
+  tmp_kstat_pages   = kstat$pages;
+#endif
+  tmp_lrswap        = lr_swapspace$s;
+  tmp_lrkmem        = lr_kmem$kmem;
+  tmp_kstat_misc    = kstat$misc;
+#ifdef WATCH_NFS_SERVER
+  tmp_nfs           = kstat$nfs;
+  tmp_rfsproccnt_v2 = kstat$rfsproccnt_v2;
+  tmp_rfsproccnt_v3 = kstat$rfsproccnt_v3;
 #endif
-  tmp_lrswap      = lr_swapspace$s;
-  tmp_lrkmem      = lr_kmem$kmem;
-  tmp_kstat_misc  = kstat$misc;
 }
 
 measure_os(long now, tm_t tm_now)
@@ -666,9 +712,14 @@
   measure_tcp();
 #endif
 
-  // Take care of NFS.
-#ifdef WATCH_NFS
-  measure_nfs();
+  // Take care of NFS client statistics.
+#ifdef WATCH_NFS_CLIENT
+  measure_nfs_client();
+#endif
+
+  // Take care of NFS server statistics.
+#ifdef WATCH_NFS_SERVER
+  measure_nfs_server();
 #endif
 
   // Take care of DNLC.
@@ -687,16 +738,18 @@
 #endif
 }
 
-/* state as a character */
+/*
+ * State as a character
+ */
 char state_char(int state) {
   switch(state) {
-    case ST_WHITE: return 'w'; /* OK states are lower case */
+    case ST_WHITE: return 'w'; /* OK states are lower case. */
     case ST_BLUE:  return 'b';
     case ST_GREEN: return 'g';
-    case ST_AMBER: return 'A'; /* bad states are upper case to stand out */
+    case ST_AMBER: return 'A'; /* Bad states are upper case to stand out. */
     case ST_RED:   return 'R';
     case ST_BLACK: return 'B';
-    default: return 'I';	/* invalid state */
+    default:       return 'I'; /* Invalid state. */
   }
 }
 
@@ -889,8 +942,8 @@
 }
 #endif
 
-#ifdef WATCH_NFS
-measure_nfs()
+#ifdef WATCH_NFS_CLIENT
+measure_nfs_client()
 {
   put_output("nfs_call/s", sprintf("%10.3f", tmp_lrpcc.calls));
   put_output("nfs_timo/s", sprintf("%10.3f", tmp_lrpcc.timeouts));
@@ -898,6 +951,32 @@
 }
 #endif
 
+#ifdef WATCH_NFS_SERVER
+measure_nfs_server()
+{
+  ulong calls;
+  ulong badcalls;
+  ulong v2read;
+  ulong v2write;
+  ulong v3read;
+  ulong v3write;
+
+  calls    = tmp_nfs.calls;
+  badcalls = tmp_nfs.badcalls;
+  v2read   = tmp_rfsproccnt_v2.read;
+  v2write  = tmp_rfsproccnt_v2.write;
+  v3read   = tmp_rfsproccnt_v3.read;
+  v3write  = tmp_rfsproccnt_v3.write;
+
+  put_output("nfss_calls", sprintf("%10lu", calls));
+  put_output("nfss_bad",   sprintf("%8lu", badcalls));
+  put_output(" v2reads",   sprintf("%8lu", v2read));
+  put_output("v2writes",   sprintf("%8lu", v2write));
+  put_output(" v3reads",   sprintf("%8lu", v3read));
+  put_output("v3writes",   sprintf("%8lu", v3write));
+}
+#endif
+
 #ifdef WATCH_MOUNTS
 measure_mounts()
 {
@@ -998,10 +1077,7 @@
   total_readk    = 0.0;
   total_writek   = 0.0;
   for (i=0; i<GLOBAL_disk_count; i++) {
-    put_output(sprintf("disk_runp_c%dt%dd%d",
-               GLOBAL_disk[i].info.controller,
-               GLOBAL_disk[i].info.target,
-               GLOBAL_disk[i].info.device),
+    put_output(sprintf("disk_runp_%s", GLOBAL_disk[i].info.long_name),
                sprintf("%16.5f", GLOBAL_disk[i].run_percent));
     total_reads     += GLOBAL_disk[i].reads;
     total_writes    += GLOBAL_disk[i].writes;
@@ -1071,7 +1147,9 @@
 #endif
 
 #ifdef WATCH_WEB
-// Breakdown access log format.
+/*
+ * Breakdown access log format.
+ */
 accesslog(string buf) {
   int     z;
   int     size_index;
@@ -1095,54 +1173,39 @@
 
   ishead = 0;
 #ifdef WATCH_YAHOO
-  // Make sure that the input line has at least 32 bytes of data plus a new
-  // line, for a total length of 33.
+  /*
+   * Make sure that the input line has at least 32 bytes of data plus a new
+   * line, for a total length of 33.
+   */
   if (strlen(buf) < 33) {
     return;
   }
-  word = strtok(buf,"\05");
+  word = strtok(buf, "\05");
 #else
-  word = strtok(buf," ");
+  word = strtok(buf, " ");
 #endif
   if (word == nil) {
     return;
   }
 
 #ifdef WATCH_SQUID
-  // Word contains unix time in seconds.milliseconds.
-  word                = strtok(nil, " ");	// Elapsed request time in ms
-  xf                  = atof(word)/1000.0;
+  /*
+   * Word contains unix time in seconds.milliseconds.
+   */
+  word = strtok(nil, " ");
+  if (word == nil) {
+    return;
+  }
+  xf = atof(word)/1000.0;
   www_dwnld_time_sum += xf;
 #ifdef DINKY
   printf("time: %s %f total %f\n", word, xf, xfer_sum);
 #endif
-  word    = strtok(nil, " ");			// Client IP address
-  logtag  = strtok(nil, "/");			// Log tag
-  word    = strtok(nil, " ");			// Reply code
-  WWW_REPLY_CODE(word)
-  word    = strtok(nil, " ");			// Size sent to client
-  z       = atoi(word);
-  request = strtok(nil, " ");			// Request method
-  word    = strtok(nil, " ");			// URL
-  if (word != nil) {
-    if (word =~ "cgi-bin") {
-      httpop_cgi_bins++;
-    }
-    if (word =~ www_search_url) {
-      httpop_searches++;
-    }
-  }
-  word = strtok(nil, " ");			// Optional user ident
-  word = strtok(nil, "/");			// Hierarchy
-  if (word != nil) {
-    if (word =~ "DIRECT") {
-      prxy_squid_indirect++;
-    }
+  word   = strtok(nil, " ");			/* Client IP address.      */
+  logtag = strtok(nil, "/");			/* Log tag.                */
+  if (logtag == nil) {
+    return;
   }
-  word = strtok(nil, " ");			// Hostname
-  word = strtok(nil, " ");			// Content-type
-
-  // Process the collected data.
   if (logtag =~ "TCP") {
     squid_client_http++;
   }
@@ -1155,37 +1218,84 @@
   if (logtag =~ "MISS") {
     squid_cache_misses++;
   }
-  WWW_METHOD(request)
 
-  // Do not add size if its a HEAD.
+  word = strtok(nil, " ");			/* Reply code.             */
+  if (word == nil) {
+    return;
+  }
+  WWW_REPLY_CODE(word)
+  word = strtok(nil, " ");			/* Size sent to client.    */
+  if (word == nil) {
+    return;
+  }
+  z = atoi(word);
+  WWW_SIZE_INDEX(z, size_index)
+  www_dwnld_time_by_size[size_index] += xf;
+
+  request = strtok(nil, " ");			/* Request method.         */
+  if (request == nil) {
+    return;
+  }
+  WWW_METHOD(request)
+  /* Do not add the size if it is a HEAD. */
   if (ishead == 0) {
     dwnld_totalz += z;
   }
 
-  WWW_SIZE_INDEX(z, size_index)
-  www_dwnld_time_by_size[size_index] += xf;
+  word = strtok(nil, " ");			/* URL.                    */
+  if (word == nil) {
+    return;
+  }
+  if (word =~ "cgi-bin") {
+    httpop_cgi_bins++;
+  }
+  if (word =~ www_search_url) {
+    httpop_searches++;
+  }
+  strtok(nil, " ");				/* Optional user identity. */
+  word = strtok(nil, "/");			/* Hierarchy.              */
+  if (word == nil) {
+    return;
+  }
+  if (word =~ "DIRECT") {
+    prxy_squid_indirect++;
+  }
+#if 0
+  word = strtok(nil, " ");			/* Hostname.               */
+  if (word == nil) {
+    return;
+  }
+  word = strtok(nil, " ");			/* Content-type.           */
+  if (word == nil) {
+    return;
+  }
+#endif
 
 #elif WATCH_YAHOO
-  // Yahoo log format.  Fields in square brackets will only appear in the
-  // log file if the data actually exists (ie. you will never see a null
-  // Referrer field).  Further, fields labelled here with "(CONFIG)" will
-  // only appear if they are enabled via the YahooLogOptions configuration
-  // directive.
-  //
-  //     IP Address		(8 hex digits)
-  //     Timestamp		(time_t as 8 hex digits)
-  //     Processing Time	(in microseconds, as 8 hex digits)
-  //     Bytes Sent		(8 hex digits)
-  //     URL
-  //     [^Er referrer]  (CONFIG)
-  //     [^Em method]    (CONFIG)
-  //     [^Es status_code]
-  //     ^Ed signature
-  //     \n
-
-  // Ignore the IP address and timestamp.  Get the processing time, the
-  // number of bytes sent and the URL.  For each portion of the line, split
-  // it up into separate pieces.
+  /*
+   * Yahoo log format.  Fields in square brackets will only appear in the
+   * log file if the data actually exists (ie. you will never see a null
+   * Referrer field).  Further, fields labelled here with "(CONFIG)" will
+   * only appear if they are enabled via the YahooLogOptions configuration
+   * directive.
+   *
+   *     IP Address		(8 hex digits)
+   *     Timestamp		(time_t as 8 hex digits)
+   *     Processing Time	(in microseconds, as 8 hex digits)
+   *     Bytes Sent		(8 hex digits)
+   *     URL
+   *     [^Er referrer]  (CONFIG)
+   *     [^Em method]    (CONFIG)
+   *     [^Es status_code]
+   *     ^Ed signature
+   *     \n
+   */
+
+  /*
+   * Ignore the IP address and timestamp.  Get the processing time, the
+   * number of bytes sent and the URL.  For each portion of the line, split
+   * it up into separate pieces.
+   */
   if (sscanf(word, "%8lx%8lx%8x%8x", &tmp, &tmp, &ulong_xf, &z) != 4) {
     return;
   }
@@ -1224,98 +1334,117 @@
     }
   }
 
-  // If no method was seen, then assume it was a GET.
+  /* If no method was seen, then assume it was a GET. */
   if (ptr == 0) {
     httpop_gets++;
   }
 
-  // Do not add size if its a HEAD.
+  /* Do not add the size if it is a HEAD. */
   if (ishead == 0) {
     dwnld_totalz += z;
   }
   
 #else	/* common or netscape proxy formats */
-  strtok(nil, " ");		// -
-  strtok(nil, " ");		// -
-  strtok(nil, " [");		// date
-  strtok(nil, " ");		// zone]
-  word = strtok(nil, " \"");	// GET or POST
+  strtok(nil, " ");		/* -.           */
+  strtok(nil, " ");		/* -.           */
+  strtok(nil, " [");		/* date.        */
+  strtok(nil, " ");		/* zone].       */
+  strtok(nil, " \"");		/* GET or POST. */
+  if (word == nil) {
+    return;
+  }
   WWW_METHOD(word)
-  word = strtok(nil, " ");	// URL
-  if (word != nil) {
-    if (word =~ "cgi-bin") {
-      httpop_cgi_bins++;
-    }
-    if (word =~ www_search_url) {
-      httpop_searches++;
-    }
+  word = strtok(nil, " ");	/* URL.         */
+  if (word == nil) {
+    return;
   }
-  // Sometimes HTTP/1.x is not listed in the access log.  Skip it
-  // if it does exist.  Load the error/success code.
+  if (word =~ "cgi-bin") {
+    httpop_cgi_bins++;
+  }
+  if (word =~ www_search_url) {
+    httpop_searches++;
+  }
+  /*
+   * Sometimes HTTP/1.x is not listed in the access log.  Skip it
+   * if it does exist.  Load the error/success code.
+   */
   word = strtok(nil, " ");
-  if (word != nil && (word =~ "HTTP" || word =~ "http")) {
+  if (word == nil) {
+    return;
+  }
+  if (word =~ "HTTP" || word =~ "http") {
     word = strtok(nil, " ");
+    if (word == nil) {
+      return;
+    }
   }
   WWW_REPLY_CODE(word)
-  word = strtok(nil, " ");	// Bytes transferred.
-  if (word != nil) {
-    z = atoi(word);
-    if (ishead == 0) {		// Do not add size if its a HEAD.
-      dwnld_totalz += z;
-    }
-    WWW_SIZE_INDEX(z, size_index)
+  word = strtok(nil, " ");	/* Bytes transferred. */
+  if (word == nil) {
+    return;
+  }
+  z = atoi(word);
+  /* Do not add the size if it is a HEAD. */
+  if (ishead == 0) {
+    dwnld_totalz += z;
   }
+  WWW_SIZE_INDEX(z, size_index)
 #ifdef WATCH_PROXY
-  word = strtok(nil, " ");	// status from server
-  word = strtok(nil, " ");	// length from server
-  word = strtok(nil, " ");	// length from client POST
-  word = strtok(nil, " ");	// length POSTed to remote
-  word = strtok(nil, " ");	// client header req
-  word = strtok(nil, " ");	// proxy header resp
-  word = strtok(nil, " ");	// proxy header req
-  word = strtok(nil, " ");	// server header resp
-  word = strtok(nil, " ");	// transfer total secs
-  word = strtok(nil, " ");	// route
-
-  // - DIRECT PROXY(host.domain:port) SOCKS
-  if (word != nil) {  
-    if (strncmp(word, "PROXY", 5) == 0 ||
-        strncmp(word, "SOCKS", 5) == 0) {
-      prxy_squid_indirect++;
-    }
+  strtok(nil, " ");		/* Status from server.      */
+  strtok(nil, " ");		/* Length from server.      */
+  strtok(nil, " ");		/* Length from client POST. */
+  strtok(nil, " ");		/* Length POSTed to remote. */
+  strtok(nil, " ");		/* Client header request.   */
+  strtok(nil, " ");		/* Proxy header response.   */
+  strtok(nil, " ");		/* Proxy header request.    */
+  strtok(nil, " ");		/* Server header response.  */
+  strtok(nil, " ");		/* Transfer total seconds.  */
+  word = strtok(nil, " ");	/* Route.                   */
+  if (word == nil) {
+    return;
   }
-  word = strtok(nil, " ");	// client finish status
-  word = strtok(nil, " ");	// server finish status
-  word = strtok(nil, " ");	// cache finish status
-  // ERROR HOST-NOT-AVAILABLE = error or incomplete op
-  // WRITTEN REFRESHED CL-MISMATCH(content length mismatch) = cache_writes
-  // NO-CHECK UP-TO-DATE = cache_hits
-  // DO-NOT-CACHE NON-CACHEABLE = uncacheable
-  if (word != nil) { 
-    switch(word) {
-      case "WRITTEN":
-      case "REFRESHED":
-      case "CL-MISMATCH":
-        prxy_cache_writes++;
-        break;
-      case "NO-CHECK":
-      case "UP-TO-DATE":
-        prxy_squid_cache_hits++;
-        break;
-      case "DO-NOT-CACHE":
-      case "NON-CACHEABLE":
-        prxy_uncacheable++;
-        break;
-      default:
-        break;
-    }
+
+  /* - DIRECT PROXY(host.domain:port) SOCKS. */
+  if (strncmp(word, "PROXY", 5) == 0 ||
+      strncmp(word, "SOCKS", 5) == 0) {
+    prxy_squid_indirect++;
+  }
+  strtok(nil, " ");		/* Client finish status.    */
+  strtok(nil, " ");		/* Server finish status.    */
+  word = strtok(nil, " ");	/* Cache finish status.     */
+  if (word == nil) {
+    return;
   }
-  word = strtok(nil, " [");		// [transfer total time x.xxx
-  if (word != nil) {
-    xf = atof(word);
-    www_dwnld_time_sum                 += xf;
-    www_dwnld_time_by_size[size_index] += xf;
+  /*
+   * ERROR HOST-NOT-AVAILABLE = error or incomplete op
+   * WRITTEN REFRESHED CL-MISMATCH(content length mismatch) = cache_writes
+   * NO-CHECK UP-TO-DATE = cache_hits
+   * DO-NOT-CACHE NON-CACHEABLE = uncacheable
+   */
+  switch(word) {
+    case "WRITTEN":
+    case "REFRESHED":
+    case "CL-MISMATCH":
+      prxy_cache_writes++;
+      break;
+    case "NO-CHECK":
+    case "UP-TO-DATE":
+      prxy_squid_cache_hits++;
+      break;
+    case "DO-NOT-CACHE":
+    case "NON-CACHEABLE":
+      prxy_uncacheable++;
+      break;
+    default:
+      break;
   }
+  word = strtok(nil, " [");		/* [transfer total time x.xxx. */
+  if (word == nik) {
+    return;
+  }
+  xf = atof(word);
+  www_dwnld_time_sum                 += xf;
+  www_dwnld_time_by_size[size_index] += xf;
 #endif
 #endif
 }
@@ -1372,6 +1501,7 @@
 #endif
       now = time(0);
       if (www_fd != 0) {
+        buf[BUFSIZ-1] = 127;
         while (fgets(buf, BUFSIZ, www_fd) != nil) {
           httpops += 1.0;
           if (www_gatelen > 0) {
@@ -1380,19 +1510,38 @@
             }
           }
           accesslog(buf);
+
+          /*
+           * If the line is longer than the buffer, then ignore the rest
+           * of the line.
+           */
+          while (buf[BUFSIZ-1] == 0    &&
+                 buf[BUFSIZ-2] != '\n') {
+            buf[BUFSIZ-1] = 127;
+            if (fgets(buf, BUFSIZ, www_fd) == nil) {
+              break;
+            }
+          }
         }
       }
 
-      /* see if the file has been switched or truncated */
+      /*
+       * See if the file has been switched or truncated.
+       */
       stat(www_log_filename, www_stat);
       if (www_ino != www_stat[0].st_ino || www_size > www_stat[0].st_size) {
         if (www_fd != 0) {
-          fclose(www_fd); /* close the old log */
+          /* Close the old log file. */
+          fclose(www_fd);
         }
-        /* log file has changed, open the new one */
+
+        /*
+         * The log file has changed, open the new one.
+         */
         www_fd = fopen(www_log_filename, "r");
         if (www_fd != 0) {
           www_ino = www_stat[0].st_ino;
+          buf[BUFSIZ-1] = 127;
           while(fgets(buf, BUFSIZ, www_fd) != nil) {
             httpops += 1.0;
             if (www_gatelen > 0) {
@@ -1401,6 +1550,18 @@
               }
             }
             accesslog(buf);
+
+            /*
+             * If the line is longer than the buffer, then ignore the rest
+             * of the line.
+             */
+            while (buf[BUFSIZ-1] == 0    &&
+                   buf[BUFSIZ-2] != '\n') {
+              buf[BUFSIZ-1] = 127;
+              if (fgets(buf, BUFSIZ, www_fd) == nil) {
+                break;
+              }
+            }
           }
         }
       }
@@ -1414,7 +1575,7 @@
       }
       lastops = httpops;
 
-      // Remember size for next time.
+      /* Remember size for next time. */
       www_size = www_stat[0].st_size;
     }
   }
@@ -1427,7 +1588,9 @@
   www_interval = (www_now - www_then) * 0.000000001;
   www_then     = www_now;
 
-  // Use dtmp to get percentages.
+  /*
+   * Use dtmp to get percentages.
+   */
   if (httpops == 0.0) {
     dtmp = 0.0;
   }

Modified: trunk/orca/orcallator/start_orcallator.sh.in
==============================================================================
--- trunk/orca/orcallator/start_orcallator.sh.in	(original)
+++ trunk/orca/orcallator/start_orcallator.sh.in	Sat Jul 13 21:07:52 2002
@@ -48,7 +48,7 @@
 # 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."
+  echo "Orcallator already running.  Exiting."
   exit 1
 fi
 

Modified: trunk/orca/Makefile.in
==============================================================================
--- trunk/orca/Makefile.in	(original)
+++ trunk/orca/Makefile.in	Sat Jul 13 21:07:52 2002
@@ -50,8 +50,7 @@
 	$(RM) config.cache config.log config.status Makefile
 
 to-autoconf:
-	aclocal -I config --output=config/aclocal.m4
-	autoconf --localdir=config
+	aclocal -I config --output=config/aclocal.m4 && autoconf --localdir=config
 
 configure: configure.in
 	$(MAKE) to-autoconf

Modified: trunk/orca/TODO
==============================================================================
--- trunk/orca/TODO	(original)
+++ trunk/orca/TODO	Sat Jul 13 21:07:52 2002
@@ -1,3 +1,7 @@
+XXX Fix the bug where if a legend is listed in a plot {} then the
+XXX number of colored boxes in the generated plot are more than the
+XXX data that appears there.
+
 This is a pretty comprehensive to-do list for Orca and the related data
 gathering tools.  Any comments and additions to this list are welcome.
 

Modified: trunk/orca/configure.in
==============================================================================
--- trunk/orca/configure.in	(original)
+++ trunk/orca/configure.in	Sat Jul 13 21:07:52 2002
@@ -1,5 +1,5 @@
 # This file is an input file used by the GNU "autoconf" program to
-# generate the file "configure", which is run during Borp installation
+# generate the file "configure", which is run during Orca installation
 # to configure the system for the local environment.
 AC_INIT(src/orca.pl.in)
 AC_CONFIG_AUX_DIR(config)
@@ -17,8 +17,8 @@
 DATA_DUMPER_DIR=Data-Dumper-2.101
 DIGEST_MD5_DIR=Digest-MD5-2.09
 MATH_INTERPOLATE_DIR=Math-Interpolate-1.05
-RRDTOOL_DIR=rrdtool-1.0.7.2
-STORABLE_DIR=Storable-0.6.7
+RRDTOOL_DIR=rrdtool-1.0.13
+STORABLE_DIR=Storable-0.6.9
 AC_SUBST(COMPRESS_ZLIB_DIR)
 AC_SUBST(DATA_DUMPER_DIR)
 AC_SUBST(DIGEST_MD5_DIR)
@@ -161,7 +161,7 @@
 
 # Include the file that defines BORP_PERL_RUN.
 AC_PATH_PROG(PERL, perl, NOT_FOUND)
-if test "x$PERL" = "xNOT_FOUND"; then
+if test "x$PERL" = xNOT_FOUND; then
   AC_MSG_ERROR([*** Perl not found.  Please install Perl.  See INSTALL how to do this.])
 else
   BORP_PERL_RUN($PERL, PERL_HEAD=PerlHead1, PERL_HEAD=PerlHead2)
@@ -169,6 +169,32 @@
 PERL_HEAD="../config/$PERL_HEAD"
 AC_SUBST(PERL_HEAD)
 
+# Determine the correct ps command to use to find out about process
+# information for itself.
+AC_PATH_PROG(PS, ps)
+case "$target" in
+  *-solaris*)
+    PS_SELF="$PS -p PID -o \'rss vsz pmem time user pid comm\'"
+    ;;
+  *-linux-*)
+    PS_SELF="$PS auxp PID"
+    ;;
+  *)
+    PS_SELF="$PS aux | grep PID"
+    AC_MSG_WARN([*** If you know a better PS command than])
+    AC_MSG_WARN([***   '$PS_SELF'])
+    AC_MSG_WARN([*** to get process information for your host,])
+    AC_MSG_WARN([*** please email the command the the output from])
+    AC_MSG_WARN([*** ./config/config.guess to])
+    AC_MSG_WARN([*** orca-developers at onelist.com])
+    ;;
+esac
+if test "$PS_SELF"; then
+  AC_MSG_CHECKING([for ps command])
+  AC_MSG_RESULT($PS_SELF)
+  AC_SUBST(PS_SELF)
+fi
+AC_PATH_PROG(SE, se,,$PATH:/opt/RICHPse/bin)
 AC_PATH_PROG(UNAME, uname, uname)
 AC_PATH_PROG(UNCOMPRESS, uncompress)
 
@@ -189,49 +215,39 @@
 AC_SUBST(COMPRESSOR)
 AC_SUBST(UNCOMPRESSOR_PIPE)
 
-# Now we check for those portions of Orca that should be built and set
-# up for installation.  The first step is to check for operating system
-# specific modules.  For Solaris hosts, orcallator.se is built and
-# installed.  This requires the additional building of a librrd.so
-# installed in libdir.  Then we check for the proper Perl modules.
-AC_MSG_CHECKING([for solaris host for orcallator install])
-case "$target" in
-  *-solaris*)
-    BUILD_ORCALLATOR=yes
-    ORCALLATOR_SUBDIR=orcallator
-    # Add --enable-shared to the configure options for RRDtool if it is
-    # not already declared.
-    expr "$CONFIGURE_COMMAND_LINE" : "--enable-shared" >/dev/null 2>&1 || CONFIGURE_COMMAND_LINE="$CONFIGURE_COMMAND_LINE --enable-shared"
-
-    INSTALL_LIB_RRDTOOL=install_lib_rrdtool
-    MAKE_RRDTOOL=make_rrdtool
-    TEST_RRDTOOL=test_rrdtool
-    INSTALL_PERL_RRDTOOL=
-    CLEAN_RRDTOOL=clean_rrdtool
-    DISTCLEAN_RRDTOOL=distclean_rrdtool
-    ;;
-  *)
-    INSTALL_LIB_RRDTOOL=
-    BUILD_ORCALLATOR=no
-    ORCALLATOR_SUBDIR=
-    ;;
-esac
+# Always build the orcallator files regardless of the operating system.
+BUILD_ORCALLATOR=yes
+ORCALLATOR_SUBDIR=orcallator
+INSTALL_LIB_RRDTOOL=
 AC_SUBST(ORCALLATOR_SUBDIR)
 AC_SUBST(INSTALL_LIB_RRDTOOL)
 
-AC_MSG_RESULT($BUILD_ORCALLATOR)
-if test "$BUILD_ORCALLATOR" = "yes"; then
-  AC_PATH_PROG(SE, se,,$PATH:/opt/RICHPse/bin)
-fi
+# These commands can be used if the orcallator should not be built.
+# AC_MSG_CHECKING([for solaris host for orcallator install])
+# AC_MSG_RESULT($BUILD_ORCALLATOR)
+# BUILD_ORCALLATOR=no
+# ORCALLATOR_SUBDIR=
+
+# These commands can be used to force a build of the librrdtool library.
+# INSTALL_LIB_RRDTOOL=install_lib_rrdtool
+# MAKE_RRDTOOL=make_rrdtool
+# TEST_RRDTOOL=test_rrdtool
+# INSTALL_PERL_RRDTOOL=
+# CLEAN_RRDTOOL=clean_rrdtool
+# DISTCLEAN_RRDTOOL=distclean_rrdtool
+
+# This command can be used to add --enable-shared to the configure
+# options for RRDtool if it is not already declared.
+# expr "$CONFIGURE_COMMAND_LINE" : "--enable-shared" >/dev/null 2>&1 || CONFIGURE_COMMAND_LINE="$CONFIGURE_COMMAND_LINE --enable-shared"
 
 dnl BORP_PERL_MODULE(borp_cv_perl_compress_zlib, $PERL, Compress::Zlib, 1.05)
-if test "$borp_cv_perl_compress_zlib" = no; then
-  MAKE_COMPRESS_ZLIB=make_compress_zlib
-  TEST_COMPRESS_ZLIB=test_compress_zlib
-  INSTALL_PERL_COMPRESS_ZLIB=install_perl_compress_zlib
-  CLEAN_COMPRESS_ZLIB=clean_compress_zlib
-  DISTCLEAN_COMPRESS_ZLIB=distclean_compress_zlib
-fi
+dnl if test "$borp_cv_perl_compress_zlib" = no; then
+dnl   MAKE_COMPRESS_ZLIB=make_compress_zlib
+dnl   TEST_COMPRESS_ZLIB=test_compress_zlib
+dnl   INSTALL_PERL_COMPRESS_ZLIB=install_perl_compress_zlib
+dnl   CLEAN_COMPRESS_ZLIB=clean_compress_zlib
+dnl   DISTCLEAN_COMPRESS_ZLIB=distclean_compress_zlib
+dnl fi
 AC_SUBST(MAKE_COMPRESS_ZLIB)
 AC_SUBST(TEST_COMPRESS_ZLIB)
 AC_SUBST(INSTALL_PERL_COMPRESS_ZLIB)
@@ -252,7 +268,7 @@
 AC_SUBST(CLEAN_DATA_DUMPER)
 AC_SUBST(DISTCLEAN_DATA_DUMPER)
 
-BORP_PERL_MODULE(borp_cv_perl_digest_md5, $PERL, Digest::MD5, 2.00)
+BORP_PERL_MODULE(borp_cv_perl_digest_md5, $PERL, Digest::MD5, 2.09)
 if test "$borp_cv_perl_digest_md5" = no; then
   MAKE_DIGEST_MD5=make_digest_md5
   TEST_DIGEST_MD5=test_digest_md5
@@ -266,7 +282,7 @@
 AC_SUBST(CLEAN_DIGEST_MD5)
 AC_SUBST(DISTCLEAN_DIGEST_MD5)
 
-BORP_PERL_MODULE(borp_cv_perl_math_interpolate, $PERL, Math::Interpolate, 1.04)
+BORP_PERL_MODULE(borp_cv_perl_math_interpolate, $PERL, Math::Interpolate, 1.05)
 if test "$borp_cv_perl_math_interpolate" = no; then
   MAKE_MATH_INTERPOLATE=make_math_interpolate
   TEST_MATH_INTERPOLATE=test_math_interpolate
@@ -280,7 +296,7 @@
 AC_SUBST(CLEAN_MATH_INTERPOLATE)
 AC_SUBST(DISTCLEAN_MATH_INTERPOLATE)
 
-BORP_PERL_MODULE(borp_cv_perl_rdds, $PERL, RRDs, 1.000072)
+BORP_PERL_MODULE(borp_cv_perl_rdds, $PERL, RRDs, 1.000131)
 if test "$borp_cv_perl_rdds" = no; then
   MAKE_RRDTOOL=make_rrdtool
   TEST_RRDTOOL=test_rrdtool
@@ -294,7 +310,7 @@
 AC_SUBST(CLEAN_RRDTOOL)
 AC_SUBST(DISTCLEAN_RRDTOOL)
 
-BORP_PERL_MODULE(borp_cv_perl_storable, $PERL, Storable, 0.603)
+BORP_PERL_MODULE(borp_cv_perl_storable, $PERL, Storable, 0.609)
 if test "$borp_cv_perl_storable" = no; then
   MAKE_STORABLE=make_storable
   TEST_STORABLE=test_storable
@@ -319,7 +335,7 @@
 #	Generate the Makefiles and shell scripts with the
 #	variable substitutions.
 #--------------------------------------------------------------------
-if test "$BUILD_ORCALLATOR" = "yes"; then
+if test "$BUILD_ORCALLATOR" = yes; then
   ORCALLATOR_OUTPUT="orcallator/orcallator.cfg
                      orcallator/orcallator_running.pl
                      orcallator/restart_orcallator.sh
@@ -339,14 +355,17 @@
 	  docs/Makefile
 	  Makefile)
 
-command="(cd packages/$RRDTOOL_DIR; ./configure $CONFIGURE_COMMAND_LINE --cache-file=../../config.cache)"
-echo ""
-echo "Running configure in packages/$RRDTOOL_DIR to create RRDtool and RRDs.pm."
-echo ""
-echo $command
-echo ""
-eval $command
+# Build the RRDtool library if it is needed.
+if test "$borp_cv_perl_rdds" = no; then
+  command="(cd packages/$RRDTOOL_DIR; ./configure $CONFIGURE_COMMAND_LINE --cache-file=../../config.cache)"
+  echo ""
+  echo "Running configure in packages/$RRDTOOL_DIR to create RRDtool and RRDs.pm."
+  echo ""
+  echo $command
+  echo ""
+  eval $command
+fi
 
 if test -z "$WEB_LOG"; then
-  AC_MSG_WARN([*** Unless you use a --with-*-log option you will not gather WWW log data.])
+  AC_MSG_WARN([*** Unless you use a --with-*-log option orcallator will not gather WWW log data.])
 fi

Modified: trunk/orca/lib/homesteaders.cfg
==============================================================================
--- trunk/orca/lib/homesteaders.cfg	(original)
+++ trunk/orca/lib/homesteaders.cfg	Sat Jul 13 21:07:52 2002
@@ -86,7 +86,7 @@
   <font face="Arial,Helvetica">
     Please email requests for enhancements, comments, or suggestions
     to Dr. Blair Zajac
-    <a href="mailto:bzajac at akamai.com">&lt;bzajac at akamai.com&gt;</a>.
+    <a href="mailto:blair at akamai.com">&lt;blair at akamai.com&gt;</a>.
   </font>
 
 # These are the same plot except one of them do not allow deletions.

Modified: trunk/orca/lib/Makefile.in
==============================================================================
--- trunk/orca/lib/Makefile.in	(original)
+++ trunk/orca/lib/Makefile.in	Sat Jul 13 21:07:52 2002
@@ -19,6 +19,18 @@
 	perl -e 'while (sysread(STDIN, $$b, 35)){print unpack("h*", $$b),"\n"}' < $< > $@
 
 install: all
+	$(MKDIR) $(libdir)/Orca
+	@for f in Orca/*.pm; do						\
+		$(INSTALL) -m 0644 $$f $(libdir)/Orca;			\
+		echo $(INSTALL) -m 0644 $$f $(libdir)/Orca;		\
+	done
+	@if test -d Orca/Config; then					\
+		$(MKDIR) $(libdir)/Orca/Config;				\
+		for f in Orca/Config/*.pm; do				\
+			$(INSTALL) -m 0644 $$f $(libdir)/Orca/Config;	\
+			echo $(INSTALL) -m 0644 $$f $(libdir)/Orca/Config; \
+		done;							\
+	fi
 
 clean:
 

Added: trunk/orca/lib/Orca/HTMLFile.pm
==============================================================================
--- trunk/orca/lib/Orca/HTMLFile.pm	(original)
+++ trunk/orca/lib/Orca/HTMLFile.pm	Sat Jul 13 21:07:52 2002
@@ -0,0 +1,92 @@
+# Orca::HTMLFile: Manage the creation of HTML files.
+#
+# Copyright (C) 1998, 1999 Blair Zajac and Yahoo!, Inc.
+
+package Orca::HTMLFile;
+
+use strict;
+use Carp;
+use Orca::Constants qw($ORCA_VERSION);
+use vars            qw($VERSION);
+
+$VERSION = substr q$Revision: 0.02 $, 10;
+
+# Use a blessed reference to an array as the storage for this class.
+# Define these constant subroutines as indexes into the array.  If
+# the order of these indexes change, make sure to rearrange the
+# constructor in new.
+sub I_FILENAME () { 0 }
+sub I_FD       () { 1 }
+sub I_BOTTOM   () { 2 }
+
+sub new {
+  unless (@_ == 4 or @_ == 5) {
+    confess "$0: Orca::HTMLFile::new passed wrong number of arguments.\n";
+  }
+  my ($class, $filename, $title, $top, $bottom) = @_;
+  $bottom = '' unless defined $bottom;
+
+  local *FD;
+  unless (open(FD, "> $filename.htm")) {
+    $@ = "cannot open `$filename.htm' for writing: $!";
+    return;
+  }
+
+  print FD <<END;
+<html>
+<head>
+<title>$title</title>
+</head>
+<body bgcolor="#ffffff">
+
+$top
+<h1>$title</h1>
+END
+
+  bless [$filename, *FD, $bottom], $class;
+}
+
+sub print {
+  my $self = shift;
+  print { $self->[I_FD] } "@_";
+}
+
+my $i_bottom = I_BOTTOM;
+
+sub DESTROY {
+  my $self = shift;
+
+  print { $self->[I_FD] } <<END;
+$self->[$i_bottom]
+<p>
+<hr align=left width=475>
+<table cellpadding=0 border=0>
+  <tr>
+    <td width=350 valign=center>
+      <a href="http://www.gps.caltech.edu/~blair/orca/">
+        <img width=186 height=45 border=0 src="orca.gif" alt="Orca Home Page"></a>
+      <br>
+      <font FACE="Arial,Helvetica" size=2>
+        Orca-$ORCA_VERSION by
+        <a href="http://www.gps.caltech.edu/~blair/">Blair Zajac</a>
+        <a href="mailto:blair\@akamai.com">blair\@akamai.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>
+    </td>
+  </tr>
+</table>
+</body>
+</html>
+END
+
+  my $filename = $self->[I_FILENAME];
+  close($self->[I_FD]) or
+    warn "$0: warning: cannot close `$filename.htm': $!\n";
+  rename("$filename.htm", $filename) or
+    warn "$0: cannot rename `$filename.htm' to `$filename': $!\n";
+}
+
+1;

Added: trunk/orca/lib/Orca/OpenFileHash.pm
==============================================================================
--- trunk/orca/lib/Orca/OpenFileHash.pm	(original)
+++ trunk/orca/lib/Orca/OpenFileHash.pm	Sat Jul 13 21:07:52 2002
@@ -0,0 +1,219 @@
+# Orca::OpenFileHash: Cache open file descriptors for the whole program.
+#
+# Copyright (C) 1998, 1999 Blair Zajac and Yahoo!, Inc.
+
+package Orca::OpenFileHash;
+
+use strict;
+use Carp;
+use Exporter;
+use Orca::Constants     qw($opt_verbose);
+use Orca::SourceFileIDs qw(@sfile_fids);
+use vars                qw(@EXPORT_OK @ISA $VERSION);
+
+ at ISA     = qw(Exporter);
+$VERSION = substr q$Revision: 0.01 $, 10;
+
+# Set up a cache of 100 open file descriptors for the source data
+# files.  This leaves a large number of free file descriptors for
+# other use in the program.
+use vars qw($open_file_cache);
+unless ($open_file_cache) {
+  $open_file_cache = Orca::OpenFileHash->new(100)
+}
+
+# Export a global open file cache object.
+ at EXPORT_OK = qw($open_file_cache);
+
+# Use a blessed reference to an array as the storage for this class.
+# Define these constant subroutines as indexes into the array.  If
+# the order of these indexes change, make sure to rearrange the
+# constructor in new.
+sub I_MAX_ELEMENTS    () { 0 }
+sub I_HASH            () { 1 }
+sub I_WEIGHTS         () { 2 }
+sub I_FILENOS         () { 3 }
+
+# These constants are used in the array reference for a particular FID.
+sub I_FID_FD      () { 0 }
+sub I_FID_WEIGHT  () { 1 }
+sub I_FID_IS_PIPE () { 2 }
+
+sub new {
+  unless (@_ == 2) {
+    confess "$0: Orca::OpenFileHash::new passed wrong number of arguments.\n";
+  }
+
+  my ($class, $max_elements) = @_;
+
+  bless [$max_elements, {}, {}, {}], $class;
+}
+
+sub open {
+  unless (@_ == 3) {
+    confess "$0: Orca::OpenFileHash::open passed wrong number of arguments.\n";
+  }
+
+  my ($self, $fid, $weight) = @_;
+
+  local *FD;
+
+  # Uncompress compressed files on the fly and read them in.
+  my $filename = $sfile_fids[$fid];
+  my $is_pipe = 1;
+  if ($filename =~ /\.gz$/) {
+    $filename = "gunzip -c $filename |";
+  } elsif ($filename =~ /\.Z$/) {
+    $filename = "uncompress -c $filename |";
+  } elsif ($filename =~ /\.bz2$/) {
+    $filename = "bunzip2 -c $filename |";
+  } else {
+    $is_pipe = 0;
+  }
+
+  # Try to open the file or pipe.  If the pipe fails and if there are
+  # other opened files, then reduce the maximum number of open files.
+  # If this is the first open file and the pipe fails, then do not
+  # attempt to open it again.
+  while (!open(FD, $filename)) {
+    warn "$0: warning: cannot open `$filename' for reading: $!\n";
+    my $num_current_open_files = (keys %{$self->[I_HASH]});
+    return unless $num_current_open_files;
+    $num_current_open_files -= 2;
+    return if $num_current_open_files <= 4;
+    warn "$0: warning: shrinking maximum number open files to ",
+         "$num_current_open_files.\n";
+    $self->[I_MAX_ELEMENTS] = $num_current_open_files;
+    $self->_close_extra($num_current_open_files-1);
+  }
+
+  $self->add($fid, $weight, *FD, $is_pipe);
+
+  *FD;
+}
+
+sub add {
+  unless (@_ == 5) {
+    confess "$0: Orca::OpenFileHash::add passed wrong number of arguments.\n";
+  }
+
+  my ($self, $fid, $weight, $fd, $is_pipe) = @_;
+
+  # If there is an open file descriptor for this fid, then force it
+  # to close.  Then make space for the new file descriptor in the
+  # cache.
+  $self->close($fid);
+  $self->_close_extra($self->[I_MAX_ELEMENTS] - 1);
+
+  my $fileno = fileno($fd);
+
+  $self->[I_HASH]{$fid}[I_FID_FD]      = $fd;
+  $self->[I_HASH]{$fid}[I_FID_WEIGHT]  = $weight;
+  $self->[I_HASH]{$fid}[I_FID_IS_PIPE] = $is_pipe;
+  $self->[I_FILENOS]{$fid}             = $fileno;
+
+  unless (defined $self->[I_WEIGHTS]{$weight}) {
+    $self->[I_WEIGHTS]{$weight} = [];
+  }
+  push(@{$self->[I_WEIGHTS]{$weight}}, $fid);
+}
+
+sub close {
+  my ($self, $fid) = @_;
+
+  my $data_ref = delete $self->[I_HASH]{$fid};
+  return $self unless $data_ref;
+
+  my $filename    = $sfile_fids[$fid];
+  my $fd          = $data_ref->[I_FID_FD];
+  my $weight      = $data_ref->[I_FID_WEIGHT];
+  my $is_pipe     = $data_ref->[I_FID_IS_PIPE];
+  my $is_eof      = $is_pipe ? eof($fd) : 0;
+  my $close_value = close($fd);
+  unless ($close_value) {
+    if ($is_pipe) {
+      if ($is_eof) {
+        warn "$0: warning: cannot close pipe for `$filename': ",
+             "[$close_value \$?=$?] $!\n" if $opt_verbose > 1;
+      }
+    } else {
+      warn "$0: warning: cannot close `$filename': [$close_value] $!\n";
+    }
+  }
+
+  my $fileno = delete $self->[I_FILENOS]{$fid};
+
+  my @fids = grep { $_ != $fid } @{$self->[I_WEIGHTS]{$weight}};
+  if (@fids) {
+    $self->[I_WEIGHTS]{$weight} = \@fids;
+  } else {
+    delete $self->[I_WEIGHTS]{$weight};
+  }
+
+  $close_value;
+}
+
+sub _close_extra {
+  my ($self, $max_elements) = @_;
+
+  # Remove this number of elements from the structure.
+  my $close_number = (keys %{$self->[I_HASH]}) - $max_elements;
+
+  return $self unless $close_number > 0;
+
+  my @weights = sort { $a <=> $b } keys %{$self->[I_WEIGHTS]};
+
+  while ($close_number > 0) {
+    my $weight = shift(@weights);
+    foreach my $fid (@{$self->[I_WEIGHTS]{$weight}}) {
+      $self->close($fid);
+      --$close_number;
+    }
+  }
+
+  $self;
+}
+
+sub change_weight {
+  my ($self, $fid, $new_weight) = @_;
+
+  return unless defined $self->[I_HASH]{$fid};
+
+  my $old_weight = $self->[I_HASH]{$fid}[I_FID_WEIGHT];
+  return if $old_weight == $new_weight;
+
+  # Save the new weight.
+  $self->[I_HASH]{$fid}[I_FID_WEIGHT] = $new_weight;
+
+  unless (defined $self->[I_WEIGHTS]{$new_weight}) {
+    $self->[I_WEIGHTS]{$new_weight} = [];
+  }
+  push(@{$self->[I_WEIGHTS]{$new_weight}}, $fid);
+
+  # Remove the old weight.
+  my @fids = @{$self->[I_WEIGHTS]{$old_weight}};
+  @fids = grep { $_ != $fid } @fids;
+  if (@fids) {
+    $self->[I_WEIGHTS]{$old_weight} = \@fids;
+  } else {
+    delete $self->[I_WEIGHTS]{$old_weight};
+  }
+
+  1;
+}
+
+sub get_fd {
+  my ($self, $fid) = @_;
+
+  if (defined (my $ref = $self->[I_HASH]{$fid})) {
+    return $ref->[I_FID_FD];
+  } else {
+    return;
+  }
+}
+
+sub is_open {
+  defined $_[0]->[I_HASH]{$_[1]};
+}
+
+1;

Added: trunk/orca/lib/Orca/Config.pm
==============================================================================
--- trunk/orca/lib/Orca/Config.pm	(original)
+++ trunk/orca/lib/Orca/Config.pm	Sat Jul 13 21:07:52 2002
@@ -0,0 +1,697 @@
+# Orca::Config: Manage configuration options for Orca.
+#
+# Copyright (C) 1998, 1999 Blair Zajac and Yahoo!, Inc.
+
+package Orca::Config;
+
+use strict;
+use Carp;
+use Exporter;
+use Orca::Constants     qw($opt_verbose
+                           $is_sub_re
+                           die_when_called);
+use Orca::SourceFileIDs qw(@sfile_fids);
+use vars qw(@EXPORT_OK @ISA $VERSION);
+
+ at ISA     = qw(Exporter);
+$VERSION = substr q$Revision: 0.01 $, 10;
+
+# Export the main subroutine to load configuration data and a subroutine
+# to get a color indexed by an integer.
+push(@EXPORT_OK, qw(load_config get_color));
+
+# The following array and hashes hold the contents of the
+# configuration file.
+use vars         qw(%config_options %config_groups @config_plots);
+push(@EXPORT_OK, qw(%config_options %config_groups @config_plots));
+
+# These are state variables for reading the config file.  The
+# $pcl_group_name variable holds the name of the group when a
+# group is being defined.  If $pcl_group_name is '', then a group
+# configuration is not being read.  $pcl_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_group_name  = '';
+my $pcl_plot_index = '-0';
+
+# The following options go into the options and files hashes.  If you
+# add any elements to pcl_plot_append_elements, make sure to update
+# Orca::SourceFile::add_plots.
+my @pcl_option_elements        = qw(base_dir
+                                    expire_images
+                                    find_times
+                                    html_dir
+                                    html_page_footer
+                                    html_page_header
+                                    html_top_title
+                                    late_interval
+                                    rrd_dir
+                                    state_file
+                                    sub_dir
+                                    warn_email);
+my @pcl_group_elements         = qw(column_description
+                                    date_format
+                                    date_source
+                                    filename_compare
+                                    find_files
+                                    interval
+                                    reopen);
+my @pcl_plot_elements          = qw(base
+                                    color
+                                    data
+                                    data_min
+                                    data_max
+                                    data_type
+                                    flush_regexps
+                                    href
+                                    legend
+                                    line_type
+                                    logarithmic
+                                    plot_height
+                                    plot_min
+                                    plot_max
+                                    plot_width
+                                    required
+                                    rigid_min_max
+                                    source
+                                    title
+                                    y_legend);
+my @pcl_plot_append_elements   = qw(color
+                                    data
+                                    legend
+                                    line_type);
+my @pcl_filepath_elements      = qw(find_files
+                                    html_dir
+                                    rrd_dir
+                                    state_file);
+my @pcl_no_arg_elements        = qw(flush_regexps
+                                    logarithmic
+                                    required
+                                    rigid_min_max);
+my %pcl_option_keep_as_array   =   ();
+my %pcl_group_keep_as_array    =   (column_description => 1,
+                                    date_source        => 1,
+                                    find_files         => 1);
+my %pcl_plot_keep_as_array     =   (data               => 1);
+
+# The following variables are used to check that the configuration file
+# contains the required options.  the @cc_required_* are the names of
+# the options that must occur in a configuration file.  The @cc_optional_*
+# options are options set to '' if they are not set in the configuration
+# file.
+my @cc_required_option         = qw(html_dir
+                                    rrd_dir
+                                    state_file);
+my @cc_required_group          = qw(column_description
+                                    date_source
+                                    find_files
+                                    interval);
+my @cc_required_plot           = qw(data
+                                    source);
+my @cc_optional_option         = qw(expire_images
+                                    html_page_footer
+                                    html_page_header
+                                    html_top_title
+                                    late_interval
+                                    sub_dir
+                                    warn_email);
+my @cc_optional_group          = qw(reopen);
+my @cc_optional_plot           = qw(flush_regexps
+                                    href
+                                    plot_width
+                                    plot_height);
+
+# This is the default list of colors.
+my @cc_default_colors          =   ('00ff00',	# Green
+                                    '0000ff',	# Blue
+                                    'ff0000',	# Red
+                                    'a020f0',	# Magenta
+                                    'ffa500',	# Orange
+                                    'a52a2a',	# Brown
+                                    '00ffff',	# Cyan
+                                    '00aa00',	# Dark Green
+                                    'eeee00',	# Yellow
+                                    '5e5e5e',	# Dark Gray
+                                    '0000aa');	# Dark Blue
+
+sub get_color {
+  $cc_default_colors[$_[0] % @cc_default_colors];
+}
+
+# This variable stores the anonymous subroutine that compares FIDs
+# when a group in the configuration files does not contain a
+# filename_compare parameter.
+my $cmp_fids_sub;
+
+sub check_config {
+  my $config_filename = shift;
+
+  # If rrd_dir is not set, then use base_dir.  Only die if both are
+  # not set.
+  unless (defined $config_options{rrd_dir}) {
+    if (defined $config_options{base_dir}) {
+      $config_options{rrd_dir} = $config_options{base_dir};
+    } else {
+      die "$0: error: must define `rrd_dir' in `$config_filename'.\n";
+    }
+  }
+
+  # Check that we the required options are satisfied.
+  foreach my $option (@cc_required_option) {
+    unless (defined $config_options{$option}) {
+      die "$0: error: must define `$option' in `$config_filename'.\n";
+    }
+  }
+
+  # Check if the html_dir and rrd_dir directories exist.
+  foreach my $dir_key ('html_dir', 'rrd_dir') {
+    my $dir = $config_options{$dir_key};
+    die "$0: error: please create $dir_key `$dir'.\n" unless -d $dir;
+  }
+
+  # Set any optional options to '' if it isn't defined.
+  foreach my $option (@cc_optional_option) {
+    $config_options{$option} = '' unless defined $config_options{$option};
+  }
+
+  # Late_interval is a valid mathematical expression. Replace the word
+  # interval with $_[0].  Try the subroutine to make sure it works.
+  unless ($config_options{late_interval}) {
+    $config_options{late_interval} = 'interval';
+  }
+  my $expr = "sub { $config_options{late_interval}; }";
+  $expr =~ s/interval/\$_[0]/g;
+  my $sub;
+  {
+    local $SIG{__DIE__}  = 'DEFAULT';
+    local $SIG{__WARN__} = \&die_when_called;
+    $sub = eval $expr;
+  }
+  if ($@) {
+    die "$0: cannot evaluate `late_interval' in `$config_filename':\n   ",
+        "$expr\nOutput: $@\n";
+  }
+  {
+    local $SIG{__DIE__}  = 'DEFAULT';
+    local $SIG{__WARN__} = \&die_when_called;
+    eval '&$sub(3.1415926) + 0;';
+  }
+  if ($@) {
+    die "$0: cannot execute `late_interval' in `$config_filename':\n   ",
+         "$expr\nOutput: $@\n";
+  }
+  $config_options{late_interval} = $sub;
+
+  # Convert the list of find_times into an array of fractional hours.
+  my @find_times;
+  unless (defined $config_options{find_times}) {
+    $config_options{find_times} = '';
+  }
+  foreach my $find_time (split(' ', $config_options{find_times})) {
+    if (my ($hours, $minutes) = $find_time =~ /^(\d{1,2}):(\d{2})/) {
+      # Because of the regular expression match we're doing, the hours
+      # and minutes will only be positive, so check for hours > 23 and
+      # minutes > 59.
+      unless ($hours < 24) {
+        warn "$0: warning: ignoring find_times `$find_time': hours must be less than 24.\n";
+        next;
+      }
+      unless ($minutes < 60) {
+        warn "$0: warning: ignoring find_times `$find_time': minutes must be less than 60.\n";
+        next;
+      }
+      push(@find_times, $hours + $minutes/60.0);
+    } else {
+      warn "$0: warning: ignoring find_times `$find_time': illegal format.\n";
+    }
+  }
+  $config_options{find_times} = [ sort { $a <=> $b } @find_times ];
+
+  # There must be at least one group.
+  unless (keys %config_groups) {
+    die "$0: error: must define at least one `group' in `$config_filename'.\n";
+  }
+
+  # For each group parameter there are required options.
+  foreach my $group_name (keys %config_groups) {
+    my $group = $config_groups{$group_name};
+
+    foreach my $option (@cc_required_group) {
+      unless (defined $group->{$option}) {
+        die "$0: error: must define `$option' for `group $group_name' ",
+            "in `$config_filename'.\n";
+      }
+    }
+
+    # Optional group options will be set to '' here if they haven't
+    # been set by the user.
+    foreach my $option (@cc_optional_group) {
+      $group->{$option} = '' unless defined $group->{$option};
+    }
+
+    # Create the filename comparison function.  The function must be
+    # handle input ala sort() via the package global $a and $b variables.
+    if (defined $group->{filename_compare} or !$cmp_fids_sub) {
+      my $expr = defined $group->{filename_compare} ?
+                 $group->{filename_compare} :
+                 'sub { $a cmp $b }';
+      $expr = "sub { $expr }" if $expr !~ /$is_sub_re/o;
+      my $sub;
+      {
+        local $SIG{__DIE__}  = 'DEFAULT';
+        local $SIG{__WARN__} = \&die_when_called;
+        $sub = eval $expr;
+      }
+      if ($@) {
+        if ($group->{filename_compare}) {
+          die "$0: cannot compile `filename_compare' for group `$group_name' ",
+              "in `$config_filename':\n   $expr\nOutput: $@\n";
+        } else {
+          die "$0: internal error: cannot compile default ",
+              "`filename_compare':\n   $expr\nOutput: $@\n";
+        }
+      }
+
+      # This subroutine looks fine.  Now change all the variables to use
+      # file IDs instead.
+      $expr =~ s/\$a(\W)/\$sfile_fids[\$a]$1/g;
+      $expr =~ s/\$b(\W)/\$sfile_fids[\$b]$1/g;
+      {
+        no strict;
+        local $SIG{__DIE__}  = 'DEFAULT';
+        local $SIG{__WARN__} = \&die_when_called;
+        $sub = eval $expr;
+      }
+      if ($@) {
+        if ($group->{filename_compare}) {
+          die "$0: cannot compile `filename_compare' for group `$group_name' ",
+              "in `$config_filename':\n   $expr\nOutput: $@\n";
+        } else {
+          die "$0: internal error: cannot compile default ",
+              "`filename_compare':\n   $expr\nOutput: $@\n";
+        }
+      }
+      $cmp_fids_sub = $sub if !$group->{filename_compare};
+      $group->{filename_compare} = $sub;
+    } else {
+      $group->{filename_compare} = $cmp_fids_sub;
+    }
+
+    # 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 = $group->{date_source}[0];
+    if ($date_source eq 'column_name') {
+      unless (@{$group->{date_source}} == 2) {
+        die "$0: error: incorrect number of arguments for `date_source' for ",
+            "`group $group_name'.\n";
+      }
+      unless (defined $group->{date_format}) {
+        die "$0: error: must define `date_format' with ",
+            "`date_source columns ...' for `group $group_name'.\n";
+      }
+    } else {
+      unless ($date_source eq 'file_mtime') {
+        die "$0: error: illegal argument for `date_source' for ",
+             "`group $group_name'.\n";
+      }
+    }
+    $group->{date_source}[0] = $date_source;
+
+    # Validate the regular expression for find_files and get a unique list
+    # of them.  Check if the regular expressions contain any ()'s that will
+    # place the found files into different groups.  If any ()'s are found,
+    # then the output HTML and image tree will use subdirectories for each
+    # group.
+    #
+    # In this comment, all path names are Perl escaped, so the directory
+    # . would be written as \. instead.
+    #
+    # Since we do not want to search on the current directory, find any
+    # text that begins a regular expression with a \./ and remove it.  Also
+    # Remove any matches for /\./ in the path since they are unnecessary.
+    # However, do not remove searches for /./, since this can match single
+    # character files or directories.
+    my $sub_dir = 0;
+    my %find_files;
+    my $number_finds = @{$group->{find_files}};
+    for (my $i=0; $i<$number_finds; ++$i) {
+      my $orig_find = $group->{find_files}[$i];
+      my $find      = $orig_find;
+      $find         =~ s:^\\\./+::;
+      $find         =~ s:/+\\\./+:/:g;
+      $find         = $orig_find unless $find;
+      $group->{find_files}[$i] = $find;
+      my $test_string          = 'abcdefg';
+      local $SIG{__DIE__}      = 'DEFAULT';
+      local $SIG{__WARN__}     = \&die_when_called;
+      eval { $test_string =~ /$find/ };
+      if ($@) {
+        die "$0: error: illegal regular expression in `find_files $orig_find' ",
+            "for `files $group_name' in `$config_filename':\n$@\n";
+      }
+      $find_files{$find} = 1;
+      $sub_dir = 1 if $find =~ m:\(.+\):;
+    }
+    $group->{find_files} = [sort keys %find_files];
+    $group->{sub_dir}    = $sub_dir || $config_options{sub_dir};
+  }
+
+  # There must be at least one plot.
+  unless (@config_plots) {
+    die "$0: error: must define at least one `plot' in `$config_filename'.\n";
+  }
+
+  # Foreach plot there are required options.  Create default options
+  # if the user has not done so.
+  for (my $i=0; $i<@config_plots; ++$i) {
+    my $plot = $config_plots[$i];
+
+    my $j = $i + 1;
+    foreach my $option (@cc_required_plot) {
+      unless (defined $plot->{$option}) {
+        die "$0: error: must define `$option' for `plot' #$j in ",
+            "`$config_filename'.\n";
+      }
+    }
+
+    # Create an array for each plot that will have a list of images that
+    # were generated from this plot.
+    $plot->{creates} = [];
+
+    # Optional options will be set to '' here if they haven't been set
+    # by the user.
+    foreach my $option (@cc_optional_plot) {
+      $plot->{$option} = '' unless defined $plot->{$option};
+    }
+
+    # Set the default plot width and height.
+    $plot->{plot_width}  =  500 unless $plot->{plot_width};
+    $plot->{plot_height} =  125 unless $plot->{plot_height};
+
+    # Make sure the base is either 1000 or 1024.
+    if (defined $plot->{base} && length($plot->{base})) {
+      if ($plot->{base} != 1000 and $plot->{base} != 1024) {
+        die "$0: error: plot #$j must define base to be either 1000 or 1024.\n";
+      }
+    } else {
+      $plot->{base} = 1000;
+    }
+
+    # Set the plot minimum and maximum values to U unless they are
+    # set.
+    $plot->{data_min} = 'U' unless defined $plot->{data_min};
+    $plot->{data_max} = 'U' unless defined $plot->{data_max};
+
+    # The data type must be either gauge, absolute, or counter.
+    if (defined $plot->{data_type}) {
+      my $type = substr($plot->{data_type}, 0, 1);
+      if ($type eq 'g' or $type eq 'G') {
+        $plot->{data_type} = 'GAUGE';
+      } elsif ($type eq 'c' or $type eq 'C') {
+        $plot->{data_type} = 'COUNTER';
+      } elsif ($type eq 'a' or $type eq 'A') {
+        $plot->{data_type} = 'ABSOLUTE';
+      } elsif ($type eq 'd' or $type eq 'D') {
+        $plot->{data_type} = 'DERIVE';
+      } else {
+        die "$0: error: `data_type $plot->{data_type}' for `plot' #$j in ",
+            "`$config_filename' must be gauge, counter, derive, or absolute.\n";
+      }
+    } else {
+      $plot->{data_type} = 'GAUGE';
+    }
+
+    # The data source needs to be a valid group name.
+    my $source = $plot->{source};
+    unless (defined $config_groups{$source}) {
+      die "$0: error: plot #$j `source $source' references non-existant ",
+          "`group' in `$config_filename'.\n";
+    }
+    unless ($plot->{source}) {
+      die "$0: error: plot #$j `source $source' requires one group_name ",
+          "argument in `$config_filename'.\n";
+    }
+
+    # Set the legends of any columns not defined.
+    $plot->{legend} = [] unless defined $plot->{legend};
+    my $number_datas = @{$plot->{data}};
+    for (my $k=@{$plot->{legend}}; $k<$number_datas; ++$k) {
+      $plot->{legend}[$k] = "@{$plot->{data}[$k]}";
+    }
+
+    # Set the colors of any data not defined.
+    $plot->{color} = [] unless defined $plot->{color};
+    for (my $k=@{$plot->{color}}; $k<$number_datas; ++$k) {
+      $plot->{color}[$k] = get_color($k);
+    }
+
+    # Check each line type setting.
+    for (my $k=0; $k<$number_datas; ++$k) {
+      if (defined $plot->{line_type}[$k]) {
+      my $line_type = $plot->{line_type}[$k];
+        if ($line_type =~ /^line([123])$/i) {
+          $line_type = "LINE$1";
+        } elsif ($line_type =~ /^area$/i) {
+          $line_type = 'AREA';
+        } elsif ($line_type =~ /^stack$/i) {
+          $line_type = 'STACK';
+        } else {
+          die "$0: error: plot #$j illegal `line_type' `$line_type'.\n";
+        }
+        $plot->{line_type}[$k] = $line_type;
+      } else {
+        $plot->{line_type}[$k] = 'LINE1';
+      }
+    }
+
+    # If the generic y_legend is not set, then set it equal to the
+    # first legend.
+    unless (defined $plot->{y_legend}) {
+      $plot->{y_legend} = $plot->{legend}[0];
+    }
+
+    # If the title is not set, then set it equal to all of the legends
+    # with the group name prepended.
+    unless (defined $plot->{title}) {
+      my $title = '%G ';
+      for (my $k=0; $k<$number_datas; ++$k) {
+        $title .= $plot->{legend}[$k];
+        $title .= " & " if $k < $number_datas-1;
+      }
+      $plot->{title} = $title;
+    }
+  }
+
+  1;
+}
+
+sub _trim_path {
+  my $path = shift;
+
+  # Replace any multiple /'s with a single /.
+  $path =~ s:/{2,}:/:g;
+
+  # Trim any trailing /.'s unless the path is only /., in which case
+  # make it /.
+  if ($path eq '/.') {
+    $path = '/';
+  } else {
+    $path =~ s:/\.$::;
+  }
+  $path;
+}
+
+sub process_config_line {
+  my ($config_filename, $line_number, $line) = @_;
+
+  # Take the line and split it and make the first element lowercase.
+  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.
+  if ($key ne '}') {
+    if (grep {$key eq $_} @pcl_no_arg_elements) {
+      push(@line, 1) unless @line;
+    } else {
+      unless (@line) {
+        warn "$0: warning: option `$key' needs arguments in `$config_filename' line $line_number.\n";
+        return;
+      }
+    }
+  }
+
+  # Clean up paths in the following order:
+  # 1) Trim the path.
+  # 2) Prepend the base_dir to paths that are not prepended by
+  #    ^\\?\.{0,2}/, which matches /, ./, ../, and \./.
+  # 3) Trim the resulting path.
+  if (grep {$key eq $_} @pcl_filepath_elements) {
+    my $base_dir = defined $config_options{base_dir}?
+      _trim_path($config_options{base_dir}) : '';
+    for (my $i=0; $i<@line; ++$i) {
+      my $path = _trim_path($line[$i]);
+      if ($base_dir) {
+        $path = "$base_dir/$path" unless $path =~ m:^\\?\.{0,2}/:;
+      }
+      $line[$i] = _trim_path($path);
+    }
+  }
+
+  my $value = "@line";
+
+  # Process the line differently if we're reading for a particular
+  # option.  This one is for groups.
+  if ($pcl_group_name) {
+    if ($key eq '}') {
+      $pcl_group_name = '';
+      return;
+    }
+    unless (grep {$key eq $_} @pcl_group_elements) {
+      warn "$0: warning: directive `$key' unknown for group at line $line_number in `$config_filename'.\n";
+      return;
+    }
+
+    if (defined $config_groups{$pcl_group_name}{$key}) {
+      warn "$0: warning: `$key' for group already defined at line $line_number in `$config_filename'.\n";
+    }
+    if ($pcl_group_keep_as_array{$key}) {
+      $config_groups{$pcl_group_name}{$key} = [ @line ];
+    } else {
+      $config_groups{$pcl_group_name}{$key} = $value;
+    }
+    return;
+  }
+
+  # Handle options for plot.
+  if ($pcl_plot_index !~ /^-/) {
+    if ($key eq '}') {
+      ++$pcl_plot_index;
+      $pcl_plot_index = "-$pcl_plot_index";
+      return;
+    }
+    unless (grep {$key eq $_} @pcl_plot_elements) {
+      warn "$0: warning: directive `$key' unknown for plot at line $line_number in `$config_filename'.\n";
+      return;
+    }
+
+    # Handle those elements that can just append.
+    if (grep { $key eq $_ } @pcl_plot_append_elements) {
+      unless (defined $config_plots[$pcl_plot_index]{$key}) {
+        $config_plots[$pcl_plot_index]{$key} = [];
+      }
+      if ($pcl_plot_keep_as_array{$key}) {
+        push(@{$config_plots[$pcl_plot_index]{$key}}, [ @line ]);
+      } else {
+        push(@{$config_plots[$pcl_plot_index]{$key}}, $value);
+      }
+      return;
+    }
+
+    if (defined $config_plots[$pcl_plot_index]{$key}) {
+      warn "$0: warning: `$key' for plot already defined at line $line_number in `$config_filename'.\n";
+      return;
+    }
+    if ($pcl_plot_keep_as_array{$key}) {
+      $config_plots[$pcl_plot_index]{$key} = [ @line ];
+    } else {
+      $config_plots[$pcl_plot_index]{$key} = $value;
+    }
+    return;
+  }
+
+  # Take care of generic options.
+  if (grep {$key eq $_} @pcl_option_elements) {
+    if ($pcl_option_keep_as_array{$key}) {
+      $config_options{$key} = [ @line ];
+    } else {
+      $config_options{$key} = $value;
+    }
+    return;
+  }
+
+  # Take care of a group.
+  if ($key eq 'group') {
+    unless (@line) {
+      die "$0: error: group needs a group name followed by { at ",
+          "line $line_number in `$config_filename'.\n"
+    }
+    $pcl_group_name = shift(@line);
+    unless (@line == 1 and $line[0] eq '{' ) {
+      warn "$0: warning: '{' required after `group $pcl_group_name' at ",
+           "line $line_number in `$config_filename'.\n";
+    }
+    if (defined $config_groups{$pcl_group_name}) {
+      warn "$0: warning: `group $key' at line $line_number in ",
+           "`$config_filename' previously defined.\n";
+    }
+    return;
+  }
+
+  # Take care of plots to make.  Include in each plot its index.
+  if ($key eq 'plot') {
+    $pcl_plot_index =~ s:^-::;
+    $config_plots[$pcl_plot_index]{_index} = $pcl_plot_index;
+    unless (@line == 1 and $line[0] eq '{') {
+      warn "$0: warning: '{' required after `plot' at line $line_number in `$config_filename'.\n";
+    }
+    return;
+  }
+
+  warn "$0: warning: unknown directive `$key' at line $line_number in `$config_filename'.\n";
+}
+
+sub load_config {
+  my $config_filename = shift;
+
+  open(CONFIG, $config_filename) or
+    die "$0: error: cannot open `$config_filename' for reading: $!\n";
+
+  # These values hold the information from the config file.
+  my %options;
+  my %groups;
+  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.
+  my $complete_line = '';
+  my $line_number = 1;
+  while (<CONFIG>) {
+    chomp;
+    # Skip lines that begin with #.
+    next if /^#/;
+
+    # If the line begins with whitespace, then append it to the
+    # previous line.
+    if (/^\s+/) {
+      $complete_line .= " $_";
+      next;
+    }
+
+    # Process the previously read complete line.
+    if ($complete_line) {
+      process_config_line($config_filename, $line_number, $complete_line);
+    }
+
+    # Now save this read line.
+    $complete_line = $_;
+    $line_number = $.;
+  }
+
+  # Process any remaining line.
+  if ($complete_line) {
+    process_config_line($config_filename, $line_number, $complete_line);
+  }
+
+  close(CONFIG) or
+    warn "$0: error in closing `$config_filename': $!\n";
+
+  check_config($config_filename);
+}
+
+1;

Added: trunk/orca/lib/Orca/RRDFile.pm
==============================================================================
--- trunk/orca/lib/Orca/RRDFile.pm	(original)
+++ trunk/orca/lib/Orca/RRDFile.pm	Sat Jul 13 21:07:52 2002
@@ -0,0 +1,244 @@
+# Orca::RRDFile: Manage RRD file creation and updating.
+#
+# Copyright (C) 1998, 1999 Blair Zajac and Yahoo!, Inc.
+
+package Orca::RRDFile;
+
+use strict;
+use Carp;
+use RRDs;
+use Orca::Constants qw($opt_verbose
+          	       $ORCA_RRD_VERSION
+                       $incorrect_number_of_args
+                       @RRA_PDP_COUNTS
+                       @RRA_ROW_COUNTS);
+use Orca::Config    qw(%config_options
+                       %config_groups
+                       @config_plots);
+use Orca::Utils     qw(recursive_mkdir);
+use vars            qw($VERSION);
+
+$VERSION = substr q$Revision: 0.01 $, 10;
+
+# Use a blessed reference to an array as the storage for this class.
+# Define these constant subroutines as indexes into the array.  If the
+# order of these indexes change, make sure to rearrange the
+# constructor in new.
+sub I_RRD_FILENAME     () { 0 }
+sub I_NAME             () { 1 }
+sub I_NEW_DATA         () { 2 }
+sub I_CREATED_IMAGES   () { 3 }
+sub I_PLOT_REF         () { 4 }
+sub I_INTERVAL         () { 5 }
+sub I_RRD_VERSION      () { 6 }
+sub I_CHOOSE_DATA_SUBS () { 7 }
+sub I_RRD_UPDATE_TIME  () { 8 }
+
+sub new {
+  unless (@_ == 5) {
+    confess "$0: Orca::RRDFile::new $incorrect_number_of_args";
+  }
+
+  my ($class,
+      $group_name,
+      $subgroup_name,
+      $name,
+      $plot_ref) = @_;
+
+  # Remove any special characters from the unique name and do some
+  # replacements.
+  $name = &::escape_name($name);
+
+  # Create the paths to the data directory.
+  my $rrd_dir = $config_options{rrd_dir};
+  if ($config_groups{$group_name}{sub_dir}) {
+    $rrd_dir .= "/$subgroup_name";
+    unless (-d $rrd_dir) {
+      warn "$0: making directory `$rrd_dir'.\n";
+      recursive_mkdir($rrd_dir);
+    }
+  }
+  my $rrd_filename = "$rrd_dir/$name.rrd";
+
+  # Create the new object.
+  my $self = bless [
+    $rrd_filename,
+    $name,
+    {},
+    {},
+    $plot_ref,
+    int($config_groups{$group_name}{interval}+0.5),
+    $ORCA_RRD_VERSION,
+    {},
+    -2
+  ], $class;
+
+  # 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.
+  if (-e $rrd_filename) {
+    my $update_time = RRDs::last $rrd_filename;
+    if (my $error = RRDs::error) {
+      warn "$0: RRDs::last error: `$rrd_filename' $error\n";
+    } else {
+      if (open(RRDFILE, "<$rrd_filename")) {
+        my $version = '';
+        while (<RRDFILE>) {
+          if (/Orca(\d{8})/) {
+            $version = $1;
+            last;
+          }
+        }
+        close(RRDFILE) or
+          warn "$0: error in closing `$rrd_filename' for reading: $!\n";
+
+        # Compare the version number of file to the required version.
+        if (length($version)) {
+          if ($version >= $ORCA_RRD_VERSION) {
+            $self->[I_RRD_UPDATE_TIME] = $update_time;
+            $self->[I_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";
+        }
+      }
+    }
+  }
+
+  $self;
+}
+
+sub version {
+  $_[0]->[I_RRD_VERSION];
+}
+
+sub filename {
+  $_[0]->[I_RRD_FILENAME];
+}
+
+sub name {
+  $_[0]->[I_NAME];
+}
+
+sub rrd_update_time {
+  $_[0]->[I_RRD_UPDATE_TIME];
+}
+
+sub add_image {
+  my ($self, $image) = @_;
+  $self->[I_CREATED_IMAGES]{$image->name} = $image;
+  $self;
+}
+
+sub created_images {
+  values %{$_[0]->[I_CREATED_IMAGES]};
+}
+
+# Queue a list of (time, value) data pairs.  Return the number of data
+# pairs sucessfully queued.
+# Call:   $self->(unix_epoch_time1, value1, unix_epoch_time2, value2, ...);
+sub queue_data {
+  my $self = shift;
+
+  my $count = 0;
+  my $rrd_update_time = $self->[I_RRD_UPDATE_TIME];
+  while (@_ > 1) {
+    my ($time, $value) = splice(@_, 0, 2);
+    next if $time <= $rrd_update_time;
+    $self->[I_NEW_DATA]{$time} = $value;
+    ++$count;
+  }
+
+  $count;
+}
+
+sub flush_data {
+  my $self = shift;
+
+  # Get the times of the new data to put into the RRD file.
+  my @times = sort { $a <=> $b } keys %{$self->[I_NEW_DATA]};
+
+  return unless @times;
+
+  my $rrd_filename = $self->[I_RRD_FILENAME];
+
+  # Create the Orca data file if it needs to be created.
+  if ($self->[I_RRD_UPDATE_TIME] == -2) {
+
+    # Assume that a maximum of two time intervals are needed before a
+    # data source value is set to unknown.
+    my $interval = $self->[I_INTERVAL];
+   
+    my $data_source = "DS:Orca$ORCA_RRD_VERSION:" .
+                      $self->[I_PLOT_REF]{data_type};
+    $data_source   .= sprintf ":%d:", 2*$interval;
+    $data_source   .= $self->[I_PLOT_REF]{data_min} . ':';
+    $data_source   .= $self->[I_PLOT_REF]{data_max};
+    my @options = ($rrd_filename,
+                   '-b', $times[0]-1,
+                   '-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.
+    my $count          = int($RRA_ROW_COUNTS[0]*300.0/$interval + 0.5);
+    my @one_pdp_option = ("RRA:AVERAGE:0.5:1:$count");
+
+    for (my $i=1; $i<@RRA_PDP_COUNTS; ++$i) {
+      next if $interval > 300*$RRA_PDP_COUNTS[$i];
+      my $rra_pdp_count = int($RRA_PDP_COUNTS[$i]*300.0/$interval + 0.5);
+      if (@one_pdp_option and $rra_pdp_count != 1) {
+        push(@options, @one_pdp_option);
+      }
+      @one_pdp_option = ();
+      push(@options, "RRA:AVERAGE:0.5:$rra_pdp_count:$RRA_ROW_COUNTS[$i]");
+    }
+
+    # Now do the actual creation.
+    if ($opt_verbose) {
+      print "  Creating RRD `$rrd_filename'";
+      if ($opt_verbose > 2) {
+        print " with options ", join(' ', @options[1..$#options]);
+      }
+      print ".\n";
+    }
+    RRDs::create @options;
+
+    if (my $error = RRDs::error) {
+      warn "$0: RRDs::create error: `$rrd_filename' $error\n";
+      return;
+    }
+  }
+
+  # Flush all of the stored data into the RRD file.
+  my @options;
+  my $old_rrd_update_time = $self->[I_RRD_UPDATE_TIME];
+  foreach my $time (@times) {
+    push(@options, "$time:" . $self->[I_NEW_DATA]{$time});
+  }
+  RRDs::update $rrd_filename, @options;
+  my $ok = 1;
+  if (my $error = RRDs::error) {
+    warn "$0: warning: cannot put data starting at ",
+         scalar localtime($times[0]),
+         " ($times[0]) into `$rrd_filename': $error\n";
+    return 0;
+  }
+
+  # If there were no errors, then totally clear the hash to save
+  # memory.
+  undef $self->[I_NEW_DATA];
+  $self->[I_NEW_DATA] = {};
+
+  $self->[I_RRD_UPDATE_TIME] = $times[-1];
+
+  1;
+}
+
+1;

Added: trunk/orca/lib/Orca/DataFile.pm
==============================================================================
--- trunk/orca/lib/Orca/DataFile.pm	(original)
+++ trunk/orca/lib/Orca/DataFile.pm	Sat Jul 13 21:07:52 2002
@@ -0,0 +1,116 @@
+# Orca::DataFile: Base class for managing source data, RRD and image files.
+#
+# Copyright (C) 1998, 1999 Blair Zajac and Yahoo!, Inc.
+
+package Orca::DataFile;
+
+use strict;
+use Carp;
+use Exporter;
+use Orca::SourceFileIDs qw(@sfile_fids);
+use vars                qw(@ISA @EXPORT_OK $VERSION);
+
+ at ISA       = qw(Exporter);
+ at EXPORT_OK = qw(ORCA_DATAFILE_LAST_INDEX);
+$VERSION   = substr q$Revision: 0.01 $, 10;
+
+# Use a blessed reference to an array as the storage for this class.
+# Define these constant subroutines as indexes into the array.
+sub I_FID                    () { 0 }
+sub I_LAST_STAT_TIME         () { 1 }
+sub I_FILE_DEV               () { 2 }
+sub I_FILE_INO               () { 3 }
+sub I_FILE_SIZE              () { 4 }
+sub I_FILE_MTIME             () { 5 }
+sub ORCA_DATAFILE_LAST_INDEX () { 5 }
+
+sub new {
+  unless (@_ == 2) {
+    confess "$0: Orca::DataFile::new passed wrong number of arguments.\n";
+  }
+
+  my ($class, $fid) = @_;
+
+  confess "$0: fid not passed to $class.\n" unless defined($fid);
+  confess "$0: numeric fid not passed to $class.\n" unless $fid =~ /^\d+$/;
+  my $self = bless [$fid, -1, -1, -1, -1, -1], $class;
+  $self;
+}
+
+sub fid {
+  $_[0]->[I_FID];
+}
+
+sub last_stat_time {
+  $_[0]->[I_LAST_STAT_TIME];
+}
+
+sub file_dev {
+  $_[0]->[I_FILE_DEV];
+}
+
+sub file_ino {
+  $_[0]->[I_FILE_INO];
+}
+
+sub file_size {
+  $_[0]->[I_FILE_SIZE];
+}
+
+sub file_mtime {
+  $_[0]->[I_FILE_MTIME];
+}
+
+# Return 1 if the file exists, 0 otherwise.
+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.
+  my $time = time;
+  if ($time > $self->[I_LAST_STAT_TIME] + 1) {
+    if (my @stat = stat($sfile_fids[$self->[I_FID]])) {
+      @$self[I_FILE_DEV, I_FILE_INO, I_FILE_SIZE, I_FILE_MTIME] =
+        @stat[0, 1, 7, 9];
+    } else {
+      @$self[I_FILE_DEV, I_FILE_INO, I_FILE_SIZE, I_FILE_MTIME] =
+        (-1, -1, -1, -1);
+    }
+    $self->[I_LAST_STAT_TIME] = $time;
+  }
+
+  $self->[I_FILE_MTIME] != -1;
+}
+
+# Return a status depending upon the file:
+#   -1 if the file does not exist.
+#    0 if the file has not been updated since the last status check.
+#    1 if the file has been updated since the last status check.
+#    2 if the file has a new device or inode since the last status check.
+sub status {
+  my $self = shift;
+
+  # Save the old state.
+  my ($fid, $file_dev, $file_ino, $file_size, $file_mtime) =
+    @$self[I_FID, I_FILE_DEV, I_FILE_INO, I_FILE_SIZE, I_FILE_MTIME];
+
+  my $result = 0;
+  if ($self->update_stat) {
+    if ($self->[I_FILE_DEV] != $file_dev or
+        $self->[I_FILE_INO] != $file_ino) {
+      $result = 2;
+    } elsif ($self->[I_FILE_MTIME] != $file_mtime or
+           $self->[I_FILE_SIZE]  != $file_size) {
+      $result = 1;
+    }
+  } else {
+    $result = -1;
+  }
+
+  $result;
+}
+
+1;

Added: trunk/orca/lib/Orca/NewState.pm
==============================================================================
--- trunk/orca/lib/Orca/NewState.pm	(original)
+++ trunk/orca/lib/Orca/NewState.pm	Sat Jul 13 21:07:52 2002
@@ -0,0 +1,254 @@
+# Orca::NewState: Keep state information between invocations of Orca.
+#
+# Copyright (C) 1998, 1999 Blair Zajac and Yahoo!, Inc.
+
+package Orca::NewState;
+
+use strict;
+use Carp;
+use Storable        qw(nstore_fd retrieve_fd);
+use Orca::Constants qw($opt_verbose
+                       die_when_called);
+use vars            qw(@EXPORT_OK @ISA $VERSION);
+
+ at ISA     = qw(Exporter);
+$VERSION = substr q$Revision: 0.01 $, 10;
+
+# Create one global state object for the whole program.
+use vars      qw($orca_state);
+ at EXPORT_OK  = qw($orca_state);
+$orca_state = Orca::NewState->new;
+
+# This defines the minimum version of saved state file required.
+my $required_version = "1.0";
+
+# The following variables are stored from and restored to from the
+# given packages.  While importing the packages are not necessary,
+# they do provide error checking in case a mistake is made in
+# naming a package name and/or variable.
+use vars qw(@source_file_ids @source_files);
+BEGIN {
+  @source_file_ids = qw(%sfile_fids
+                        @sfile_fids
+                        @sfile_unused_fids);
+  @source_files    = qw(@sfile_file_dev
+                        @sfile_file_ino
+                        @sfile_file_mtime
+                        @sfile_last_stat_time
+                        @sfile_last_read_time
+                        @sfile_last_data_time
+                        @sfile_cid);
+}
+use Orca::SourceFileIDs @source_file_ids;
+use Orca::SourceFiles   @source_files;
+
+# This is a list of references to objects to save and restore.
+my @store_restore_list;
+
+# This subroutine takes a package name and a list of variable names in that
+# package that should be saved.  Using the package and variable names, it
+# goes into Perl's symbol table to get references to these variables.
+sub save_variables {
+  my ($caller_package, @vars) = @_;
+  foreach my $var (@vars) {
+    my ($type, $symbol) = unpack('a1a*', $var);
+    no strict 'refs';
+    push(@store_restore_list,
+      $type eq '$' ? \$ {"${caller_package}::$symbol"} :
+      $type eq '@' ? \@ {"${caller_package}::$symbol"} :
+      $type eq '%' ? \% {"${caller_package}::$symbol"} :
+      do {
+        confess "$0: internal error: Orca::NewState::save_variables cannot save `$var'.\n";
+      }
+    );
+    use strict;
+  }
+}
+save_variables('Orca::SourceFileIDs', @source_file_ids);
+save_variables('Orca::SourceFiles',   @source_files);
+
+sub new {
+  unless (@_ == 1 or @_ == 2) {
+    confess "$0: Orca::NewState::new passed wrong number of arguments.\n";
+  }
+
+  my $class = shift;
+
+  my $self = bless {}, $class;
+
+  if (@_) {
+    $self->load(@_);
+  }
+
+  $self;
+}
+
+sub exists {
+  unless (@_ == 2) {
+    confess "$0: Orca::NewState::exists passed wrong number of arguments.\n";
+  }
+
+  exists $_[0]->{$_[1]};
+}
+
+sub fetch {
+  $_[0]->{$_[1]};
+}
+
+sub load {
+  unless (@_ == 2) {
+    confess "$0: Orca::NewState::load passed wrong number of arguments.\n";
+  }
+
+  my ($self, $filename) = @_;
+
+  return unless -r $filename;
+
+  print "Loading state from `$filename'.\n" if $opt_verbose;
+
+  if (open(STATE, $filename)) {
+    binmode(STATE);
+    my $result = $self->_load_state($filename, \*STATE);
+    close(STATE) or
+      warn "$0: error in closing `$filename' for reading: $!\n";
+    if (defined $result) {
+      return $result;
+    } else {
+      warn "$0: cannot use state file `$filename'.\n";
+      return;
+    }
+  } else {
+    warn "$0: cannot open `$filename' for reading: $!.\n";
+    return;
+  }
+}
+
+sub _load_state {
+return;
+  unless (@_ == 3) {
+    confess "$0: Orca::NewState::load passed wrong number of arguments.\n";
+  }
+
+  my ($self, $filename, $fd) = @_;
+
+  # Determine the version of the state file and ignore it if it is an old
+  # version.
+  my $line = <$fd>;
+  chomp($line);
+  unless ($line) {
+    warn "$0: ignoring unknown version state file `$filename'.\n";
+    return;
+  }
+  if ($line =~ /_filename/) {
+    warn "$0: ignoring old state file `$filename'.\n";
+    return;
+  }
+  my ($version, $number_objects) = $line =~ /(\d+\.\d+)\D+(\d+)/;
+  unless ($version) {
+    warn "$0: ignoring unknown version state file `$filename'.\n";
+    return;
+  }
+  if ($version < $required_version) {
+    warn "$0: ignoring old $version state file `$filename' when version $required_version is required.\n";
+    return;
+  }
+  unless ($number_objects) {
+    warn "$0: cannot detmine number of objects in state file `$filename'.\n";
+    return;
+  }
+  unless ($number_objects == @store_restore_list) {
+    warn "$0: incorrect number of saved objects in state file `$filename'.\n";
+    return;
+  }
+
+  # Go through all of the objects, try to load them in, and if they all are
+  # loaded, then copy them over to the final location.
+  my @restored_objects;
+  my $ok = 1;
+  {
+    eval {
+      local $SIG{__DIE__}  = 'DEFAULT';
+      local $SIG{__WARN__} = \&die_when_called;
+      foreach (@store_restore_list) {
+        my $data = retrieve_fd($fd);
+        if ($data) {
+          push(@restored_objects, $data);
+        } else {
+          $ok = 0;
+          last;
+        }
+      }
+    };
+  }
+  if ($@) {
+    warn "$0: warning: cannot read state file `$filename': $@\n";
+    return;
+  } elsif (!$ok) {
+    warn "$0: warning: cannot load data from state file `$filename': $!\n";
+    return;
+  }
+
+  # Copy the loaded data into the final location.
+  for (my $i=0; $i<@store_restore_list; ++$i) {
+    my $ref = $store_restore_list[$i];
+    if (UNIVERSAL::isa($ref, "SCALAR")) {
+      $$ref = ${$restored_objects[$i]};
+    } elsif (UNIVERSAL::isa($ref, "ARRAY")) {
+      @$ref = @{$restored_objects[$i]};
+    } elsif (UNIVERSAL::isa($ref, "HASH")) {
+      %$ref = %{$restored_objects[$i]};
+    } else {
+      die "$0: internal error: restoring a ", ref($ref), " which is unknown.\n";
+    }
+  }
+  1;
+}
+
+sub flush {
+  unless (@_ == 2) {
+    confess "$0: Orca::NewState::flush passed wrong number of arguments.\n";
+  }
+
+  my ($self, $filename) = @_;
+  my $tmp_filename      = "$filename.tmp";
+  print "Saving state into `$filename'.\n" if $opt_verbose;
+
+  unless (open(STATE, "> $tmp_filename")) {
+    warn "$0: cannot open `$tmp_filename' for writing: $!\n";
+    return;
+  }
+
+  print STATE "Orca state file version $required_version with ",
+    scalar(@store_restore_list), " saved objects.\n";
+
+  # Write the saved objects to disk.
+  my $result = 1;
+  foreach my $ref (@store_restore_list) {
+    $result = $result && nstore_fd($ref, \*STATE);
+  }
+
+  unless ($result) {
+    warn "$0: error in writing to `$tmp_filename': $!\n";
+  }
+
+  unless (close(STATE)) {
+    $result = 0;
+    warn "$0: error in closing `$tmp_filename' for writing: $!\n";
+  }
+
+  unless ($result) {
+    warn "$0: cannot flush state to file `$tmp_filename': $!\n";
+    unlink($tmp_filename) or
+      warn "$0: error in unlinking `$tmp_filename': $!\n";
+    return;
+  }
+
+  unless (rename($tmp_filename, $filename)) {
+    warn "$0: cannot rename `$tmp_filename' to `$filename': $!\n";
+    return;
+  }
+
+  1;
+}
+
+1;

Added: trunk/orca/lib/Orca/Constants.pm
==============================================================================
--- trunk/orca/lib/Orca/Constants.pm	(original)
+++ trunk/orca/lib/Orca/Constants.pm	Sat Jul 13 21:07:52 2002
@@ -0,0 +1,108 @@
+# Orca::Constants.pm: Global constants for Orca.
+#
+# Copyright (C) 1998, 1999 Blair Zajac and Yahoo!, Inc.
+
+package Orca::Constants;
+
+use strict;
+use Exporter;
+use vars qw(@EXPORT_OK @ISA $VERSION $ORCA_VERSION $ORCA_RRD_VERSION);
+
+ at ISA     = qw(Exporter);
+$VERSION = substr q$Revision: 0.01 $, 10;
+
+# Define the constants.
+
+# ORCA_VERSION		This version of Orca.
+# ORCA_RRD_VERSION	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.
+# DAY_SECONDS		The number of seconds in one day.
+$ORCA_VERSION        =    '0.26beta1';
+$ORCA_RRD_VERSION    =    19990222;
+sub DAY_SECONDS      () { 24*60*60 };
+push(@EXPORT_OK, qw($ORCA_VERSION $ORCA_RRD_VERSION DAY_SECONDS));
+
+# These define the name of the different RRAs create in each RRD file,
+# how many primary data points go into a consolidated data point, and
+# how far back in time they go.
+#
+# The first RRA 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 first array holds the names of the different plot types to
+# create.  The second array holds the number of 300 second intervals
+# are used to create a consolidated data point.  The third array is
+# the number of consolidated data points held in the RRA.
+use vars         qw(@RRA_PLOT_TYPES @RRA_PDP_COUNTS @RRA_ROW_COUNTS);
+push(@EXPORT_OK, qw(@RRA_PLOT_TYPES @RRA_PDP_COUNTS @RRA_ROW_COUNTS));
+ at RRA_PLOT_TYPES = qw(daily weekly monthly yearly);
+ at RRA_PDP_COUNTS =   (    1,     6,     24,   288);
+ at RRA_ROW_COUNTS =   ( 2400,  1488,   1200,  1098);
+
+# Define the different plots to create.  These settings do not need to
+# be exactly the same as the RRA definitions, but they can be.  Here
+# create a quarterly plot (100 days) between the monthly and yearly
+# plots.  The quarterly plot is updated daily.  The last array here
+# holds the number of days back in time to place data in the plot.  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
+# image, 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 image should be at least 481
+# pixels wide.
+use vars         qw(@IMAGE_PLOT_TYPES @IMAGE_PDP_COUNTS @IMAGE_DAYS_BACK);
+push(@EXPORT_OK, qw(@IMAGE_PLOT_TYPES @IMAGE_PDP_COUNTS @IMAGE_DAYS_BACK));
+ at IMAGE_PLOT_TYPES = (@RRA_PLOT_TYPES[0..2], 'quarterly', $RRA_PLOT_TYPES[3]);
+ at IMAGE_PDP_COUNTS = (@RRA_PDP_COUNTS[0..2], @RRA_PDP_COUNTS[3, 3]);
+ at IMAGE_DAYS_BACK  = (  1.5,  10,  40, 100, 428);
+# Data points ->    (432  , 480, 480, 100, 428);
+
+# This subroutine is compiled once to prevent compiling of the
+# subroutine sub { die $_[0] } every time an eval block is entered.
+sub die_when_called {
+  die $_[0];
+}
+push(@EXPORT_OK, qw(die_when_called));
+
+# These variables are set once at program start depending upon the
+# command line arguments.
+#
+# $opt_generate_gifs		Generate GIFs instead of PNGs.
+# $opt_once_only		Do only one pass through Orca.
+# $opt_rrd_update_only		Do not generate any images.
+# $opt_verbose			Be verbose about my running.
+#
+use vars         qw($opt_generate_gifs
+                    $opt_once_only
+                    $opt_rrd_update_only
+                    $opt_verbose
+                    $IMAGE_SUFFIX);
+push(@EXPORT_OK, qw($opt_generate_gifs
+                    $opt_once_only
+                    $opt_rrd_update_only
+                    $opt_verbose
+                    $IMAGE_SUFFIX));
+$opt_generate_gifs   = 0;
+$opt_once_only       = 0;
+$opt_rrd_update_only = 0;
+$opt_verbose         = 0;
+$IMAGE_SUFFIX        = 'png';
+
+# This contains the regular expression string to check if a string
+# contains the "sub {" and "}" portions or this should be added.
+use vars         qw($is_sub_re);
+push(@EXPORT_OK, qw($is_sub_re));
+$is_sub_re = '^\s*sub\s*{.*}\s*$';
+
+# This constant stores the commonly used string to indicate that a
+# subroutine has been passed an incorrect number of arguments.
+use vars qw($incorrect_number_of_args);
+push(@EXPORT_OK, qw($incorrect_number_of_args));
+$incorrect_number_of_args = "passed incorrect number of arguments.\n";
+
+1;

Added: trunk/orca/lib/Orca/OldState.pm
==============================================================================
--- trunk/orca/lib/Orca/OldState.pm	(original)
+++ trunk/orca/lib/Orca/OldState.pm	Sat Jul 13 21:07:52 2002
@@ -0,0 +1,144 @@
+# Orca::OldState: Keep state information between invocations of Orca.
+#
+# Copyright (C) 1998-2000 Blair Zajac and Yahoo!, Inc.
+
+package Orca::OldState;
+
+use strict;
+use Carp;
+use Orca::Constants     qw($opt_verbose
+                           $incorrect_number_of_args);
+use Orca::SourceFileIDs qw(@sfile_fids);
+use vars                qw(@EXPORT_OK @ISA $VERSION);
+
+ at ISA     = qw(Exporter);
+$VERSION = substr q$Revision: 0.01 $, 10;
+
+# Create one global state object for the whole program.
+use vars          qw($orca_old_state);
+ at EXPORT_OK      = qw($orca_old_state load_old_state save_old_state);
+$orca_old_state = {};
+
+# If this string appears in the beginning of the first column
+# description name, then it signifies that the text following the
+# string is the filename that contains a column description that this
+# particular file should use.
+my $refer_to_filename_marker = 'USETHISFILE';
+
+# This loads the old source file state information.
+sub load_old_state {
+  unless (@_ == 1) {
+    confess "$0: Orca::OldState::load_old_state $incorrect_number_of_args";
+  }
+
+  my $state_file = shift;
+
+  unless (open(STATE, $state_file)) {
+    warn "$0: warning: cannot open state file `$state_file' for reading: $!\n";
+    return;
+  }
+
+  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.
+  my $line = <STATE>;
+  defined($line) or return;
+  chomp($line);
+  my @keys = split(' ', $line);
+  unless ($keys[0] eq '_filename') {
+    warn "$0: warning: ignoring state file `$state_file': incorrect first field.\n";
+    return;
+  }
+
+  my %file_column_descriptions;
+
+  while (<STATE>) {
+    my @line = split;
+    if (@line != 3 && @line < 8) {
+      warn "$0: incorrect number of elements on line $. of `$state_file'.\n";
+      next;
+    }
+
+    my $filename  = shift(@line);
+    my @stat_info;
+    if (@line == 2) {
+      @stat_info = (@line, -1, -1, -1, -1, undef);
+    } else {
+      @stat_info = splice(@line, 0, 6);
+      if ($line[0] =~ s/^$refer_to_filename_marker//o) {
+        push(@stat_info, $file_column_descriptions{$line[0]});
+      } else {
+        $file_column_descriptions{$filename} = \@line;
+        push(@stat_info, \@line);
+      }
+    }
+    $orca_old_state->{$filename} = \@stat_info;
+  }
+
+  close(STATE) or
+    warn "$0: warning: cannot close `$state_file' for reading: $!\n";
+
+  1;
+}
+
+# Write the state information for the source data files.
+sub save_old_state {
+  unless (@_ == 2) {
+    confess "$0: Orca::OldState::save_old_state $incorrect_number_of_args";
+  }
+
+  my ($state_file, $state_ref) = @_;
+
+  print "Saving state into `$state_file'.\n" if $opt_verbose;
+
+  if (open(STATE, "> $state_file.tmp")) {
+
+    print STATE "_filename _last_data_time _last_read_time\n";
+
+    my %file_column_descriptions;
+
+    foreach my $fid (keys %$state_ref) {
+      my $object_ref = $state_ref->{$fid};
+      my $filename   = $sfile_fids[$fid];
+      print STATE
+        "$filename ",
+        $object_ref->[&Orca::SourceFile::I_LAST_DATA_TIME], ' ',
+        $object_ref->[&Orca::SourceFile::I_LAST_READ_TIME], ' ',
+        $object_ref->[&Orca::DataFile::I_FILE_DEV], ' ',
+        $object_ref->[&Orca::DataFile::I_FILE_INO], ' ',
+        $object_ref->[&Orca::DataFile::I_FILE_SIZE], ' ',
+        $object_ref->[&Orca::DataFile::I_FILE_MTIME];
+        my $column_ref = $object_ref->[&Orca::SourceFile::I_COLUMN_DESCRIPTION];
+        if (my $f = $file_column_descriptions{"$column_ref"}) {
+          print STATE " $refer_to_filename_marker$f\n";
+        } else {
+          print STATE " @$column_ref\n";
+          $file_column_descriptions{"$column_ref"} = $filename;
+        }
+    }
+
+    if (close(STATE)) {
+      unless (rename("$state_file.tmp", $state_file)) {
+        my $print_warning = 1;
+        if (-e $state_file) {
+          if (unlink($state_file)) {
+            $print_warning = !rename("$state_file.tmp", $state_file);
+          } else {
+            $print_warning = 0;
+            warn "$0: warning: cannot unlink old `$state_file': $!\n";
+          }
+        }
+        if ($print_warning) {
+          warn "$0: warning: cannot rename `$state_file.tmp' to `$state_file': $!\n";
+        }
+      }
+    } else {
+      warn "$0: warning: cannot close `$state_file' for writing: $!\n";
+    }
+  } else {
+    warn "$0: warning: cannot open state file `$state_file.tmp' for writing: $!\n";
+  }
+}
+
+1;

Added: trunk/orca/lib/Orca/SourceFile.pm
==============================================================================
--- trunk/orca/lib/Orca/SourceFile.pm	(original)
+++ trunk/orca/lib/Orca/SourceFile.pm	Sat Jul 13 21:07:53 2002
@@ -0,0 +1,889 @@
+# Orca::SourceFile: Manage the watching and loading of source data files.
+#
+# Copyright (C) 1998, 1999 Blair Zajac and Yahoo!, Inc.
+
+package Orca::SourceFile;
+
+use strict;
+use Carp;
+use Digest::MD5         qw(md5);
+use Storable            qw(dclone);
+use Orca::Constants     qw($opt_verbose
+                           $incorrect_number_of_args
+                           die_when_called);
+use Orca::Config        qw(%config_options
+                           %config_groups
+                           @config_plots
+                           get_color);
+use Orca::OldState      qw($orca_old_state);
+use Orca::DataFile      qw(ORCA_DATAFILE_LAST_INDEX);
+use Orca::OpenFileHash  qw($open_file_cache);
+use Orca::SourceFileIDs qw(@sfile_fids);
+use Orca::ImageFile;
+use Orca::RRDFile;
+use vars                qw(@ISA $VERSION);
+
+ at ISA     = qw(Orca::DataFile);
+$VERSION = substr q$Revision: 0.01 $, 10;
+
+# This is a static variable that lists all of the column names for a
+# particular group.
+my %group_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_rrd_list_cache;
+my %choose_data_sub_cache;
+
+# Use a blessed reference to an array as the storage for this class.
+# Since this class is a subclass of Orca::DataFile, append to the
+# end of the Orca::DataFile array the values needed by this class
+# using the ORCA_DATAFILE_LAST_INDEX index.  Define these constant
+# subroutines as indexes into the array.  If the order of these
+# indexes change, make sure to rearrange the constructor in new.
+sub I_INTERVAL           () { ORCA_DATAFILE_LAST_INDEX +  1 }
+sub I_LATE_INTERVAL      () { ORCA_DATAFILE_LAST_INDEX +  2 }
+sub I_READ_INTERVAL      () { ORCA_DATAFILE_LAST_INDEX +  3 }
+sub I_REOPEN             () { ORCA_DATAFILE_LAST_INDEX +  4 }
+sub I_DATE_SOURCE        () { ORCA_DATAFILE_LAST_INDEX +  5 }
+sub I_DATE_FORMAT        () { ORCA_DATAFILE_LAST_INDEX +  6 }
+sub I_WARN_EMAIL         () { ORCA_DATAFILE_LAST_INDEX +  7 }
+sub I_MY_RRD_LIST        () { ORCA_DATAFILE_LAST_INDEX +  8 }
+sub I_ALL_RRD_REF        () { ORCA_DATAFILE_LAST_INDEX +  9 }
+sub I_GROUP_KEYS         () { ORCA_DATAFILE_LAST_INDEX + 10 }
+sub I_CHOOSE_DATA_SUB    () { ORCA_DATAFILE_LAST_INDEX + 11 }
+sub I_COLUMN_DESCRIPTION () { ORCA_DATAFILE_LAST_INDEX + 12 }
+sub I_LAST_DATA_TIME     () { ORCA_DATAFILE_LAST_INDEX + 13 }
+sub I_LAST_READ_TIME     () { ORCA_DATAFILE_LAST_INDEX + 14 }
+sub I_FIRST_LINE         () { ORCA_DATAFILE_LAST_INDEX + 15 }
+sub I_DATE_COLUMN_INDEX  () { ORCA_DATAFILE_LAST_INDEX + 16 }
+sub I_IS_CURRENT         () { ORCA_DATAFILE_LAST_INDEX + 17 }
+sub I_IS_CURRENT_DAY     () { ORCA_DATAFILE_LAST_INDEX + 18 }
+
+sub new {
+  unless (@_ == 9) {
+    confess "$0: Orca::SourceFile::new passed $incorrect_number_of_args";
+  }
+
+  my ($class,
+      $fid,
+      $interval,
+      $late_interval,
+      $reopen,
+      $column_description,
+      $date_source,
+      $date_format,
+      $warn_email) = @_;
+
+  my $self = $class->SUPER::new($fid);
+
+  # Set the last value to preexpand the array.
+  $self->[I_IS_CURRENT_DAY]     = undef;
+  $self->[I_INTERVAL]           = $interval;
+  $self->[I_LATE_INTERVAL]      = int(&$late_interval($interval) + 0.5);
+  $self->[I_REOPEN]             = $reopen;
+  $self->[I_DATE_SOURCE]        = $date_source;
+  $self->[I_DATE_FORMAT]        = $date_format;
+  $self->[I_WARN_EMAIL]         = $warn_email;
+  $self->[I_MY_RRD_LIST]        = [];
+  $self->[I_ALL_RRD_REF]        = undef;
+  $self->[I_GROUP_KEYS]         = {};
+  $self->[I_CHOOSE_DATA_SUB]    = undef;
+
+  $self->[I_COLUMN_DESCRIPTION] = $column_description;
+  $self->[I_LAST_DATA_TIME]     = -1;
+  $self->[I_LAST_READ_TIME]     = -1;
+  $self->[I_FIRST_LINE]         =  0;
+  $self->[I_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.
+  my $read_interval = sqrt($self->[I_INTERVAL]*$self->[I_LATE_INTERVAL]);
+  $self->[I_READ_INTERVAL] = int($read_interval + 0.5);
+
+  # Load in any state information for this file.
+  my $filename = $sfile_fids[$fid];
+  my @column_description;
+  if (defined (my $ref = delete $orca_old_state->{$filename})) {
+    @$self[I_LAST_DATA_TIME,
+           I_LAST_READ_TIME,
+           &Orca::DataFile::I_FILE_DEV,
+           &Orca::DataFile::I_FILE_INO,
+           &Orca::DataFile::I_FILE_SIZE,
+           &Orca::DataFile::I_FILE_MTIME] = splice(@$ref, 0, 6);
+    @column_description = @{$ref->[0]} if $ref->[0];
+  }
+
+# XXXXX
+#  # Do the following steps if the source data file exists.  If there is
+#  # no entry in the state database for this file, then create a default
+#  # one.  If there is an entry, then check the file's mtime and if they
+#  # do not agree, then make the entry a default one so that the data from
+#  # it will be reloaded.  If the source data file does not exist, then
+#  # make the entry a default one.
+#  my $state;
+#  if ($self->status == -1) {
+#    $state = Orca::
+#  } else {
+#  }
+#  # If the source data file does not exist in the state database, then
+#  # create a new default entry.  If the file does not exist, then reset to 
+#  # If the source file's mtime is the same as stored in the saved
+#  # state file, then load all the information from it, otherwise do
+#  # not keep any of it and load the file freshly.
+#  if ($orca_
+#  if (my $mtime = delete($state->{_file_mtime}) eq $self->file_mtime) {
+#    while (my ($key, $value) = each %$state) {
+#      $self->[$key] = $value;
+#    }
+#  }
+
+  # Now do a stat of the file.
+  my $stat_status = $self->status;
+
+  # Load the column names if the column names are supposed to be loaded
+  # from the file.  Use the cached names if the file has not changed.
+  if ($self->[I_COLUMN_DESCRIPTION][0] eq 'first_line') {
+    if ($stat_status or !@column_description) {
+      my $fd = $open_file_cache->open($fid, $self->file_mtime);
+      return unless $fd;
+      my $line = <$fd>;
+      chomp($line);
+      if ($line) {
+        $self->[I_FIRST_LINE] = 1;
+        @column_description = split(' ', $line);
+      } else {
+        warn "$0: warning: no first_line for `$filename' yet.\n";
+        $open_file_cache->close($fid) or
+          warn "$0: warning: cannot close `$filename' for reading: $!\n";
+        return;
+      }
+    }
+    my $cache_key = md5(join("\200", @column_description));
+    unless (defined $first_line_cache{$cache_key}) {
+      $first_line_cache{$cache_key} = \@column_description;
+    }
+    $self->[I_COLUMN_DESCRIPTION] = $first_line_cache{$cache_key};
+  }
+
+  # 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->[I_IS_CURRENT] = $self->is_current;
+
+  return unless $self->get_date_column;
+
+  $self;
+}
+
+# For each group make a note of the column description names that appear.
+sub add_groups {
+  my $self = shift;
+
+  foreach my $group_name (@_) {
+    $self->[I_GROUP_KEYS]{$group_name} = 1;
+    foreach my $description (@{$self->[I_COLUMN_DESCRIPTION]}) {
+      $group_column_names{$group_name}{$description} = 1;
+    }
+  }
+}
+
+# Return 1 if the source data file is current or 0 otherwise.  Also
+# 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 day.
+sub is_current {
+  my $self = shift;
+
+  $self->[I_IS_CURRENT_DAY] = (localtime)[3];
+
+  $self->last_stat_time <= $self->file_mtime + $self->[I_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.
+sub next_load_time {
+  my $self = shift;
+
+  my $last_stat_time = $self->last_stat_time;
+  my $file_mtime     = $self->file_mtime;
+
+  if ($last_stat_time <= $file_mtime + $self->[I_LATE_INTERVAL]) {
+    return $file_mtime + $self->[I_READ_INTERVAL];
+  } else {
+    return $last_stat_time + $self->[I_LATE_INTERVAL];
+  }
+}
+
+sub get_date_column {
+  my $self = shift;
+
+  return $self if $self->[I_DATE_SOURCE][0] eq 'file_mtime';
+
+  my $fid              = $self->fid;
+  my $date_column_name = $self->[I_DATE_SOURCE][1];
+
+  my $found = -1;
+  for (my $i=0; $i<@{$self->[I_COLUMN_DESCRIPTION]}; ++$i) {
+    if ($self->[I_COLUMN_DESCRIPTION][$i] eq $date_column_name) {
+      $found = $i;
+      last;
+    }
+  }
+
+  unless ($found > -1) {
+    warn "$0: warning: cannot find date `$date_column_name' in `$sfile_fids[$fid]'.\n";
+warn "@{$self->[I_COLUMN_DESCRIPTION]}\n";
+    return;
+  }
+  $self->[I_DATE_COLUMN_INDEX] = $found;
+
+  $self;
+}
+
+sub add_plots {
+  # Make sure that the user has called the add_groups method and
+  # inserted at least one key.
+  unless (keys %group_column_names) {
+    confess "$0: Orca::SourceFile::add_groups must be called before add_plots.\n";
+  }
+
+  unless (@_ == 5) {
+    confess "$0: Orca::SourceFile::add_plots passed wrong number of arguments.\n";
+  }
+
+  my ($self,
+      $group_name,
+      $subgroup_name,
+      $rrd_data_files_ref,
+      $image_files_ref) = @_;
+
+  # See if we have already done all the work for a plot with this group_name,
+  # subgroup_name, 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
+  # group.  Finally, create a hash keyed by column name with a value of the
+  # index into the column description array.
+  my @column_description = @{$self->[I_COLUMN_DESCRIPTION]};
+  my %column_description;
+  for (my $i=0; $i<@column_description; ++$i) {
+    $column_description{$column_description[$i]} = $i;
+  }
+  my $plot_key  = join("\200", $group_name,
+                               $subgroup_name,
+                               @column_description);
+  my $cache_key = md5($plot_key);
+  if (defined $all_rrds_cache{$cache_key}) {
+    $self->[I_ALL_RRD_REF]     = $all_rrds_cache{$cache_key};
+    $self->[I_MY_RRD_LIST]     = $my_rrd_list_cache{$cache_key};
+    $self->[I_CHOOSE_DATA_SUB] = $choose_data_sub_cache{$cache_key};
+    return 1;
+  }
+
+  # Use this hash to keep a list of RRDs that this file uses.
+  my %my_rrd_list;
+
+  # This is the source for an anonymous subroutine that given a row
+  # from a source data file returns a hash keyed by RRD name with the
+  # values calculated from the row.
+  my $choose_data_expr = "sub {\n  (\n";
+
+  # Go through each plot to create and process it for this file.
+  my @regexp_pos          = map { 0 } (1.. at config_plots);
+  my $oldest_regexp_index = 0;
+  my $handle_regexps      = 0;
+  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.
+  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 ($handle_regexps and $i >= @config_plots) {
+      $i = $oldest_regexp_index;
+    }
+
+    my $plot = $config_plots[$i];
+
+    # Skip this plot if the group_name do not match.  Increment the
+    # index of the next plot to handle.
+    if ($plot->{source} ne $group_name) {
+      if ($oldest_regexp_index == $i) {
+        $handle_regexps = 0;
+        ++$oldest_regexp_index;
+      }
+      ++$i;
+      next;
+    }
+
+    # There are three cases to handle:
+    # 1) Regular expression match in the first data with additional datas.
+    # 2) Regular expression match in the first data with no additional datas.
+    # 3) All others.
+    # The first is a single data source that has a regular expression.  In
+    # this case, all of the columns are searched to match the regular
+    # expression.  This generates a single plot with all of the different
+    # data sources plotted on it.  The second case is two or more data
+    # sources and where the first data source has a regular expression
+    # match.  This may generate more than one plot, for each set of columns
+    # that match the regular expression.  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 $regexp_element_index = -1;
+    for (my $j=0; $j<@{$plot->{data}[0]}; ++$j) {
+      if ($plot->{data}[0][$j] =~ m:\(.+\):) {
+        $regexp_element_index = $j;
+        last;
+      }
+    }
+
+    # 1) Regular expression match in the first data with additional datas.
+    if ($number_datas == 1 and $regexp_element_index != -1) {
+
+      # If we've gone up to the last column to match, then go on.
+      if ($regexp_pos[$i] >= @column_description) {
+        if ($oldest_regexp_index == $i) {
+          $handle_regexps = 0;
+          ++$oldest_regexp_index;
+        }
+        $i = $plot->{flush_regexps} ? $oldest_regexp_index : $i + 1;
+        next;
+      }
+      $regexp_pos[$i] = @column_description;
+
+      # 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.  Replace the regular expression in the first data
+      # with the name of the column that caused the match.
+      my $creates          = delete $plot->{creates};
+      my $new_plot         = dclone($plot);
+      $plot->{creates}     = $creates;
+      $new_plot->{creates} = $creates;
+      $plot                = $new_plot;
+
+      # 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.
+      my @data_with_regexp = @{$plot->{data}[0]};
+      my $regexp           = $data_with_regexp[$regexp_element_index];
+      my $new_data_index   = 0;
+      my $original_legend  = $plot->{legend}[0];
+      foreach my $column_name (@column_description) {
+        my @matches = $column_name =~ /$regexp/;
+        next unless @matches;
+
+        # Replace the regular expression match with the matched column
+        # name.
+        $data_with_regexp[$regexp_element_index] = $column_name;
+        $plot->{data}[$new_data_index] = [ @data_with_regexp ];
+
+        # 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.
+        unless (defined $plot->{color}[$new_data_index]) {
+          $plot->{color}[$new_data_index] = get_color($new_data_index);
+        }
+        unless (defined $plot->{legend}[$new_data_index]) {
+          $plot->{legend}[$new_data_index] = $original_legend;
+        }
+        unless (defined $plot->{line_type}[$new_data_index]) {
+          $plot->{line_type}[$new_data_index] = $plot->{line_type}[0];
+        }
+
+        # Replace the regular expression in any legend elements.
+        my $legend = $plot->{legend}[$new_data_index];
+        my $count  = 1;
+        foreach my $match (@matches) {
+          $legend =~ s/\$$count/$match/ge;
+          $legend =~ s/\(.+\)/$match/ge;
+          ++$count;
+        }
+        $plot->{legend}[$new_data_index] = $legend;
+
+        ++$new_data_index;
+      }
+
+      if ($oldest_regexp_index == $i) {
+        $handle_regexps = 0;
+        ++$oldest_regexp_index;
+      }
+      $old_i = $i;
+      $i = $plot->{flush_regexps} ? $oldest_regexp_index : $i + 1;
+      next unless $new_data_index;
+    }
+
+    # 2) Regular expression match in the first data with no additional datas.
+    elsif ($number_datas > 1 and $regexp_element_index != -1) {
+      $handle_regexps = 1;
+
+      # If we've gone up to the last column to match, then go on.  If
+      # this is the oldest regexp, then increment oldest_regexp_index.
+      if ($regexp_pos[$i] >= @column_description) {
+        if ($oldest_regexp_index == $i) {
+          $handle_regexps = 0;
+          ++$oldest_regexp_index;
+        }
+        $i = $plot->{flush_regexps} ? $oldest_regexp_index : $i + 1;
+        next;
+      }
+
+      # Go through all of the columns and stop at the first match.
+      my @data_with_regexp = @{$plot->{data}[0]};
+      my $regexp           = $data_with_regexp[$regexp_element_index];
+      my $column_description;
+      my @matches;
+      for (;$regexp_pos[$i]<@column_description; ++$regexp_pos[$i]) {
+        @matches = $column_description[$regexp_pos[$i]] =~ /$regexp/;
+        if (@matches) {
+          $column_description = $column_description[$regexp_pos[$i]];
+          last;
+        }
+      }
+      unless (@matches) {
+        if ($oldest_regexp_index == $i) {
+          ++$oldest_regexp_index;
+          $handle_regexps = 0;
+        }
+        ++$i;
+        next;
+      }
+      ++$regexp_pos[$i];
+
+      # 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.  Replace the regular expression in the first data
+      # with the name of the column that caused the match.  Then create
+      # string form of the plot object using Data::Dumper::Dumper and
+      # replace all of the $1, $2, ... with what was matched in the
+      # first data source.
+      my $creates          = delete $plot->{creates};
+      my $new_plot         = dclone($plot);
+      $plot->{creates}     = $creates;
+      $plot                = $new_plot;
+      $plot->{data}[0][$regexp_element_index] = $column_description;
+      my $d                = Data::Dumper->Dump([$plot], [qw(plot)]);
+      $plot->{creates}     = $creates;
+      my $count            = 1;
+      foreach my $match (@matches) {
+        $d =~ s/\$$count/$match/mge;
+        $d =~ s/\(.+\)/$match/mge;
+        ++$count;
+      }
+      {
+        local $SIG{__DIE__}  = 'DEFAULT';
+        local $SIG{__WARN__} = \&die_when_called;
+        eval $d;
+      }
+      die "$0: internal error: eval on\n   $d\nOutput: $@\n" if $@;
+
+      # Either increment the index or reset it to the oldest regexp
+      # index.
+      $old_i = $i;
+      $i = $plot->{flush_regexps} ? $oldest_regexp_index : $i + 1;
+    }
+
+    # 3) All others.
+    else {
+      $old_i = $i++;
+      ++$oldest_regexp_index unless $handle_regexps;
+    }
+
+    # 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 group.  In this case the data argument for this file
+    # will not be used.
+    my @datas;
+    foreach my $one_data (@{$plot->{data}}) {
+      push(@datas, [@$one_data]);
+    }
+    my $required = $plot->{required};
+    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 $group_column_names{$group_name}{$element}) {
+          my $m = $old_i + 1;
+          if ($required) {
+            warn "$0: $element in `data @{$plot->{data}[$j]}' in plot #$m ",
+                 "not replaced since it is not in file `",
+                 $self->filename, "'.\n";
+          }
+          $datas[$j] = undef;
+          last;
+        }
+      }
+      # If there were no substitutions and verbose is on, then warn about it.
+      if (!$match_one_data and $opt_verbose > 1) {
+        my $m = $old_i + 1;
+        warn "$0: warning: no substitutions performed for ",
+             "`data @{$plot->{data}[$j]}' in plot #$m in `",
+             $self->filename, "'.\n";
+      }
+    }
+
+    # Because users may place code into the data statements that do not
+    # have any substitutions, then the only way to check for the validity
+    # is to create valid anonymous subroutines and try them.  Invalid
+    # ones will either return undef or fail to compile.  If the plot is
+    # required, then replace invalid subroutines with one that returns 0.
+    # Here the results of eval'ing a test subroutine on a data is kept.
+    # The cached result is either a 1 or a 0.  To test the subroutine,
+    # pass the newly created subroutine a fake array of numbers, where the
+    # array has as manay elements as there are in one line from the file.
+    # If it is an invalid subroutine but the plot is required, then set
+    # the subroutine to return 'U', which is RRD's way of declaring
+    # undefined data.
+    my @fake_numbers = 1 .. @column_description;
+    my @substituted_data_expressions;
+    my $one_ok_data = 0;
+    for (my $j=0; $j<@datas; ++$j) {
+      my $data_expression;
+      if (defined $datas[$j]) {
+        $data_expression = "@{$datas[$j]}";
+        my $sub_expr     = "sub { $data_expression }";
+        my $sub_expr_md5 = md5($data_expression);
+        my $eval_result  = $choose_data_sub_cache{$sub_expr_md5};
+        unless (defined $eval_result) {
+          $eval_result = 1;
+          my $test_value;
+          my $message;
+          {
+            local $SIG{__DIE__}  = 'DEFAULT';
+            local $SIG{__WARN__} = \&die_when_called;
+            if (my $sub = eval $sub_expr) {
+              eval { $test_value = &$sub(@fake_numbers) };
+            }
+          }
+          if ($@) {
+            $eval_result = 0;
+            $@ =~ s/\s+$//g;
+            my $m = $old_i + 1;
+            $message = "$0: warning: cannot compile `$sub_expr' for plot #$m `data @{$plot->{data}[$j]}': $@\n";
+          } elsif (!defined $test_value) {
+            $eval_result = 0;
+            my $m = $old_i + 1;
+            $message = "$0: warning: testing of `$sub_expr' for plot #$m `data @{$plot->{data}[$j]}' yielded an undefined value.\n";
+          }
+          if ($message and ($required or $opt_verbose > 1)) {
+            warn $message;
+          }
+          $choose_data_sub_cache{$sub_expr_md5} = $eval_result;
+        }
+        $data_expression = undef unless $eval_result;
+      }
+      # If the data_expression did not work, but the plot is required, then
+      # have the expression return 'U';
+      if (!$data_expression and $plot->{required}) {
+        $data_expression = "'U'";
+      }
+      $one_ok_data = 1 if $data_expression;
+      push(@substituted_data_expressions, $data_expression);
+    }
+
+    # If none of the data expressions compiled, then go on to the next
+    # unless the plot is required.
+    next if (!$one_ok_data and !$required);
+
+    # At this point we have a plot to create.
+
+    # For each valid data source in this plot, place each the substituted
+    # code a large anonymous subroutine that takes a single row of data
+    # from an input source file and returns a hash keyed by the name
+    # used for a RRD and the value calculated using the input row of
+    # data.  Also create an unique Orca data file name for this plot
+    # and a name for this plot that does not include the subgroup name.
+    my @my_rrds;
+    my @my_short_rrds;
+    my @name_with_subgroup;
+    my @name_without_subgroup;
+    my $previous_group    = '';
+    my $previous_subgroup = '';
+    for (my $j=0; $j<@substituted_data_expressions; ++$j) {
+
+      my $original_data_expression    = join('_', @{$plot->{data}[$j]});
+      my $substituted_data_expression = $substituted_data_expressions[$j];
+
+      my $name_with_subgroup = "${group_name}_${subgroup_name}_${original_data_expression}";
+      push(@name_with_subgroup, $name_with_subgroup);
+      push(@name_without_subgroup, "${group_name}_${original_data_expression}");
+
+      # Create a short name that may exclude the group and subgroup if the
+      # previous data had the same group and subgroup.
+      my $short_name_with_subgroup;
+      if ($group_name eq $previous_group) {
+        if ($subgroup_name eq $previous_subgroup) {
+          $short_name_with_subgroup = "__$original_data_expression";
+        } else {
+          $short_name_with_subgroup = "_${subgroup_name}_${original_data_expression}";
+          $previous_subgroup        = $subgroup_name;
+        }
+      } else {
+        $previous_group           = $group_name;
+        $previous_subgroup        = $subgroup_name;
+        $short_name_with_subgroup = $name_with_subgroup;
+      }
+
+      # Create a new RRD only if it doesn't already exist and if a valid
+      # get data subroutine is created.  Keep the choose_data_sub for this
+      # file.
+      if (defined $substituted_data_expression) {
+        $choose_data_expr .= "    '$name_with_subgroup', $substituted_data_expression,\n";
+        unless (defined $rrd_data_files_ref->{$name_with_subgroup}) {
+          my $rrd_file = Orca::RRDFile->new($group_name,
+                                            $subgroup_name,
+                                            $name_with_subgroup,
+                                            $plot);
+          $rrd_data_files_ref->{$name_with_subgroup} = $rrd_file;
+        }
+        $self->[I_ALL_RRD_REF]            = $rrd_data_files_ref;
+        $my_rrd_list{$name_with_subgroup} = 1;
+        push(@my_rrds, $name_with_subgroup);
+        push(@my_short_rrds, $short_name_with_subgroup);
+      }
+    }
+
+    # Generate a new plot for these data.
+    my $image;
+    my $all_names_with_subgroup = join(',', @name_with_subgroup);
+    if (defined ($image = $image_files_ref->{hash}{$all_names_with_subgroup})) {
+      $image->add_rrds(@my_rrds);
+    } else {
+      $image = Orca::ImageFile->new($group_name,
+                                    $subgroup_name,
+                                    join(',', @my_short_rrds),
+                                    join(',', @name_without_subgroup),
+                                    $plot,
+                                    $rrd_data_files_ref,
+                                    \@my_rrds);
+      $image_files_ref->{hash}{$all_names_with_subgroup} = $image;
+      push(@{$image_files_ref->{list}}, $image);
+      push(@{$config_plots[$old_i]{creates}}, $image);
+    }
+
+    # Put into each RRD the images that are generated from it.
+    foreach my $rrd_key (@my_rrds) {
+      $rrd_data_files_ref->{$rrd_key}->add_image($image);
+    }
+  }
+
+  $choose_data_expr .= "  );\n}\n";
+  {
+    local $SIG{__DIE__}        = 'DEFAULT';
+    local $SIG{__WARN__}       = \&die_when_called;
+    $self->[I_CHOOSE_DATA_SUB] = eval $choose_data_expr;
+  }
+  if ($@) {
+    my $m = $old_i + 1;
+    die "$0: warning: bad evaluation of command for plot #$m:\n$choose_data_expr\nOutput: $@\n";
+  }
+
+  $all_rrds_cache{$cache_key}        = $self->[I_ALL_RRD_REF];
+  $choose_data_sub_cache{$cache_key} = $self->[I_CHOOSE_DATA_SUB];
+  my $tmp                            = [sort keys %my_rrd_list];
+  $my_rrd_list_cache{$cache_key}     = $tmp;
+  $self->[I_MY_RRD_LIST]             = $tmp;
+
+  1;
+}
+
+sub load_new_data {
+  my $self = shift;
+
+  my $fid = $self->fid;
+
+  # 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($fid);
+  my $load_data   = $file_status != 0;
+  if ($file_status == -1) {
+    my $message = "file `$sfile_fids[$fid]' did exist and is now gone.";
+    ::email_message($self->[I_WARN_EMAIL], $message);
+    warn "$0: warning: $message\n";
+    unless ($fd) {
+      $self->[I_LAST_READ_TIME] = -1;
+      return 0;
+    }
+  }
+
+  # 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->[I_IS_CURRENT];
+  my $old_is_current_day = $self->[I_IS_CURRENT_DAY];
+  my $current_day        = (localtime($self->last_stat_time))[3];
+  $self->[I_IS_CURRENT]  = $self->is_current;
+  if ($old_is_current and
+      !$self->[I_IS_CURRENT] and
+      ($old_is_current_day == $current_day)) {
+    my $message = "file `$sfile_fids[$fid]' was current and now is not.";
+    warn "$0: warning: $message\n";
+    ::email_message($self->[I_WARN_EMAIL], $message);
+  }
+
+  # If we don't have to load the data from this file yet, then test to
+  # see if the data needs to be loaded if the file modification time
+  # is greater than the time at which it was last read.
+  my $file_mtime = $self->file_mtime;
+  unless ($load_data) {
+    $load_data = $file_mtime > $self->[I_LAST_READ_TIME];
+  }
+
+  # If the file still does not have to be loaded, now test to see if
+  # the timestamp of the last data point is larger than the last time
+  # of any RRD files that depend on this source file.
+  my $last_data_time = $self->[I_LAST_DATA_TIME];
+  unless ($load_data) {
+    foreach my $rrd_key (@{$self->[I_MY_RRD_LIST]}) {
+      if ($self->[I_ALL_RRD_REF]{$rrd_key}->rrd_update_time < $last_data_time) {
+        $load_data = 1;
+        last;
+      }
+    }
+  }
+
+  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.
+
+  my $opened_new_fd = !$fd;
+  unless ($fd) {
+    unless ($fd = $open_file_cache->open($fid, $file_mtime)) {
+      warn "$0: warning: cannot open `$sfile_fids[$fid]' for reading: $!\n";
+      return 0;
+    }
+    <$fd> if $self->[I_FIRST_LINE];
+  }
+
+  # Load in all of the data possible and send it to each plot.
+  my $date_column_index = $self->[I_DATE_COLUMN_INDEX];
+  my $use_file_mtime    = $self->[I_DATE_SOURCE][0] eq 'file_mtime';
+  my $number_added      = 0;
+  my $close_once_done   = 0;
+  my $number_columns    = @{$self->[I_COLUMN_DESCRIPTION]};
+  while (defined(my $line = <$fd>)) {
+    # Skip the line if the word timestamp appears in it.  This is a
+    # temporary fix for orcallator.se to place a new information line
+    # in the output file when it starts up.
+    next if $line =~ /timestamp/;
+
+    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.
+    if ($self->[I_FIRST_LINE] and @line != $number_columns) {
+      warn "$0: number of columns in line $. of `$sfile_fids[$fid]' does not match column description.\n";
+      next;
+    }
+
+    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, calculate
+    # the value that needs to go to each RRD and push the value to the
+    # RRD.
+    my $add    = 0;
+    my %values = &{$self->[I_CHOOSE_DATA_SUB]}(@line);
+    foreach my $rrd_key (@{$self->[I_MY_RRD_LIST]}) {
+      my $value = $values{$rrd_key};
+      if (defined $value) {
+        if ($self->[I_ALL_RRD_REF]{$rrd_key}->queue_data($time, $value)) {
+          if ($opt_verbose > 2 and !$add) {
+            print "  Loaded `@line' at ", scalar localtime($time), " ($time).\n";
+          }
+          $add = 1;
+        }
+      } else {
+        $close_once_done = 1;
+        warn "$0: internal error: expecting RRD name `$rrd_key' but no data loaded from `" . $self->filename . "' at time ", scalar localtime($time), " ($time).\n";
+      }
+    }
+    ++$number_added if $add;
+  }
+
+  # Update the time when the file was last read.
+  $self->[I_LAST_READ_TIME] = time;
+  $self->[I_LAST_DATA_TIME] = $last_data_time;
+
+  $open_file_cache->change_weight($fid, $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.
+  if ($file_status == -1 or ($file_status == 2 and !$opened_new_fd)) {
+    $open_file_cache->close($fid) or
+      warn "$0: warning: cannot close `$sfile_fids[$fid]' for reading: $!\n";
+    if ($file_status != -1) {
+      # Setting the last_read_time to -1 will force load_new_data to
+      # read it.
+      $self->[I_LAST_READ_TIME] = -1;
+      $number_added += $self->load_new_data;
+    }
+  } elsif ($close_once_done or $self->[I_REOPEN]) {
+    $open_file_cache->close($fid) or
+      warn "$0: warning: cannot close `$sfile_fids[$fid]' for reading: $!\n";
+  }
+
+  $number_added;
+}
+
+sub rrds {
+  @{$_[0]->[I_MY_RRD_LIST]};
+}
+
+sub filename {
+  $sfile_fids[$_[0]->fid];
+}
+
+1;

Added: trunk/orca/lib/Orca/Utils.pm
==============================================================================
--- trunk/orca/lib/Orca/Utils.pm	(original)
+++ trunk/orca/lib/Orca/Utils.pm	Sat Jul 13 21:07:53 2002
@@ -0,0 +1,131 @@
+# Orca::Utils: Small utility subroutines.
+#
+# Copyright (C) 1998, 1999 Blair Zajac and Yahoo!, Inc.
+
+package Orca::Utils;
+
+use strict;
+use Carp;
+use Exporter;
+use Orca::Constants     qw($incorrect_number_of_args);
+use Orca::SourceFileIDs qw(new_fids);
+use vars qw(@EXPORT_OK @ISA $VERSION);
+
+ at EXPORT_OK = qw(gcd perl_glob recursive_mkdir unique);
+ at ISA       = qw(Exporter);
+$VERSION   = substr q$Revision: 0.01 $, 10;
+
+# Return the greatest common divisor.
+sub gcd {
+  unless (@_ == 2) {
+    confess "$0: Orca::Utils::gcd $incorrect_number_of_args";
+  }
+  my ($m, $n) = @_;
+  if ($n > $m) {
+    my $tmp = $n;
+    $n = $m;
+    $m = $tmp;
+  }
+  while (my $r = $m % $n) {
+    $m = $n;
+    $n = $r;
+  }
+  $n;
+}
+
+# Find all files matching a particular Perl regular expression and
+# return file ids.
+sub perl_glob {
+  my $regexp = shift;
+
+  # perl_glob gets called recursively.  To tell if we're being called by
+  # perl_glob, look for the existence of two arguments, where the second
+  # one if the current directory to open for matching.
+  my $current_dir = @_ ? $_[0] : '.';
+
+  # Remove all multiple /'s, since they will confuse perl_glob.
+  $regexp =~ s:/{2,}:/:g;
+
+  # If the regular expression begins with a /, then remove it from the
+  # 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.
+  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.
+  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 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) {
+    @matches = grep { -f $_ and -r _ } map { "$current_dir/$_" } @matches;
+    return @_ ? @matches : new_fids(@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.  Make sure not to
+  # process any directories named `..'.
+  my @results;
+  my $new_regexp = join('/', @regexp_elements);
+  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));
+  }
+
+  return @_ ? @results : new_fids(@results);
+}
+
+# Given a directory name, attempt to make all necessary directories.
+sub recursive_mkdir {
+  my $dir = shift;
+
+  # Remove extra /'s.
+  $dir =~ s:/{2,}:/:g;
+
+  my $path;
+  if ($dir =~ m:^/:) {
+    $path = '/';
+  } else {
+    $path = './';
+  }
+
+  my @elements = split(/\//, $dir);
+  foreach my $element (@elements) {
+    $path = "$path/$element";
+    next if -d $path;
+    unless (mkdir($path, 0755)) {
+      die "$0: error: unable to create `$path': $!\n";
+    }
+  }
+}
+
+# Return a list of the unique elements of a list in the same order as
+# they appear in the input list.
+sub unique {
+  my %a;
+  my @unique;
+  foreach my $element (@_) {
+    unless (exists $a{$element}) {
+      push(@unique, $element);
+      $a{$element} = 1;
+    }
+  }
+  @unique;
+}
+
+1;

Added: trunk/orca/lib/Orca/SourceFileIDs.pm
==============================================================================
--- trunk/orca/lib/Orca/SourceFileIDs.pm	(original)
+++ trunk/orca/lib/Orca/SourceFileIDs.pm	Sat Jul 13 21:07:53 2002
@@ -0,0 +1,169 @@
+# Orca::SourceFileIDs: Associate long filenames with numeric
+# identifiers.  The primary purpose of this module is to keep only two
+# copies of all the filenames used by Orca.
+#
+# Copyright (C) 1999 Blair Zajac and Yahoo!, Inc.
+
+package Orca::SourceFileIDs;
+
+use strict;
+use Carp;
+use Math::IntervalSearch qw(interval_search);
+use vars                 qw(@EXPORT_OK @ISA $VERSION);
+
+ at ISA     = qw(Exporter);
+$VERSION = substr q$Revision: 0.01 $, 10;
+
+# This module contains three variables.  The first is a hash keyed by
+# filename with a numeric value.  The second is an array, where value
+# associated with a particular index is the filename.  The third is a
+# list of unused FIDs that have FID smaller than the maximum FID.
+# This list should really only be used by the Orca::State package.
+# This structure should not grow too large, as files are removed and
+# their space will be allocated by the next new file.
+use vars     qw(%sfile_fids @sfile_fids @sfile_unused_fids);
+ at EXPORT_OK = qw(%sfile_fids @sfile_fids @sfile_unused_fids);
+
+# The users of these variables are allowed to either add or remove a
+# file from the list of FIDs and to clear the list of FIDs.
+push(@EXPORT_OK, qw(new_fids delete_fid clear_fids));
+
+# Users of these modules will need to register either names of arrays
+# or references to arrays that are indexed by FIDs so that when array
+# truncation is done, these arrays may also be truncated.
+push(@EXPORT_OK, qw(register_fid_arrays));
+
+# Register references to arrays indexed by FIDs.  Make sure that each
+# array is only registered once.
+my %registered_arrays;
+my @registered_arrays;
+sub register_fid_arrays {
+  my $caller_package = caller;
+  foreach my $ref (@_) {
+    # Check the validity of the reference.  It needs to be either a
+    # variable name or a reference to an array.
+    if (ref $ref) {
+      # The reference should be a reference to an array.
+      unless (UNIVERSAL::isa($ref, "ARRAY")) {
+        confess "$0: internal error: Orca::SourceFileIDs::register_fid_arrays passed non-array reference.\n";
+      }
+    } else {
+      my ($type, $symbol) = unpack('a1a*', $ref);
+      unless ($type eq '@') {
+        confess "$0: internal error: Orca::SourceFileIDs::register_fid_arrays passed non-array variable name `$ref'.\n";
+      }
+      if ($symbol =~ /::/) {
+        confess "$0: internal error: Orca::SourceFileIDs::register_fid_arrays cannot pass somebody else's variables.\n";
+      }
+      no strict 'refs';
+      $ref = \@{"${caller_package}::$symbol"};
+      use strict;
+    }
+    next if defined $registered_arrays{$ref};
+    $registered_arrays{$ref} = 1;
+    push(@registered_arrays, $ref);
+  }
+}
+
+sub new_fids {
+  my @fids;
+  foreach my $filename (@_) {
+    # Use the FID if the filename is already defined.
+    my $fid = $sfile_fids{$filename};
+    if (defined $fid) {
+      push(@fids, $fid);
+      next;
+    }
+
+    # If there are any deleted FIDs, then take that space, otherwise
+    # put a FID at the end of the list.
+    if (@sfile_unused_fids) {
+      $fid = shift(@sfile_unused_fids);
+    } else {
+      $fid = $#sfile_fids + 1;
+    }
+
+    $sfile_fids[$fid] = $filename;
+    foreach my $ref (@registered_arrays) {
+      $ref->[$fid] = 'NEW';
+    }
+
+    $sfile_fids{$filename} = $fid;
+    push(@fids, $fid);
+  }
+  @fids;
+}
+
+# Remove a given filename from the list of FIDs.
+sub delete_fid {
+  my $filename = shift;
+
+  my $fid = delete $sfile_fids{$filename};
+  return unless defined $fid;
+
+  # Now manage the deleted FID.  There are several different cases to
+  # handle.  If the FID was the highest numbered FID in the array,
+  # then we need to shorten sfile_fids and any registerd arrays and
+  # also check if any smaller deleted FIDs are next to the deleted
+  # FID.  The case to handle here is if all the FIDs other than the
+  # largest FID are deleted and then the largest FID is deleted, then
+  # all of the already deleted FIDs need to be forgotten.  If the FID
+  # was not the largest FID, then just add it to the list of unused
+  # FIDs.
+  if ($fid = $#sfile_fids) {
+    my $remove_count = 1;
+    --$#sfile_fids;
+    while (@sfile_unused_fids and $sfile_unused_fids[-1] = $#sfile_fids) {
+      --$#sfile_unused_fids;
+      --$#sfile_fids;
+      ++$remove_count;
+    }
+    foreach my $ref (@registered_arrays) {
+      $#$ref -= $remove_count;
+    }
+  } else {
+    $sfile_fids[$fid] = undef;
+    foreach my $ref (@registered_arrays) {
+      $ref->[$fid] = undef;
+    }
+    my $index = interval_search($fid, \@sfile_unused_fids) + 1;
+    splice(@sfile_unused_fids, $index, 0, $fid);
+  }
+}
+
+sub clear_fids {
+  undef %sfile_fids;
+  undef @sfile_fids;
+  undef @sfile_unused_fids;
+  foreach my $ref (@registered_arrays) {
+    undef @$ref;
+  }
+}
+
+# Remove any empty FIDs from the list of FIDs.  Return the number of
+# FIDs removed.
+sub _not_working_compress_fids {
+  return 0 unless @sfile_unused_fids;
+
+  my $count = @sfile_unused_fids;
+
+  # Go through all the FIDs in descending numeric order.  If the
+  # undefined fid is at the end of the array, then just shrink the
+  # array.  Otherwise take the last FID and place it in the space of
+  # the undefined FID.
+  foreach my $fid (sort {$b <=> $a} @sfile_unused_fids) {
+    # If the FID is not the last one, then copy the last FID into the space.
+    if ($fid != $#sfile_fids) {
+      $sfile_fids[$fid] = $sfile_fids[-1];
+    }
+
+    # Shrink the array.
+    --$#sfile_fids;
+  }
+
+  @sfile_unused_fids = ();
+
+  $count;
+}
+
+1;

Added: trunk/orca/lib/Orca/ImageFile.pm
==============================================================================
--- trunk/orca/lib/Orca/ImageFile.pm	(original)
+++ trunk/orca/lib/Orca/ImageFile.pm	Sat Jul 13 21:07:53 2002
@@ -0,0 +1,362 @@
+# Orca::ImageFile: Manage the creation of PNG or GIF plot files.
+#
+# Copyright (C) 1998, 1999 Blair Zajac and Yahoo!, Inc.
+
+package Orca::ImageFile;
+
+use strict;
+use Carp;
+use RRDs;
+use Orca::Constants qw($opt_generate_gifs
+                       $opt_verbose
+                       DAY_SECONDS
+                       $IMAGE_SUFFIX
+                       @IMAGE_PLOT_TYPES
+                       @IMAGE_PDP_COUNTS
+                       @IMAGE_DAYS_BACK);
+use Orca::Config    qw(%config_options
+                       %config_groups
+                       @config_plots);
+use Orca::Utils     qw(recursive_mkdir);
+
+use vars            qw($VERSION);
+
+$VERSION = substr q$Revision: 0.01 $, 10;
+
+# Use a blessed reference to an array as the storage for this class.
+# Define these constant subroutines as indexes into the array.  If
+# the order of these indexes change, make sure to rearrange the
+# constructor in new.
+sub I_GROUP_NAME       () {  0 }
+sub I_SUBGROUP_NAME    () {  1 }
+sub I_NO_SUBGROUP_NAME () {  2 }
+sub I_NAME             () {  3 }
+sub I_IMAGE_BASENAME   () {  4 }
+sub I_ALL_RRD_REF      () {  5 }
+sub I_MY_RRD_LIST      () {  6 }
+sub I_PLOT_REF         () {  7 }
+sub I_IMAGE_HEIGHT     () {  8 }
+sub I_IMAGE_WIDTH      () {  9 }
+sub I_GRAPH_OPTIONS    () { 10 }
+sub I_UPDATE_TIME_BASE () { 11 }
+sub I_PLOT_AGE_BASE    () { I_UPDATE_TIME_BASE + @IMAGE_PLOT_TYPES }
+sub I_PLOT_LEGEND_BASE () { I_PLOT_AGE_BASE + @IMAGE_PLOT_TYPES }
+
+sub new {
+  unless (@_ == 8) {
+    confess "$0: Orca::ImageFile::new passed incorrect number of arguments.\n";
+  }
+
+  my ($class,
+      $group_name,
+      $subgroup_name,
+      $name,
+      $no_subgroup_name,
+      $plot_ref,
+      $rrd_data_files_ref,
+      $my_rrds_ref) = @_;
+
+  unless (@$my_rrds_ref) {
+    confess "$0: Orca::ImageFile::new passed empty \@rrds_ref reference.\n";
+  }
+  unless ($name) {
+    confess "$0: Orca::ImageFile::new passed empty \$name.\n";
+  }
+
+  # Remove any special characters from the unique name and do some
+  # replacements.
+  $name = &::escape_name($name);
+
+  # Create the paths to the html directory and subdirectories.
+  my $html_dir     = $config_options{html_dir};
+  if ($config_groups{$group_name}{sub_dir}) {
+    $html_dir .= "/$subgroup_name";
+    # Create the html_dir directories if necessary.
+    unless (-d $html_dir) {
+      warn "$0: making directory `$html_dir'.\n";
+      recursive_mkdir($html_dir);
+    }
+  }
+  my $image_basename = "$html_dir/$name";
+
+  # Create the new object.
+  my $self = bless [
+    $group_name,
+    $subgroup_name,
+    $no_subgroup_name,
+    $name,
+    $image_basename,
+    $rrd_data_files_ref,
+    [ &::unique(@$my_rrds_ref) ],
+    $plot_ref,
+    0,
+    0,
+    []
+  ], $class;
+
+  my $plot_end_time = $self->plot_end_time;
+  my $interval      = int($config_groups{$group_name}{interval}+0.5);
+  for (my $i=0; $i<@IMAGE_PLOT_TYPES; ++$i) {
+    # Load the data that helps this class determine if a particular
+    # image file, such as the daily image, is current or needs to be
+    # created or recreated.  The data saved is the Unix epoch file
+    # modification time.  If the file does not exist or the file
+    # modification time is newer than the time of te last data point
+    # entered, then save a file modification time of -1 which will
+    # definitely cause the image to be recreated.
+    my $plot_type = $IMAGE_PLOT_TYPES[$i];
+    my @stat      = stat("$image_basename-$plot_type.$IMAGE_SUFFIX");
+    if (@stat and $stat[9] <= $plot_end_time) {
+      $self->[I_UPDATE_TIME_BASE+$i] = $stat[9];
+    } else {
+      $self->[I_UPDATE_TIME_BASE+$i] = -1;
+    }
+
+    # Calculate how old this plot must be before it is recreated.
+    my $image_pdp_count = int($IMAGE_PDP_COUNTS[$i]*300.0/$interval + 0.5);
+    $image_pdp_count    = 1 if $image_pdp_count < 1;
+    $self->[I_PLOT_AGE_BASE+$i] = $image_pdp_count*$interval;
+
+    # Generate the unique plot title cotaining the period title for this
+    # plot.
+    $self->[I_PLOT_LEGEND_BASE+$i] =
+      &::Capatialize($plot_type) .
+      ' ' .
+      ::replace_subgroup_name($plot_ref->{title}, $subgroup_name);
+  }
+
+  $self->_update_graph_options;
+}
+
+sub _update_graph_options {
+  my $self = shift;
+
+  my $plot_ref      = $self->[I_PLOT_REF];
+  my $subgroup_name = $self->[I_SUBGROUP_NAME];
+
+  # Create the options for RRDs::graph that do not change across any
+  # invocations of RRDs::graph.
+  my @options = (
+    '-v', ::replace_subgroup_name($plot_ref->{y_legend}, $subgroup_name),
+    '-b', $plot_ref->{base}
+  );
+
+  # Add the lower-limit and upper-limit flags if defined.
+  if (defined $plot_ref->{plot_min}) {
+    push(@options, '-l', $plot_ref->{plot_min});
+  }
+  if (defined $plot_ref->{plot_max}) {
+    push(@options, '-u', $plot_ref->{plot_max});
+  }
+  if (defined $plot_ref->{rigid_min_max}) {
+    push(@options, '-r');
+  }
+  if (defined $plot_ref->{logarithmic}) {
+    push(@options, '-o');
+  }
+
+  # By default create PNG files.
+  unless ($opt_generate_gifs) {
+    push(@options, '-a', 'PNG');
+  }
+
+  my $data_sources = @{$self->[I_MY_RRD_LIST]};
+  for (my $i=0; $i<$data_sources; ++$i) {
+    my $rrd_key      = $self->[I_MY_RRD_LIST][$i];
+    my $rrd          = $self->[I_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_subgroup_name($plot_ref->{legend}[$i], $subgroup_name);
+    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', 'COMMENT:\s', '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 = $legends[$i];
+    $legend   .= ' ' x ($max_legend_length - length($legend));
+    push(@options, "GPRINT:average$i:LAST:$legend  Current\\: %9.3lf %S",
+                   "GPRINT:average$i:AVERAGE:Average\\: %9.3lf %S",
+                   "GPRINT:average$i:MIN:Min\\: %9.3lf %S",
+                   "GPRINT:average$i:MAX:Max\\: %9.3lf %S\\l"
+        );
+  }
+
+  $self->[I_GRAPH_OPTIONS] = \@options;
+
+  $self;
+}
+
+sub add_rrds {
+  my $self = shift;
+
+  $self->[I_MY_RRD_LIST] = [ &::unique(@{$self->[I_MY_RRD_LIST]}, @_) ];
+
+  $self->_update_graph_options;
+}
+
+sub image_width {
+  $_[0]->[I_IMAGE_WIDTH];
+}
+
+sub image_height {
+  $_[0]->[I_IMAGE_HEIGHT];
+}
+
+# For this image, 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 image_src_size {
+  if ($_[0]->[I_IMAGE_HEIGHT] and $_[0]->[I_IMAGE_WIDTH]) {
+    return "width=$_[0]->[I_IMAGE_WIDTH] height=$_[0]->[I_IMAGE_HEIGHT]";
+  } else {
+    return '';
+  }
+}
+
+sub name {
+  $_[0]->[I_NAME];
+}
+
+sub group_name {
+  $_[0]->[I_GROUP_NAME];
+}
+
+sub subgroup_name {
+  $_[0]->[I_SUBGROUP_NAME];
+}
+
+sub no_subgroup_name {
+  $_[0]->[I_NO_SUBGROUP_NAME];
+}
+
+sub plot_ref {
+  $_[0]->[I_PLOT_REF];
+}
+
+sub rrds {
+  @{$_[0]->[I_MY_RRD_LIST]};
+}
+
+# Calculate the time of the last data point entered into the RRD that
+# this image will use.
+sub plot_end_time {
+  my $self = shift;
+
+  my $plot_end_time = -1;
+  foreach my $rrd_key (@{$self->[I_MY_RRD_LIST]}) {
+    my $update_time = $self->[I_ALL_RRD_REF]{$rrd_key}->rrd_update_time;
+    $plot_end_time  = $update_time if $update_time > $plot_end_time;
+  }
+
+  $plot_end_time;
+}
+
+sub plot {
+  my $self = shift;
+
+  # Make the plots and specify how far back in time to plot.
+  my $plot_made = 0;
+  for (my $i=0; $i<@IMAGE_PLOT_TYPES; ++$i) {
+    $plot_made = 1 if $self->_plot($i);
+  }
+
+  $plot_made;
+}
+
+sub _plot {
+  my ($self, $i) = @_;
+
+  my $plot_type       = $IMAGE_PLOT_TYPES[$i];
+  my $image_days_back = $IMAGE_DAYS_BACK[$i];
+
+  # Get the time stamp of the last data point entered into the RRDs
+  # that are used to generate this image.
+  my $plot_end_time = $self->plot_end_time;
+
+  # Determine if the plot needs to be generated by taking 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 $time_update_index = I_UPDATE_TIME_BASE + $i;
+  my $plot_age          = $self->[I_PLOT_AGE_BASE+$i];
+  if (int($self->[$time_update_index]/$plot_age) ==
+      int($plot_end_time/$plot_age)) {
+    return;
+  }
+
+  my $image_filename = "$self->[I_IMAGE_BASENAME]-$plot_type.$IMAGE_SUFFIX";
+  print "  Creating `$image_filename'.\n" if $opt_verbose > 1;
+
+  my $plot_ref = $self->[I_PLOT_REF];
+
+  my ($graph_return, $image_width, $image_height) =
+    RRDs::graph
+      $image_filename,
+      @{$self->[I_GRAPH_OPTIONS]},
+      '-t', $self->[I_PLOT_LEGEND_BASE+$i],
+      '-s', ($plot_end_time-$image_days_back*DAY_SECONDS),
+      '-e', $plot_end_time,
+      '-w', $plot_ref->{plot_width},
+      '-h', $plot_ref->{plot_height},
+      'COMMENT:\s',
+      'COMMENT:Last data entered at ' . localtime($plot_end_time) . '.';
+  if (my $error = RRDs::error) {
+    warn "$0: warning: cannot create `$image_filename': $error\n";
+    return;
+  } else {
+    $self->[$time_update_index] = $plot_end_time;
+    $self->[I_IMAGE_HEIGHT]     = $image_height;
+    $self->[I_IMAGE_WIDTH]      = $image_width;
+    utime $plot_end_time, $plot_end_time, $image_filename or
+      warn "$0: warning: cannot change mtime for `$image_filename': $!\n";
+
+    # Expire the image at the correct time using a META file if
+    # requested.
+    if ($config_options{expire_images}) {
+      if (open(META, "> $image_filename.meta")) {
+        my $time = 
+        print META "Expires: ",
+                   _expire_string($plot_end_time + $plot_age + 30),
+                   "\n";
+        close(META) or
+          warn "$0: warning: cannot close `$image_filename.meta': $!\n";
+      } else {
+        warn "$0: warning: cannot open `$image_filename.meta' for writing: $!\n";
+      }
+    }
+  }
+
+  1;
+}
+
+sub _expire_string {
+  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];
+  if ($mday<10) {$mday = "0$mday";}
+  if ($hour<10) {$hour = "0$hour";}
+  if ($min<10)  {$min  = "0$min";}
+  if ($sec<10)  {$sec  = "0$sec";}
+  return "$wday, $mday $month ".($year+1900)." $hour:$min:$sec GMT";
+}
+
+1;

Modified: trunk/orca/INSTALL
==============================================================================
--- trunk/orca/INSTALL	(original)
+++ trunk/orca/INSTALL	Sat Jul 13 21:07:53 2002
@@ -14,15 +14,13 @@
 
  6) Test if the Perl modules properly compiled.
 
- 7) Doing an upgrade from Orca 0.23 or older?  Follow these steps.
+ 7) Install any necessary Perl modules.
 
- 8) Install any necessary Perl modules.
+ 8) Doing an upgrade from Orca 0.23 or older?  Follow these steps.
 
  9) Install Orca.
 
-10) Set the Unix process file descriptor limit to at least 256.
-
-11) [Solaris Only and Optional] Install orcallator.
+10) [Solaris Only and Optional] Install orcallator.
     a) Install the SE toolkit.
     b) Apply a patch to the SE 3.0 toolkit if necessary.
     c) Examine Orca/orcallator programs.
@@ -31,7 +29,7 @@
     e) Run start_orcallator on all systems.
     f) Edit orcallator.cfg.
 
-12) Run Orca.
+11) Run Orca.
 
 
 
@@ -97,10 +95,10 @@
     Name			Required Version	Included With Orca
     -----------------------------------------------------------------------
     Data::Dumper		2.101 or greater	2.101
-    Digest::MD5			2.00 or greater		2.09
+    Digest::MD5			2.09 or greater		2.09
     Math::IntervalSearch	1.05 or greater		1.05
-    RRDs			1.0.7.2 or greater	1.0.7.2
-    Storable			0.6.3 or greater	0.6.7
+    RRDs			1.0.13 or greater	1.0.13
+    Storable			0.6.9 or greater	0.6.9
 
     All five of these modules are included with the Orca distribution
     in the packages directory.  When you configure Orca in step 4),
@@ -169,10 +167,10 @@
 
     Storable
 
-      http://www.perl.com/CPAN/authors/id/RAM/Storable-0.6.7.tar.gz
+      http://www.perl.com/CPAN/authors/id/RAM/Storable-0.6.9.tar.gz
 
-      % gunzip -c Storable-0.6.7.tar.gz | tar xvf -
-      % cd Storable-0.6.7
+      % gunzip -c Storable-0.6.9.tar.gz | tar xvf -
+      % cd Storable-0.6.9
       % perl Makefile.PL
       % make
       % make test
@@ -228,11 +226,18 @@
 
     % make test_modules
 
- 7) Doing an upgrade from Orca 0.23 or older?  Follow these steps.
+ 7) Install any necessary Perl modules.
+
+    To automatically install these modules into Perl run the following
+    command:
+
+    % make install_modules
+
+ 8) Doing an upgrade from Orca 0.23 or older?  Follow these steps.
 
     Due to various changes to Orca between releases, many of the RRD,
     HTML and image filenames that Orca creates have changed names.
-    Two separate issues exist.
+    There are two separate issues.
 
     The first is that the naming scheme for all generated HTML and image
     (either PNG or GIF) files have changed.  Unless you want to leave
@@ -290,13 +295,6 @@
        to the new scheme, then kill any running percollator.se's before
        installing and running the following commands
 
- 8) Install any necessary Perl modules.
-
-   To automatically install these modules into Perl run the following
-   command:
-
-   % make install_modules
-
  9) Install Orca.
 
     Run the following command to install Orca:
@@ -305,36 +303,7 @@
 
     This may also install librrd.so in your $libdir.
 
-10) Set the Unix process file descriptor limit to at least 256.
-
-    Orca is designed to run with a minimum of 256 available file
-    descriptors.   If under Unix your processes have a file descriptor
-    limit less than 256, then Orca may possibly fail.
-
-    To check your default file descriptor limit, on many Unix systems
-    you can run
-
-    % ulimit -n
-
-    If this number is less than 256, then you'll need to increase your
-    limit.  This can be accomplished using the limit or ulimit command
-    in your shell, depending upon which shell you use.  See man (1)
-    ulimit or man (1) limit.
-
-    If you are running a C shell equivalent, such as csh or tcsh, then
-    you can run
-
-    % limit descriptors 256
-
-    If you have a Bourne shell equivalent, such as sh, ksh, bash, you
-    can run
-
-    % ulimit -n 256
-
-    This command should either be placed in a .login, .profile, .cshrc
-    file or run just before Orca is run.
-
-11) [Solaris Only and Optional] Install orcallator.
+10) [Solaris Only and Optional] Install orcallator.
     a) Install the SE toolkit.
 
        Perform the installation instructions as listed on the web page
@@ -399,7 +368,7 @@
        orcallator generated files are out of date, which may signify a
        orcallator program that has died and is no longer gathering data.
 
-12) Run Orca.
+11) Run Orca.
 
     Log into the system that will run Orca and run the command:
 

Modified: trunk/orca/src/orca.pl.in
==============================================================================
--- trunk/orca/src/orca.pl.in	(original)
+++ trunk/orca/src/orca.pl.in	Sat Jul 13 21:07:53 2002
@@ -9,10 +9,10 @@
 
 # Set the location of the Orca modules.
 BEGIN {
-#  my $prefix      = "@prefix@";
-#  my $exec_prefix = "@exec_prefix@";
-#  my $libdir      = "@libdir@";
-#  unshift(@INC, $libdir);
+  my $prefix      = "@prefix@";
+  my $exec_prefix = "@exec_prefix@";
+  my $libdir      = "@libdir@";
+  unshift(@INC, $libdir);
 }
 
 use Carp;
@@ -21,1845 +21,62 @@
 # addition to the loading of the modules in the other Orca
 # modules to keep all the requiste numbers here.
 use Data::Dumper         2.101;
-use Digest::MD5          2.00 qw(md5_base64);
+use Digest::MD5          2.09 qw(md5_base64);
 use Math::IntervalSearch 1.05 qw(interval_search);
-use Storable             0.603;
-use RRDs                 1.000072;
+use Storable             0.609;
+use RRDs                 1.000131;
 
 # Set behavior of the Data::Dumper module.
 $Data::Dumper::Indent   = 1;
 $Data::Dumper::Purity   = 1;
 $Data::Dumper::Deepcopy = 1;
 
-# This is the version of Orca.
-use vars qw($VERSION);
-$VERSION = '0.25';
-
-my $IMAGE_SUFFIX = 'png';
-
-# 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 = 19990222;
-
-# The number of seconds in one day.
-my $day_seconds = 24*60*60;
-
-# These define the name of the different RRAs create in each RRD file,
-# how many primary data points go into a consolidated data point, and
-# how far back in time they go.
-#
-# The first RRA 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 first array holds the names of the different plot types to
-# create.  The second array holds the number of 300 second intervals
-# are used to create a consolidated data point.  The third array is
-# the number of consolidated data points held in the RRA.
-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);
-
-# Define the different plots to create.  These settings do not need to
-# be exactly the same as the RRA definitions, but they can be.  Here
-# create a quarterly plot (100 days) between the monthly and yearly
-# plots.  Only update the quarterly plot daily.  The last array here
-# holds the number of days back in time to plot in the image.  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 image,
-# 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 image should be atleast 481
-# pixels wide.
-my @gif_plot_type = (@rra_plot_type[0..2], 'quarterly', $rra_plot_type[3]);
-my @gif_pdp_count = (@rra_pdp_count[0..2], @rra_pdp_count[3, 3]);
-my @gif_days_back = (  1.5,  10,  40, 100, 428);
-# Data points ->    (432  , 480, 480, 100, 428);
-
-# These are command line options.
-my $opt_verbose         = 0;
-my $opt_once_only       = 0;
-my $opt_rrd_update_only = 0;
-my $opt_generate_gifs   = 0;
-
-# To prevent compiling of the subroutine sub { die $_[0] } every time an
-# eval block is entered, compile it only once here and use it everywhere.
-sub die_when_called {
-  die $_[0];
-}
-
-# Set up a signal handler to force looking for new files.
-my $force_find_files = 0;
-sub handle_hup {
-  $force_find_files = 1;
-}
-$SIG{HUP} = \&handle_hup;
-
-package Orca::HTMLFile;
-
-use Carp;
-
-sub new {
-  unless (@_ >= 4) {
-    confess "$0: Orca::HTMLFile::new passed wrong number of arguments.\n";
-  }
-  my ($class, $filename, $title, $top, $bottom) = @_;
-  $bottom = '' unless defined $bottom;
-
-  local *FD;
-  unless (open(FD, "> $filename.htm")) {
-    warn "$0: cannot open `$filename.htm' for writing: $!\n";
-    return;
-  }
-
-  print FD <<END;
-<html>
-<head>
-<title>$title</title>
-</head>
-<body bgcolor="#ffffff">
-
-$top
-<h1>$title</h1>
-END
-
-  bless {_filename => $filename,
-         _handle   => *FD,
-         _bottom   => $bottom,
-  }, $class;
-}
-
-sub print {
-  my $self = shift;
-  print { $self->{_handle} } "@_";
-}
-
-sub DESTROY {
-  my $self = shift;
-
-  print { $self->{_handle} } <<END;
-$self->{_bottom}
-<p>
-<hr align=left width=475>
-<table cellpadding=0 border=0>
-  <tr>
-    <td width=350 valign=center>
-      <a href="http://www.gps.caltech.edu/~blair/orca/">
-        <img width=186 height=45 border=0 src="orca.gif" alt="Orca Home Page"></a>
-      <br>
-      <font FACE="Arial,Helvetica" size=2>
-        Orca-$::VERSION by
-        <a href="http://www.gps.caltech.edu/~blair/">Blair Zajac</a>
-        <a href="mailto:blair\@akamai.com">blair\@akamai.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>
-    </td>
-  </tr>
-</table>
-</body>
-</html>
-END
-
-  my $filename = "$self->{_filename}";
-  close($self->{_handle}) or
-    warn "$0: warning: cannot close `$filename.htm': $!\n";
-  rename("$filename.htm", $filename) or
-    warn "$0: cannot rename `$filename.htm' to `$filename': $!\n";
-}
-
-package Orca::OpenFileHash;
-
-use Carp;
-
-sub new {
-  unless (@_ == 2) {
-    confess "$0: Orca::OpenFileHash::new passed wrong number of arguments.\n";
-  }
-
-  my ($class, $max_elements) = @_;
-
-  bless {_max_elements => $max_elements,
-         _hash         => {},
-         _weights      => {},
-         _filenos      => {},
-         _buffer       => {},
-         _vec          => ''
-  }, $class;
-}
-
-sub open {
-  unless (@_ == 3) {
-    confess "$0: Orca::OpenFileHash::open passed wrong number of arguments.\n";
-  }
-
-  my ($self, $filename, $weight) = @_;
-
-  local *FD;
-
-  # Uncompress compressed files on the fly and read them in.
-  if ($filename =~ /\.gz$/) {
-    $filename = "gunzip -c $filename |";
-  }
-  elsif ($filename =~ /\.Z$/) {
-    $filename = "uncompress -c $filename |";
-  }
-  elsif ($filename =~ /\.bz2$/) {
-    $filename = "bunzip2 -c $filename |";
-  }
-
-  unless (open(FD, $filename)) {
-    warn "$0: warning: cannot open `$filename' for reading: $!\n";
-    return;
-  }
-
-  $self->add($filename, $weight, *FD);
-
-  *FD;
-}
-
-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.
-  $self->close($filename);
-  $self->_close_extra($self->{_max_elements} - 1);
-
-  my $fileno = fileno($fd);
-
-  $self->{_hash}{$filename}{weight} = $weight;
-  $self->{_hash}{$filename}{fd}     = $fd;
-  $self->{_filenos}{$filename}      = $fileno;
-  $self->{_buffer}{$filename}       = '';
-  vec($self->{_vec}, $fileno, 1)    = 1;
-
-  unless (defined $self->{_weights}{$weight}) {
-    $self->{_weights}{$weight} = [];
-  }
-  push(@{$self->{_weights}{$weight}}, $filename);
-
-}
-
-sub close {
-  my ($self, $filename) = @_;
-
-  return $self unless defined $self->{_hash}{$filename};
-
-  my $close_value = close($self->{_hash}{$filename}{fd});
-  # Only print a warning on the close if the close failed and the file
-  # descriptor is not a pipe.
-  unless ($close_value) {
-    if ($filename =~ /\|$/) {
-      warn "$0: warning: cannot close pipe `$filename': [$close_value \$?=$?] $!\n" if $opt_verbose > 1;
-    }
-    else {
-      warn "$0: warning: cannot close `$filename': [$close_value] $!\n";
-    }
-  }
-
-  my $weight = $self->{_hash}{$filename}{weight};
-  delete $self->{_hash}{$filename};
-
-  my $fileno = delete $self->{_filenos}{$filename};
-  vec($self->{_vec}, $fileno, 1) = 0;
-
-  my @filenames = @{$self->{_weights}{$weight}};
-  @filenames = grep { $_ ne $filename } @filenames;
-  if (@filenames) {
-    $self->{_weights}{$weight} = \@filenames;
-  }
-  else {
-    delete $self->{_weights}{$weight};
-  }
-
-  $close_value;
-}
-
-sub _close_extra {
-  my ($self, $max_elements) = @_;
-
-  # Remove this number of elements from the structure.
-  my $close_number = (keys %{$self->{_hash}}) - $max_elements;
-
-  return $self unless $close_number > 0;
-
-  my @weights = sort { $a <=> $b } keys %{$self->{_weights}};
-
-  while ($close_number > 0) {
-    my $weight = shift(@weights);
-    foreach my $filename (@{$self->{_weights}{$weight}}) {
-      $self->close($filename);
-      --$close_number;
-    }
-  }
-
-  $self;
-}
-
-sub change_weight {
-  my ($self, $filename, $new_weight) = @_;
-
-  return unless defined $self->{_hash}{$filename};
-
-  my $old_weight = $self->{_hash}{$filename}{weight};
-  return if $old_weight == $new_weight;
-
-  # Save the new weight.
-  $self->{_hash}{$filename}{weight} = $new_weight;
-
-  unless (defined $self->{_weights}{$new_weight}) {
-    $self->{_weights}{$new_weight} = [];
-  }
-  push(@{$self->{_weights}{$new_weight}}, $filename);
-
-  # Remove the old weight.
-  my @filenames = @{$self->{_weights}{$old_weight}};
-  @filenames = grep { $_ ne $filename } @filenames;
-  if (@filenames) {
-    $self->{_weights}{$old_weight} = \@filenames;
-  }
-  else {
-    delete $self->{_weights}{$old_weight};
-  }
-
-  1;
-}
-
-sub get_fd {
-  my ($self, $filename) = @_;
-
-  if (defined $self->{_hash}{$filename}) {
-    return $self->{_hash}{$filename}{fd};
-  }
-  else {
-    return;
-  }
-}
-
-sub is_open {
-  defined $_[0]->{_hash}{$_[1]};
-}
-
-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.
-use vars qw($open_file_cache);
-$open_file_cache = Orca::OpenFileHash->new(150) unless $open_file_cache;
-
-package Orca::DataFile;
-
-use Carp;
-
-sub new {
-  unless (@_ == 2) {
-    confess "$0: Orca::DataFile::new passed wrong number of arguments.\n";
-  }
-
-  my ($class, $filename) = @_;
-
-  confess "$0: filename not passed to $class.\n" unless $filename;
-  my $self = bless {_filename       => $filename,
-                    _last_stat_time => -1,
-                    _file_dev       => -1,
-                    _file_ino       => -1,
-                    _file_mtime     => -1
-             }, $class;
-  $self->update_stat;
-  $self;
-}
-
-sub filename {
-  $_[0]->{_filename};
-}
-
-sub file_dev {
-  $_[0]->{_file_dev};
-}
-
-sub file_ino {
-  $_[0]->{_file_ino};
-}
-
-sub file_mtime {
-  $_[0]->{_file_mtime};
-}
-
-sub last_stat_time {
-  $_[0]->{_last_stat_time};
-}
-
-# Return 1 if the file exists, 0 otherwise.
-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.
-  my $time = time;
-  if ($time > $self->{_last_stat_time} + 1) {
-    if (my @stat = stat($self->{_filename})) {
-      $self->{_file_dev}   = $stat[0];
-      $self->{_file_ino}   = $stat[1];
-      $self->{_file_mtime} = $stat[9];
-    }
-    else {
-      $self->{_file_dev}   = -1;
-      $self->{_file_ino}   = -1;
-      $self->{_file_mtime} = -1;
-    }
-    $self->{_last_stat_time} = $time;
-  }
-
-  $self->{_file_mtime} != -1;
-}
-
-# Return a status depending upon the file:
-#   -1 if the file does not exist.
-#    0 if the file has not been updated since the last status check.
-#    1 if the file has been updated since the last status check.
-#    2 if the file has a new device or inode since the last status check.
-sub status {
-  my $self = shift;
-
-  my $filename   = $self->{_filename};
-  my $file_dev   = $self->{_file_dev};
-  my $file_ino   = $self->{_file_ino};
-  my $file_mtime = $self->{_file_mtime};
-
-  my $result = 0;
-  if ($self->update_stat) {
-    if ($self->{_file_dev} != $file_dev or $self->{_file_ino} != $file_ino) {
-      $result = 2;
-    }
-    elsif ($self->{_file_mtime} != $file_mtime) {
-      $result = 1;
-    }
-  }
-  else {
-    $result = -1;
-  }
-
-  $result;
-}
-
-package Orca::ImageFile;
-
-use RRDs;
-use Carp;
-
-sub new {
-  unless (@_ == 11) {
-    confess "$0: Orca::ImageFile::new passed incorrect number of arguments.\n";
-  }
-
-  my ($class,
-      $config_options,
-      $config_files,
-      $config_plots,
-      $files_key,
-      $group,
-      $name,
-      $no_group_name,
-      $plot_ref,
-      $rrd_data_files_ref,
-      $my_rrds_ref) = @_;
-
-  unless (@$my_rrds_ref) {
-    confess "$0: Orca::ImageFile::new passed empty \@rrds_ref reference.\n";
-  }
-  unless ($name) {
-    confess "$0: Orca::ImageFile::new passed empty \$name.\n";
-  }
-
-  # Remove any special characters from the unique name and do some
-  # replacements.
-  $name = &::escape_name($name);
-
-  # Create the paths to the html directory and subdirectories.
-  my $html_dir     = $config_options->{html_dir};
-  if ($config_files->{$files_key}{sub_dir}) {
-    $html_dir .= "/$group";
-    # Create the html_dir directories if necessary.
-    unless (-d $html_dir) {
-      warn "$0: making directory `$html_dir'.\n";
-      ::recursive_mkdir($html_dir);
-    }
-  }
-  my $gif_basename = "$html_dir/$name";
-
-  # Create the new object.
-  my $self = bless {
-    _files_key		=> $files_key,
-    _group		=> $group,
-    _name		=> $name,
-    _no_group_name	=> $no_group_name,
-    _gif_basename	=> $gif_basename,
-    _all_rrd_ref	=> $rrd_data_files_ref,
-    _my_rrd_list	=> [ &::unique(@$my_rrds_ref) ],
-    _plot_ref           => $plot_ref,
-    _expire             => $config_options->{expire_images},
-    _gif_height         => 0,
-    _gif_width          => 0,
-    _graph_options      => []
-  }, $class;
-
-  my $plot_end_time = $self->plot_end_time;
-  my $interval      = int($config_files->{$files_key}{interval}+0.5);
-  for (my $i=0; $i<@gif_plot_type; ++$i) {
-    # Load the data that helps this class determine if a particular
-    # image file, such as the daily image, is current or needs to be
-    # created or recreated.  The data saved is the Unix epoch file
-    # modification time.  If the file does not exist or the file
-    # modification time is newer than the time of te last data point
-    # entered, then save a file modification time of -1 which will
-    # definitely cause the image to be recreated.
-    my $plot_type = $gif_plot_type[$i];
-    my @stat      = stat("$gif_basename-$plot_type.$IMAGE_SUFFIX");
-    if (@stat and $stat[9] <= $plot_end_time) {
-      $self->{"_${plot_type}_update_time"} = $stat[9];
-    }
-    else {
-      $self->{"_${plot_type}_update_time"} = -1;
-    }
-
-    # Calculate how old this plot must be before it is recreated.
-    my $gif_pdp_count = int($gif_pdp_count[$i]*300.0/$interval + 0.5);
-    $gif_pdp_count    = 1 if $gif_pdp_count < 1;
-    $self->{"_${plot_type}_plot_age"} = $gif_pdp_count*$interval;
-
-    # Generate the unique plot title cotaining the period title
-    # for this plot.
-    $self->{"_${plot_type}_legend"} =
-      &::Capatialize($plot_type) .
-      ' ' .
-      ::replace_group_name($plot_ref->{title}, $group);
-  }
-
-  $self->_update_graph_options;
-}
-
-sub _update_graph_options {
-  my $self = shift;
-
-  my $plot_ref = $self->{_plot_ref};
-  my $group    = $self->{_group};
-
-  # Create the options for RRDs::graph that do not change across any
-  # invocations of RRDs::graph.
-  my @options = (
-    '-a', 'PNG',
-    '-v', ::replace_group_name($plot_ref->{y_legend}, $group),
-    '-b', $plot_ref->{base}
-  );
-  # Add the lower-limit and upper-limit flags if defined.
-  if (defined $plot_ref->{plot_min}) {
-    push(@options, '-l', $plot_ref->{plot_min});
-  }
-  if (defined $plot_ref->{plot_max}) {
-    push(@options, '-u', $plot_ref->{plot_max});
-  }
-  if (defined $plot_ref->{rigid_min_max}) {
-    push(@options, '-r');
-  }
-  if (defined $plot_ref->{logarithmic}) {
-    push(@options, '-o');
-  }
-
-  # By default create PNG files.
-  unless ($opt_generate_gifs) {
-    push(@options, '-a', 'PNG');
-  }
-
-  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          = $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: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', 'COMMENT:\s', '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 = $legends[$i];
-    $legend   .= ' ' x ($max_legend_length - length($legend));
-    push(@options, "GPRINT:average$i:LAST:$legend  Current\\: %8.3f %S",
-                   "GPRINT:average$i:AVERAGE:Average\\: %8.3f %S",
-                   "GPRINT:average$i:MIN:Min\\: %8.3f %S",
-                   "GPRINT:average$i:MAX:Max\\: %8.3f %S\\l"
-        );
-  }
-
-  $self->{_graph_options} = \@options;
-
-  $self;
-}
-
-sub add_rrds {
-  my $self = shift;
-
-  $self->{_my_rrd_list} = [ &::unique(@{$self->{_my_rrd_list}}, @_) ];
-
-  $self->_update_graph_options;
-}
-
-sub files_key {
-  $_[0]->{_files_key};
-}
-
-sub gif_width {
-  $_[0]->{_gif_width};
-}
-
-sub gif_height {
-  $_[0]->{_gif_height};
-}
-
-# For this image 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 image_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 {
-  $_[0]->{_name};
-}
-
-sub no_group_name {
-  $_[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 {
-  my $self = shift;
-
-  my $plot_end_time = -1;
-  foreach my $rrd_key (@{$self->{_my_rrd_list}}) {
-    my $update_time = $self->{_all_rrd_ref}{$rrd_key}->rrd_update_time;
-    $plot_end_time  = $update_time if $update_time > $plot_end_time;
-  }
-
-  $plot_end_time;
-}
-
-sub plot {
-  my $self = shift;
-
-  # Make the plots and specify how far back in time to plot.
-  my $plot_made = 0;
-  for (my $i=0; $i<@gif_plot_type; ++$i) {
-    $plot_made = 1 if $self->_plot($gif_plot_type[$i], $gif_days_back[$i]);
-  }
-
-  $plot_made;
-}
-
-sub _plot {
-  my ($self, $plot_type, $gif_days_back) = @_;
-
-  # 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 by taking 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 $time_update_key = "_${plot_type}_update_time";
-  my $plot_age        = $self->{"_${plot_type}_plot_age"};
-  if (int($self->{$time_update_key}/$plot_age) == int($plot_end_time/$plot_age)) {
-    return;
-  }
-
-  my $gif_filename = "$self->{_gif_basename}-$plot_type.$IMAGE_SUFFIX";
-  print "  Creating `$gif_filename'.\n" if $opt_verbose > 1;
-
-  my $plot_ref = $self->{_plot_ref};
-
-  my ($graph_return, $gif_width, $gif_height) =
-    RRDs::graph
-      $gif_filename,
-      @{$self->{_graph_options}},
-      '-t', $self->{"_${plot_type}_legend"},
-      '-s', ($plot_end_time-$gif_days_back*$day_seconds),
-      '-e', $plot_end_time,
-      '-w', $plot_ref->{plot_width},
-      '-h', $plot_ref->{plot_height},
-      'COMMENT:\s',
-      'COMMENT:Last data entered at ' . localtime($plot_end_time) . '.';
-  if (my $error = RRDs::error) {
-    warn "$0: warning: cannot create `$gif_filename': $error\n";
-    return;
-  }
-  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.
-    if ($self->{_expire}) {
-      if (open(META, "> $gif_filename.meta")) {
-        my $time = 
-        print META "Expires: ",
-                   _expire_string($plot_end_time + $plot_age + 30),
-                   "\n";
-        close(META) or
-          warn "$0: warning: cannot close `$gif_filename.meta': $!\n";
-      }
-      else {
-        warn "$0: warning: cannot open `$gif_filename.meta' for writing: $!\n";
-      }
-    }
-  }
-
-  1;
-}
-
-sub _expire_string {
-  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];
-  if ($mday<10) {$mday = "0$mday";}
-  if ($hour<10) {$hour = "0$hour";}
-  if ($min<10)  {$min  = "0$min";}
-  if ($sec<10)  {$sec  = "0$sec";}
-  return "$wday, $mday $month ".($year+1900)." $hour:$min:$sec GMT";
-}
-
-package Orca::RRDFile;
-
-use RRDs;
-use Carp;
-use vars qw(@ISA);
-
- at ISA = qw(Orca::DataFile);
-
-sub new {
-  unless (@_ == 7) {
-    confess "$0: Orca::RRDFile::new passed incorrect number of arguments.\n";
-  }
-
-  my ($class,
-      $config_options,
-      $config_files,
-      $files_key,
-      $group,
-      $name,
-      $plot_ref) = @_;
-
-  # Remove any special characters from the unique name and do some
-  # replacements.
-  $name = &::escape_name($name);
-
-  # Create the paths to the data directory.
-  my $rrd_dir = $config_options->{rrd_dir};
-  if ($config_files->{$files_key}{sub_dir}) {
-    $rrd_dir .= "/$group";
-    unless (-d $rrd_dir) {
-      warn "$0: making directory `$rrd_dir'.\n";
-      ::recursive_mkdir($rrd_dir);
-    }
-  }
-  my $rrd_filename = "$rrd_dir/$name.rrd";
-
-  # Create the new object.
-  my $self = $class->SUPER::new($rrd_filename);
-  return unless $self;
-  $self->{_name}             = $name;
-  $self->{_new_data}         = {};
-  $self->{_created_gifs}     = {};
-  $self->{_plot_ref}         = $plot_ref;
-  $self->{_interval}         = int($config_files->{$files_key}{interval}+0.5);
-  $self->{_rrd_version}      = $ORCA_RRD_VERSION;
-  $self->{_choose_data_subs} = {};
-
-  # 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;
-  if ($self->status >= 0) {
-    my $update_time = RRDs::last $rrd_filename;
-    if (my $error = RRDs::error) {
-      warn "$0: RRDs::last error: `$rrd_filename' $error\n";
-    }
-    else {
-      if (open(RRDFILE, "<$rrd_filename")) {
-        my $version = '';
-        while (<RRDFILE>) {
-          if (/Orca(\d{8})/) {
-            $version = $1;
-            last;
-          }
-        }
-        close(RRDFILE) or
-          warn "$0: error in closing `$rrd_filename' for reading: $!\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";
-        }
-      }
-    }
-  }
-
-  $self;
-}
-
-sub version {
-  $_[0]->{_rrd_version};
-}
-
-sub name {
-  $_[0]->{_name};
-}
-
-sub rrd_update_time {
-  $_[0]->{_rrd_update_time};
-}
-
-sub add_image {
-  my ($self, $gif) = @_;
-  $self->{_created_gifs}{$gif->name} = $gif;
-  $self;
-}
-
-sub created_gifs {
-  values %{$_[0]->{_created_gifs}};
-}
-
-# Queue a list of (time, value) data pairs.  Return the number of data
-# pairs sucessfully queued.
-# Call:   $self->(unix_epoch_time1, value1, unix_epoch_time2, value2, ...);
-sub queue_data {
-  my $self = shift;
-
-  my $count = 0;
-  my $rrd_update_time = $self->{_rrd_update_time};
-  while (@_ > 1) {
-    my ($time, $value) = splice(@_, 0, 2);
-    next if $time <= $rrd_update_time;
-    $self->{_new_data}{$time} = $value;
-    ++$count;
-  }
-
-  $count;
-}
-
-sub flush_data {
-  my $self = shift;
-
-  # Get the times of the new data to put into the RRD file.
-  my @times = sort { $a <=> $b } keys %{$self->{_new_data}};
-
-  return unless @times;
-
-  my $rrd_filename = $self->filename;
-
-  # Create the Orca data file if it needs to be created.
-  if ($self->{_rrd_update_time} == -2) {
-
-    # Assume that a maximum of two time intervals are needed before a
-    # data source value is set to unknown.
-    my $interval = $self->{_interval};
-   
-    my $data_source = "DS:Orca$ORCA_RRD_VERSION:$self->{_plot_ref}{data_type}";
-    $data_source   .= sprintf ":%d:", 2*$interval;
-    $data_source   .= "$self->{_plot_ref}{data_min}:";
-    $data_source   .= "$self->{_plot_ref}{data_max}";
-    my @options = ($rrd_filename,
-                   '-b', $times[0]-1,
-                   '-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.
-    my $count = int($rra_row_count[0]*300.0/$interval + 0.5);
-    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];
-      my $rra_pdp_count = int($rra_pdp_count[$i]*300.0/$interval + 0.5);
-      if (@one_pdp_option and $rra_pdp_count != 1) {
-        push(@options, @one_pdp_option);
-      }
-      @one_pdp_option = ();
-      push(@options, "RRA:AVERAGE:0.5:$rra_pdp_count:$rra_row_count[$i]");
-    }
-
-    # Now do the actual creation.
-    if ($opt_verbose) {
-      print "  Creating RRD `$rrd_filename'";
-      if ($opt_verbose > 2) {
-        print " with options ", join(' ', @options[1..$#options]);
-      }
-      print ".\n";
-    }
-    RRDs::create @options;
-
-    if (my $error = RRDs::error) {
-      warn "$0: RRDs::create error: `$rrd_filename' $error\n";
-      return;
-    }
-  }
-
-  # Flush all of the stored data into the RRD file.
-  my @options;
-  my $old_rrd_update_time = $self->{_rrd_update_time};
-  foreach my $time (@times) {
-    push(@options, "$time:$self->{_new_data}{$time}");
-  }
-  RRDs::update $rrd_filename, @options;
-  my $ok = 1;
-  if (my $error = RRDs::error) {
-    warn "$0: warning: cannot put data starting at ",
-         scalar localtime($times[0]),
-         " ($times[0]) into `$rrd_filename': $error\n";
-    return 0;
-  }
-
-  # If there were no errors, then totally clear the hash to save
-  # memory.
-  delete $self->{_new_data};
-  $self->{_new_data} = {};
-
-  $self->{_rrd_update_time} = $times[-1];
-
-  return 1;
-}
-
-package Orca::Config::Plot;
-
-use Carp;
-
-sub new {
-  unless (@_ == 2) {
-    confess "$0: Orca::Config::Plot::new passed incorrect number of arguments.\n";
-  }
-
-  bless $_[1], $_[0];
-}
-
-package Orca::Config::FilesGroup;
-
-use Carp;
-
-sub new {
-  unless (@_ == 2) {
-    confess "$0: Orca::Config::FilesGroup::new passed incorrect number of arguments.\n";
-  }
-
-  bless $_[1], $_[0];
-}
-
-package Orca::SourceFile;
-
-use Carp;
-use Digest::MD5 qw(md5);
-use Storable    qw(dclone);
-use vars qw(@ISA);
-
- at ISA = qw(Orca::DataFile);
-
-# This is a static variable that lists all of the column names for a
-# particular group.
-my %group_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_rrd_list_cache;
-my %choose_data_sub_cache;
-
-sub new {
-  unless (@_ == 10) {
-    confess "$0: Orca::SourceFile::new passed incorrect number of arguments.\n";
-  }
+# Load the required Orca modules.
+use Orca::Constants     qw($ORCA_VERSION
+                           @IMAGE_PLOT_TYPES
+                           $opt_generate_gifs
+                           $opt_once_only
+                           $opt_rrd_update_only
+                           $opt_verbose
+                           $IMAGE_SUFFIX);
+use Orca::Config        qw(load_config
+                           %config_options
+                           %config_groups
+                           @config_plots);
+use Orca::OldState      qw($orca_old_state 
+                           load_old_state 
+                           save_old_state);
+use Orca::Utils         qw(perl_glob unique);
+use Orca::SourceFile;
+use Orca::SourceFileIDs qw(@sfile_fids);
+use Orca::HTMLFile;
 
-  my ($class,
-      $filename,
-      $interval,
-      $late_interval,
-      $reopen,
-      $column_description,
-      $date_source,
-      $date_format,
-      $warn_email,
-      $saved_source_file_state) = @_;
-
-  my $self = $class->SUPER::new($filename);
-  $self->{_interval}           = $interval;
-  $self->{_late_interval}      = int(&$late_interval($interval) + 0.5);
-  $self->{_reopen}             = $reopen;
-  $self->{_date_source}        = $date_source;
-  $self->{_date_format}        = $date_format;
-  $self->{_warn_email}         = $warn_email;
-  $self->{_my_rrd_list}        = [];
-  $self->{_all_rrd_ref}        = undef;
-  $self->{_group_keys}         = {};
-  $self->{_choose_data_sub}    = undef;
-
-  $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.
-  my $read_interval = sqrt($self->{_interval}*$self->{_late_interval});
-  $self->{_read_interval} = int($read_interval + 0.5);
-
-  # Load in any state information for this file.
-  if (defined $saved_source_file_state->{$filename}) {
-    while (my ($key, $value) = each %{$saved_source_file_state->{$filename}}) {
-      $self->{$key} = $value;
-    }
-  }
-
-  # 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;
-  return unless $self->get_date_column;
-
-  $self;
-}
-
-# For each files key store make a note of the column description names
-# that appear.
-sub add_groups {
-  my $self = shift;
-
-  foreach my $group_name (@_) {
-    $self->{_group_keys}{$group_name} = 1;
-    foreach my $description (@{$self->{_column_description}}) {
-      $group_column_names{$group_name}{$description} = 1;
-    }
-  }
-}
-
-# Return 1 if the source data file is current or 0 otherwise.  Also
-# 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 day.
-sub is_current {
-  my $self = shift;
-
-  $self->{_is_current_day} = (localtime)[3];
-
-  $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.
-sub next_load_time {
-  my $self = shift;
-
-  my $last_stat_time = $self->last_stat_time;
-  my $file_mtime     = $self->file_mtime;
-
-  if ($last_stat_time <= $file_mtime + $self->{_late_interval}) {
-    return $file_mtime + $self->{_read_interval};
-  }
-  else {
-    return $last_stat_time + $self->{_late_interval};
-  }
-}
-
-sub get_column_names {
-  my $self = shift;
-
-  return $self unless $self->{_column_description}[0] eq 'first_line';
-
-  my $filename = $self->filename;
-  $self->update_stat;
-  my $fd = $::open_file_cache->open($filename, $self->file_mtime);
-  return unless $fd;
-
-  my $line = <$fd>;
-
-  chomp($line);
-  if ($line) {
-    $self->{_first_line} = 1;
-    my @line = split(' ', $line);
-    my $cache_key = md5(join("\200", @line));
-    unless (defined $first_line_cache{$cache_key}) {
-      $first_line_cache{$cache_key} = \@line;
-    }
-    $self->{_column_description} = $first_line_cache{$cache_key};
-  }
-  else {
-    warn "$0: warning: no first_line for `$filename' yet.\n";
-    $::open_file_cache->close($filename) or
-      warn "$0: warning: cannot close `$filename' for reading: $!\n";
-    return;
-  }
-
-  $self;
-}
-
-sub get_date_column {
-  my $self = shift;
-
-  return $self if $self->{_date_source}[0] eq 'file_mtime';
-
-  my $filename         = $self->filename;
-  my $date_column_name = $self->{_date_source}[1];
-
-  my $found = -1;
-  for (my $i=0; $i<@{$self->{_column_description}}; ++$i) {
-    if ($self->{_column_description}[$i] eq $date_column_name) {
-      $found = $i;
-      last;
-    }
-  }
-
-  unless ($found > -1) {
-    warn "$0: warning: cannot find date `$date_column_name' in `$filename'.\n";
-    return;
-  }
-  $self->{_date_column_index} = $found;
-
-  $self;
-}
-
-sub add_plots {
-  # Make sure that the user has called the add_groups method and
-  # inserted at least one key.
-  unless (keys %group_column_names) {
-    confess "$0: Orca::SourceFile::add_groups must be called before add_plots.\n";
-  }
-
-  unless (@_ == 8) {
-    confess "$0: Orca::SourceFile::add_plots passed wrong number of arguments.\n";
-  }
-
-  my ($self,
-      $config_options,
-      $config_files,
-      $config_plots,
-      $group_name,
-      $subgroup_name,
-      $rrd_data_files_ref,
-      $image_files_ref) = @_;
-
-  # See if we have already done all the work for a plot with this group_name,
-  # subgroup_name, 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
-  # group.  Finally, create a hash keyed by column name with a value of the
-  # index into the column description array.
-  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", $group_name,
-                               $subgroup_name,
-                               @column_description);
-  my $cache_key = md5($plot_key);
-  if (defined $all_rrds_cache{$cache_key}) {
-    $self->{_all_rrd_ref}     = $all_rrds_cache{$cache_key};
-    $self->{_my_rrd_list}     = $my_rrd_list_cache{$cache_key};
-    $self->{_choose_data_sub} = $choose_data_sub_cache{$cache_key};
-    return 1;
-  }
-
-  # Use this hash to keep a list of RRDs that this file uses.
-  my %my_rrd_list;
-
-  # This is the source for an anonymous subroutine that given a row
-  # from a source data file returns a hash keyed by RRD name with the
-  # values calculated from the row.
-  my $choose_data_expr = "sub {\n  (\n";
-
-  # Go through each plot to create and process it for this file.
-  my @regexp_pos          = map { 0 } (1..@$config_plots);
-  my $oldest_regexp_index = 0;
-  my $handle_regexps      = 0;
-  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.
-  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 ($handle_regexps and $i >= @$config_plots) {
-      $i = $oldest_regexp_index;
-    }
-
-    my $plot = $config_plots->[$i];
-
-    # Skip this plot if the group_name do not match.  Increment the
-    # index of the next plot to handle.
-    if ($plot->{source} ne $group_name) {
-      if ($oldest_regexp_index == $i) {
-        $handle_regexps = 0;
-        ++$oldest_regexp_index;
-      }
-      ++$i;
-      next;
-    }
-
-    # There are three cases to handle:
-    # 1) Regular expression match in the first data with additional datas.
-    # 2) Regular expression match in the first data with no additional datas.
-    # 3) All others.
-    # The first is a single data source that has a regular expression.  In
-    # this case, all of the columns are searched to match the regular
-    # expression.  This generates a single plot with all of the different
-    # data sources plotted on it.  The second case is two or more data
-    # sources and where the first data source has a regular expression
-    # match.  This may generate more than one plot, for each set of columns
-    # that match the regular expression.  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 $regexp_element_index = -1;
-    for (my $j=0; $j<@{$plot->{data}[0]}; ++$j) {
-      if ($plot->{data}[0][$j] =~ m:\(.+\):) {
-        $regexp_element_index = $j;
-        last;
-      }
-    }
-
-    # 1) Regular expression match in the first data with additional datas.
-    if ($number_datas == 1 and $regexp_element_index != -1) {
-
-      # If we've gone up to the last column to match, then go on.
-      if ($regexp_pos[$i] >= @column_description) {
-        if ($oldest_regexp_index == $i) {
-          $handle_regexps = 0;
-          ++$oldest_regexp_index;
-        }
-        $i = $plot->{flush_regexps} ? $oldest_regexp_index : $i + 1;
-        next;
-      }
-      $regexp_pos[$i] = @column_description;
-
-      # 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.  Replace the regular expression in the first data
-      # with the name of the column that caused the match.
-      my $creates          = delete $plot->{creates};
-      my $new_plot         = dclone($plot);
-      $plot->{creates}     = $creates;
-      $new_plot->{creates} = $creates;
-      $plot                = $new_plot;
-
-      # 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.
-      my @data_with_regexp = @{$plot->{data}[0]};
-      my $regexp           = $data_with_regexp[$regexp_element_index];
-      my $new_data_index   = 0;
-      my $original_legend  = $plot->{legend}[0];
-      foreach my $column_name (@column_description) {
-        my @matches = $column_name =~ /$regexp/;
-        next unless @matches;
-
-        # Replace the regular expression match with the matched column
-        # name.
-        $data_with_regexp[$regexp_element_index] = $column_name;
-        $plot->{data}[$new_data_index] = [ @data_with_regexp ];
-
-        # 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.
-        unless (defined $plot->{color}[$new_data_index]) {
-          $plot->{color}[$new_data_index] = &::get_color($new_data_index);
-        }
-        unless (defined $plot->{legend}[$new_data_index]) {
-          $plot->{legend}[$new_data_index] = $original_legend;
-        }
-        unless (defined $plot->{line_type}[$new_data_index]) {
-          $plot->{line_type}[$new_data_index] = $plot->{line_type}[0];
-        }
-
-        # Replace the regular expression in any legend elements.
-        my $legend = $plot->{legend}[$new_data_index];
-        my $count  = 1;
-        foreach my $match (@matches) {
-          $legend =~ s/\$$count/$match/ge;
-          $legend =~ s/\(.+\)/$match/ge;
-          ++$count;
-        }
-        $plot->{legend}[$new_data_index] = $legend;
-
-        ++$new_data_index;
-      }
-
-      if ($oldest_regexp_index == $i) {
-        $handle_regexps = 0;
-        ++$oldest_regexp_index;
-      }
-      $old_i = $i;
-      $i = $plot->{flush_regexps} ? $oldest_regexp_index : $i + 1;
-      next unless $new_data_index;
-    }
-
-    # 2) Regular expression match in the first data with no additional datas.
-    elsif ($number_datas > 1 and $regexp_element_index != -1) {
-      $handle_regexps = 1;
-
-      # If we've gone up to the last column to match, then go on.  If
-      # this is the oldest regexp, then increment oldest_regexp_index.
-      if ($regexp_pos[$i] >= @column_description) {
-        if ($oldest_regexp_index == $i) {
-          $handle_regexps = 0;
-          ++$oldest_regexp_index;
-        }
-        $i = $plot->{flush_regexps} ? $oldest_regexp_index : $i + 1;
-        next;
-      }
-
-      # Go through all of the columns and stop at the first match.
-      my @data_with_regexp = @{$plot->{data}[0]};
-      my $regexp           = $data_with_regexp[$regexp_element_index];
-      my $column_description;
-      my @matches;
-      for (;$regexp_pos[$i]<@column_description; ++$regexp_pos[$i]) {
-        @matches = $column_description[$regexp_pos[$i]] =~ /$regexp/;
-        if (@matches) {
-          $column_description = $column_description[$regexp_pos[$i]];
-          last;
-        }
-      }
-      unless (@matches) {
-        if ($oldest_regexp_index == $i) {
-          ++$oldest_regexp_index;
-          $handle_regexps = 0;
-        }
-        ++$i;
-        next;
-      }
-      ++$regexp_pos[$i];
-
-      # 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.  Replace the regular expression in the first data
-      # with the name of the column that caused the match.  Then create
-      # string form of the plot object using Data::Dumper::Dumper and
-      # replace all of the $1, $2, ... with what was matched in the
-      # first data source.
-      my $creates          = delete $plot->{creates};
-      my $new_plot         = dclone($plot);
-      $plot->{creates}     = $creates;
-      $plot                = $new_plot;
-      $plot->{data}[0][$regexp_element_index] = $column_description;
-      my $d                = Data::Dumper->Dump([$plot], [qw(plot)]);
-      $plot->{creates}     = $creates;
-      my $count            = 1;
-      foreach my $match (@matches) {
-        $d =~ s/\$$count/$match/mge;
-        $d =~ s/\(.+\)/$match/mge;
-        ++$count;
-      }
-      {
-        local $SIG{__DIE__}  = 'DEFAULT';
-        local $SIG{__WARN__} = \&::die_when_called;
-        eval $d;
-      }
-      die "$0: internal error: eval on\n   $d\nOutput: $@\n" if $@;
-
-      # Either increment the index or reset it to the oldest regexp
-      # index.
-      $old_i = $i;
-      $i = $plot->{flush_regexps} ? $oldest_regexp_index : $i + 1;
-    }
-
-    # 3) All others.
-    else {
-      $old_i = $i++;
-      ++$oldest_regexp_index unless $handle_regexps;
-    }
-
-    # 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 group.  In this case the data argument for this file
-    # will not be used.
-    my @datas;
-    foreach my $one_data (@{$plot->{data}}) {
-      push(@datas, [@$one_data]);
-    }
-    my $required = $plot->{required};
-    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 $group_column_names{$group_name}{$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" if $required;
-          $datas[$j] = undef;
-          last;
-        }
-      }
-      # If there were no substitutions and verbose is on, then warn about it.
-      if (!$match_one_data and $opt_verbose > 1) {
-        my $m = $old_i + 1;
-        warn "$0: warning: no substitutions performed for `data @{$plot->{data}[$j]}' in plot #$m in `" . $self->filename . "'.\n";
-      }
-    }
-
-    # Because users may place code into the data statements that do not
-    # have any substitutions, then the only way to check for the validity
-    # is to create valid anonymous subroutines and try them.  Invalid
-    # ones will either return undef or fail to compile.  If the plot is
-    # required, then replace invalid subroutines with one that returns 0.
-    # Here the results of eval'ing a test subroutine on a data is kept.
-    # The cached result is either a 1 or a 0.  To test the subroutine,
-    # pass the newly created subroutine a fake array of numbers, where the
-    # array has as manay elements as there are in one line from the file.
-    # If it is an invalid subroutine but the plot is required, then set
-    # the subroutine to return 'U', which is RRD's way of declaring
-    # undefined data.
-    my @fake_numbers = 1 .. @column_description;
-    my @substituted_data_expressions;
-    my $one_ok_data = 0;
-    for (my $j=0; $j<@datas; ++$j) {
-      my $data_expression;
-      if (defined $datas[$j]) {
-        $data_expression = "@{$datas[$j]}";
-        my $sub_expr     = "sub { $data_expression }";
-        my $sub_expr_md5 = md5($data_expression);
-        my $eval_result  = $choose_data_sub_cache{$sub_expr_md5};
-        unless (defined $eval_result) {
-          $eval_result = 1;
-          my $test_value;
-          my $message;
-          {
-            local $SIG{__DIE__}  = 'DEFAULT';
-            local $SIG{__WARN__} = \&::die_when_called;
-            my $sub              = eval $sub_expr;
-            eval { $test_value   = &$sub(@fake_numbers) };
-          }
-          if ($@) {
-            $eval_result = 0;
-            $@ =~ s/\s+$//g;
-            my $m = $old_i + 1;
-            $message = "$0: warning: cannot compile `$sub_expr' for plot #$m `data @{$plot->{data}[$j]}': $@\n";
-          }
-          elsif (!defined $test_value) {
-            $eval_result = 0;
-            my $m = $old_i + 1;
-            $message = "$0: warning: testing of `$sub_expr' for plot #$m `data @{$plot->{data}[$j]}' yielded an undefined value.\n";
-          }
-          if ($message and ($required or $opt_verbose > 1)) {
-            warn $message;
-          }
-          $choose_data_sub_cache{$sub_expr_md5} = $eval_result;
-        }
-        $data_expression = undef unless $eval_result;
-      }
-      # If the data_expression did not work, but the plot is required, then
-      # have the expression return 'U';
-      if (!$data_expression and $plot->{required}) {
-        $data_expression = "'U'";
-      }
-      $one_ok_data = 1 if $data_expression;
-      push(@substituted_data_expressions, $data_expression);
-    }
-
-    # If none of the data expressions compiled, then go on to the next
-    # unless the plot is required.
-    next if (!$one_ok_data and !$required);
-
-    # At this point we have a plot to create.
-
-    # For each valid data source in this plot, place each the substituted
-    # code a large anonymous subroutine that takes a single row of data
-    # from an input source file and returns a hash keyed by the name
-    # used for a RRD and the value calculated using the input row of
-    # data.  Also create an unique Orca data file name for this plot
-    # and a name for this plot that does not include the subgroup name.
-    my @my_rrds;
-    my @my_short_rrds;
-    my @name_with_subgroup;
-    my @name_without_subgroup;
-    my $previous_group    = '';
-    my $previous_subgroup = '';
-    for (my $j=0; $j<@substituted_data_expressions; ++$j) {
-
-      my $original_data_expression    = join('_', @{$plot->{data}[$j]});
-      my $substituted_data_expression = $substituted_data_expressions[$j];
-
-      my $name_with_subgroup = "${group_name}_${subgroup_name}_${original_data_expression}";
-      push(@name_with_subgroup, $name_with_subgroup);
-      push(@name_without_subgroup, "${group_name}_${original_data_expression}");
-
-      # Create a short name that may exclude the group and subgroup if the
-      # previous data had the same group and subgroup.
-      my $short_name_with_subgroup;
-      if ($group_name eq $previous_group) {
-        if ($subgroup_name eq $previous_subgroup) {
-          $short_name_with_subgroup = "__$original_data_expression";
-        }
-        else {
-          $short_name_with_subgroup = "_${subgroup_name}_${original_data_expression}";
-          $previous_subgroup        = $subgroup_name;
-        }
-      }
-      else {
-        $previous_group           = $group_name;
-        $previous_subgroup        = $subgroup_name;
-        $short_name_with_subgroup = $name_with_subgroup;
-      }
-
-      # Create a new RRD only if it doesn't already exist and if a valid
-      # get data subroutine is created.  Keep the choose_data_sub for this
-      # file.
-      if (defined $substituted_data_expression) {
-        $choose_data_expr .= "    '$name_with_subgroup', $substituted_data_expression,\n";
-        unless (defined $rrd_data_files_ref->{$name_with_subgroup}) {
-          my $rrd_file = Orca::RRDFile->new($config_options,
-                                            $config_files,
-                                            $group_name,
-                                            $subgroup_name,
-                                            $name_with_subgroup,
-                                            $plot);
-          $rrd_data_files_ref->{$name_with_subgroup} = $rrd_file;
-        }
-        $self->{_all_rrd_ref}             = $rrd_data_files_ref;
-        $my_rrd_list{$name_with_subgroup} = 1;
-        push(@my_rrds, $name_with_subgroup);
-        push(@my_short_rrds, $short_name_with_subgroup);
-      }
-    }
-
-    # Generate a new plot for these data.
-    my $image;
-    my $all_names_with_subgroup = join(',', @name_with_subgroup);
-    if (defined ($image = $image_files_ref->{hash}{$all_names_with_subgroup})) {
-      $image->add_rrds(@my_rrds);
-    }
-    else {
-      $image = Orca::ImageFile->new($config_options,
-                                    $config_files,
-                                    $config_plots,
-                                    $group_name,
-                                    $subgroup_name,
-                                    join(',', @my_short_rrds),
-                                    join(',', @name_without_subgroup),
-                                    $plot,
-                                    $rrd_data_files_ref,
-                                    \@my_rrds);
-      $image_files_ref->{hash}{$all_names_with_subgroup} = $image;
-      push(@{$image_files_ref->{list}}, $image);
-      push(@{$config_plots->[$old_i]{creates}}, $image);
-    }
-
-    # Put into each RRD the images that are generated from it.
-    foreach my $rrd_key (@my_rrds) {
-      $rrd_data_files_ref->{$rrd_key}->add_image($image);
-    }
-  }
-
-  $choose_data_expr .= "  );\n}\n";
-  {
-    local $SIG{__DIE__}       = 'DEFAULT';
-    local $SIG{__WARN__}      = \&::die_when_called;
-    $self->{_choose_data_sub} = eval $choose_data_expr;
-  }
-  if ($@) {
-    my $m = $old_i + 1;
-    die "$0: warning: bad evaluation of command for plot #$m:\n$choose_data_expr\nOutput: $@\n";
-  }
-
-  $all_rrds_cache{$cache_key}        = $self->{_all_rrd_ref};
-  $choose_data_sub_cache{$cache_key} = $self->{_choose_data_sub};
-  my $tmp                            = [sort keys %my_rrd_list];
-  $my_rrd_list_cache{$cache_key}     = $tmp;
-  $self->{_my_rrd_list}              = $tmp;
-
-  1;
-}
-
-sub load_new_data {
-  my $self = shift;
-
-  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.
-  my $file_status = $self->status;
-  my $fd          = $::open_file_cache->get_fd($filename);
-  my $load_data   = $file_status != 0;
-  if ($file_status == -1) {
-    my $message = "file `$filename' did exist and is now gone.";
-    ::email_message($self->{_warn_email}, $message);
-    warn "$0: warning: $message\n";
-    unless ($fd) {
-      $self->{_last_read_time} = -1;
-      return 0;
-    }
-  }
-
-  # 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];
-  $self->{_is_current} = $self->is_current;
-  if ($old_is_current and
-      !$self->{_is_current} and
-      ($old_is_current_day == $current_day)) {
-    my $message = "file `$filename' was current and now is not.";
-    warn "$0: warning: $message\n";
-    ::email_message($self->{_warn_email}, $message);
-  }
-
-  # If we don't have to load the data from this file yet, then test to
-  # see if the data needs to be loaded if the file modification time
-  # is greater than the time at which it was last read.
-  my $file_mtime = $self->file_mtime;
-  unless ($load_data) {
-    $load_data = $file_mtime > $self->{_last_read_time};
-  }
-
-  # If the file still does not have to be loaded, now test to see if
-  # the timestamp of the last data point is larger than the last time
-  # of any RRD files that depend on this source file.
-  my $last_data_time = $self->{_last_data_time};
-  unless ($load_data) {
-    foreach my $rrd_key (@{$self->{_my_rrd_list}}) {
-      if ($self->{_all_rrd_ref}{$rrd_key}->rrd_update_time < $last_data_time) {
-        $load_data = 1;
-        last;
-      }
-    }
-  }
-
-  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.
-
-  my $opened_new_fd = !$fd;
-  unless ($fd) {
-    unless ($fd = $::open_file_cache->open($filename, $file_mtime)) {
-      warn "$0: warning: cannot open `$filename' for reading: $!\n";
-      return 0;
-    }
-    <$fd> if $self->{_first_line};
-  }
-
-  # Load in all of the data possible and send it to each plot.
-  my $date_column_index = $self->{_date_column_index};
-  my $use_file_mtime    = $self->{_date_source}[0] eq 'file_mtime';
-  my $number_added      = 0;
-  my $close_once_done   = 0;
-  my $number_columns    = @{$self->{_column_description}};
-  while (defined(my $line = <$fd>)) {
-    # Skip the line if the word timestamp appears in it.  This is a
-    # temporary fix for orcallator.se to place a new information line
-    # in the output file when it starts up.
-    next if $line =~ /timestamp/;
-
-    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.
-    if ($self->{_first_line} and @line != $number_columns) {
-      warn "$0: number of columns in line $. of `$filename' does not match column description.\n";
-      next;
-    }
-
-    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, calculate
-    # the value that needs to go to each RRD and push the value to the
-    # RRD.
-    my $add = 0;
-    my %values = &{$self->{_choose_data_sub}}(@line);
-    foreach my $rrd_key (@{$self->{_my_rrd_list}}) {
-      my $value = $values{$rrd_key};
-      if (defined $value) {
-        if ($self->{_all_rrd_ref}{$rrd_key}->queue_data($time, $value)) {
-          if ($opt_verbose > 2 and !$add) {
-            print "  Loaded `@line' at ", scalar localtime($time), " ($time).\n";
-          }
-          $add = 1;
-        }
-      }
-      else {
-        $close_once_done = 1;
-        warn "$0: internal error: expecting RRD name `$rrd_key' but no data loaded from `" . $self->filename . "' at time ", scalar localtime($time), " ($time).\n";
-      }
-    }
-    ++$number_added if $add;
-  }
-
-  # Update the time when the file was last read.
-  $self->{_last_data_time} = $last_data_time;
-  $self->{_last_read_time} = time;
-
-  $::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.
-  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.
-      $self->{_last_read_time} = -1;
-      $number_added += $self->load_new_data;
-    }
-  }
-  elsif ($close_once_done or $self->{_reopen}) {
-    $::open_file_cache->close($filename) or
-      warn "$0: warning: cannot close `$filename' for reading: $!\n";
-  }
+# Note the starting time of the script.
+my $start_time = time;
 
-  $number_added;
-}
-
-sub rrds {
-  @{$_[0]->{_my_rrd_list}};
+# Set up a signal handler to force looking for new files.
+my $force_find_files = 0;
+sub handle_hup {
+  $force_find_files = 1;
 }
-
-package main;
+$SIG{HUP} = \&handle_hup;
 
 sub Usage {
-  die "usage: $0 [-gifs] [-o] [-r] [-v] config_file\n";
+  die "usage: $0 [-o] [-r] [-v] config_file\n";
 }
 
 while (@ARGV and $ARGV[0] =~ /^-\w/) {
   my $arg = shift;
   if ($arg eq '-gifs') {
-    ++$opt_generate_gifs;
-    $IMAGE_SUFFIX = 'gif';
-  }
-  elsif ($arg eq '-o') {
-    ++$opt_once_only;
-  }
-  elsif ($arg eq '-v') {
+    $opt_generate_gifs = 1;
+    $IMAGE_SUFFIX      = 'gif';
+  } elsif ($arg eq '-o') {
+    $opt_once_only = 1;
+  } elsif ($arg eq '-r') {
+    $opt_rrd_update_only = 1;
+  } elsif ($arg eq '-v') {
     ++$opt_verbose;
-  }
-  elsif ($arg eq '-r') {
-    ++$opt_rrd_update_only;
-  }
-  else {
+  } else {
     Usage;
   }
 }
@@ -1872,20 +89,23 @@
 $SIG{__DIE__} = \&catch_signal;
 
 if ($opt_verbose) {
-  print "Orca version $VERSION using RRDs version $RRDs::VERSION.\n";
+  print "Orca version $ORCA_VERSION using RRDs version $RRDs::VERSION.\n";
 }
 
 &main(@ARGV);
 
 exit 0;
 
-# This is the name of the locking directory.
+# This is the locking directory.
 my $locking_directory;
 
 # This is set to 1 if the locking directory should be removed.
 my $rmdir_locking_directory;
 
 sub clean_up_and_quit {
+  # Print some statistics about running.
+  &running_stats;
+
   if ($rmdir_locking_directory and
       $locking_directory and
       -d $locking_directory) {
@@ -1901,8 +121,7 @@
   $signal =~ s/\.+$//;
   if ($signal =~ /$0/o) {
     print STDERR "$signal.\n";
-  }
-  else {
+  } else {
     print STDERR "$0: caught signal $signal.\n";
   }
   clean_up_and_quit;
@@ -1911,6 +130,10 @@
 sub main {
   my $config_filename = shift;
 
+  unless (-r $config_filename) {
+    die "$0: no configuration file `$config_filename' to read.\n";
+  }
+
   # Create a locking directory using the configuration filename.
   $locking_directory = "$config_filename.lock";
   unless (mkdir($locking_directory, 0755)) {
@@ -1918,59 +141,56 @@
   }
   $rmdir_locking_directory = 1;
 
-  my $start_time = time;
-
   # Load the configuration file.
-  my ($config_options,
-      $config_files,
-      $config_plots) = &load_config($config_filename);
-
-  # Check and do any work on the configuration information.
-  &check_config($config_filename,
-                $config_options,
-                $config_files,
-                $config_plots);
+  load_config($config_filename) or
+    die "$0: cannot load configuration file.\n";
 
-  # Load in any new data and update necessary plots.
-  &watch_data_sources($config_filename,
-                      $config_options,
-                      $config_files,
-                      $config_plots);
-
-  my $time_span = time - $start_time;
-  my $minutes   = int($time_span/60);
-  my $seconds   = $time_span - 60*$minutes;
+  # Load the file state information from disk.
+  load_old_state($config_options{state_file});
 
-  if ($opt_verbose) {
-    printf "Running time is %d:%02d minutes.\n", $minutes, $seconds;
-  }
+  # Create orca.gif, rrdtool.gif and any other static images for
+  # the HTML pages.
+  &create_static_images;
+
+  # Load in any new data and update necessary plots.
+  &watch_data_sources($config_filename);
 
   &clean_up_and_quit;
 }
 
-# Given a directory name, attempt to make all necessary directories.
-sub recursive_mkdir {
-  my $dir = shift;
-
-  # Remove extra /'s.
-  $dir =~ s:/{2,}:/:g;
-
-  my $path;
-  if ($dir =~ m:^/:) {
-    $path = '/';
-  }
-  else {
-    $path = './';
-  }
-
-  my @elements = split(/\//, $dir);
-  foreach my $element (@elements) {
-    $path = "$path/$element";
-    next if -d $path;
-    unless (mkdir($path, 0755)) {
-      die "$0: error: unable to create `$path': $!\n";
+sub create_static_images {
+  # Create the necessary images files in the HTML directory unless
+  # Orca was passed the -r flag, which instructs it to only update
+  # the RRD files.  The generated files should include orca.gif and
+  # rrdtool.gif.  Convert the hexadecimal forms stored in the DATA
+  # section to the raw image form on disk.
+  return if $opt_rrd_update_only;
+  my $image_filename = '';
+  while (<main::DATA>) {
+    chomp;
+    if ($image_filename) {
+      if (/CLOSE/) {
+        close(ORCA_WRITE) or
+          warn "$0: error in closing `$image_filename' for writing: $!\n";
+        $image_filename = '';
+      } else {
+        chomp;
+        print ORCA_WRITE pack('h*', $_);
+      }
+    } elsif (/OPEN (.*)/) {
+      $image_filename = "$config_options{html_dir}/$1";
+      print "Creating $1.\n" if $opt_verbose;
+      unless (open(ORCA_WRITE, ">$image_filename")) {
+        warn "$0: cannot open `$image_filename' for writing: $!\n";
+        $image_filename = '';
+      }
     }
   }
+  if ($image_filename) {
+    close(ORCA_WRITE) or
+      warn "$0: error in closing `$image_filename' for writing: $!\n";
+    $image_filename = '';
+  }
 }
 
 sub get_time_interval {
@@ -1982,33 +202,26 @@
 }
 
 sub watch_data_sources {
-  unless (@_ == 4) {
+  unless (@_ == 1) {
     confess "$0: watch_data_sources: passed wrong number of arguments.\n";
   }
-
-  my ($config_filename,
-      $config_options,
-      $config_files,
-      $config_plots) = @_;
+  my $config_filename = shift;
 
   my $rrd_data_files_ref  = {};
   my $old_found_files_ref = {};
   my $new_found_files_ref;
-  my $group_files_ref;
+  my $subgroup_fids_ref;
   my $image_files_ref = {list => [], hash => {}};
 
-  # Load the current state of the source data files.
-  my $saved_source_file_state = &load_state($config_options->{state_file});
-
   # The first time through we always find new files.  Determine the
   # time interval that the current time is in, where the intervals are
   # defined as the times to have Orca find new source data files.
   my $find_new_files = 1;
-  my $time_interval  = get_time_interval($config_options->{find_times});
+  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.
-  my %group_load_time;
+  # in a particular subgroup.
+  my %subgroup_load_time;
 
   for (;;) {
     # If Orca is being forced to find new files, then set up the
@@ -2016,7 +229,7 @@
     if ($force_find_files) {
       $force_find_files = 0;
       $find_new_files   = 1;
-      $time_interval    = get_time_interval($config_options->{find_times});
+      $time_interval    = get_time_interval($config_options{find_times});
     }
 
     my $found_new_files = 0;
@@ -2031,131 +244,157 @@
       # 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) =
+      ($found_new_files, $new_found_files_ref, $subgroup_fids_ref) =
          &find_files($config_filename,
-                     $config_options,
-                     $config_files,
-                     $config_plots,
-                     $saved_source_file_state,
                      $old_found_files_ref,
                      $rrd_data_files_ref,
                      $image_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.
-      undef %group_load_time;
-      foreach my $group (keys %$group_files_ref) {
-        my $group_load_time = 1e20;
-        foreach my $filename (@{$group_files_ref->{$group}}) {
-          my $load_time    = $new_found_files_ref->{$filename}->next_load_time;
-          $group_load_time = $load_time if $load_time < $group_load_time;
+      # Go through all of the subgroups and for each subgroup and all
+      # of the files in the subgroup find the next load time in the
+      # future.
+      undef %subgroup_load_time;
+      foreach my $group_name (keys %$subgroup_fids_ref) {
+        foreach my $subgroup_name (keys %{$subgroup_fids_ref->{$group_name}}) {
+          my $subgroup_load_time = 1e20;
+          foreach my $fid (@{$subgroup_fids_ref->{$group_name}{$subgroup_name}}) {
+            my $load_time       = $new_found_files_ref->{$fid}->next_load_time;
+            $subgroup_load_time = $load_time if $load_time < $subgroup_load_time;
+          }
+          $subgroup_load_time{$group_name}{$subgroup_name} = $subgroup_load_time;
         }
-        $group_load_time{$group} = $group_load_time;
       }
     }
 
-#    system("/bin/ps -p $$ -o\"rss vsz pmem time user pid comm\"");
+    &running_stats;
 
     # Because the amount of data loaded from the source data files can
-    # be large, go through each group of source files, load all of the
-    # data for that group, flush the data, and then go on to the next
-    # group.  For each source file that had new data, note the RRDs
-    # that get updated from that source file.  When going through each
-    # group note the time when the group should be next examined for
-    # updates.  Only note the time to sleep to if it is in the future.
-    my $updated_source_files = 0;
+    # be large, go through each subgroup of source files, load all of
+    # the data for that subgroup, flush the data, and then go on to
+    # the next subgroup.  For each source file that had new data, note
+    # the RRDs that get updated from that source file.  When going
+    # through each subgroup note the time when the subgroup should be
+    # next examined for updates.  Only note the time to sleep to if it
+    # is in the future.
     my $sleep_till_time;
-    foreach my $group (sort keys %group_load_time) {
-
-      # Skip this group if the load time has not been reached and if
-      # no new files were found.
-      my $group_load_time = $group_load_time{$group};
-      if ($group_load_time > time) {
-        $sleep_till_time = $group_load_time unless $sleep_till_time;
-        $sleep_till_time = $group_load_time if $group_load_time < $sleep_till_time;
-        next unless $found_new_files;
-      }
+    my $need_to_save_state = $found_new_files;
+    foreach my $group_name (sort keys %subgroup_load_time) {
+      foreach my $subgroup_name (sort keys %{$subgroup_load_time{$group_name}}) {
+        # Skip this subgroup if the load time has not been reached and
+        # if no new files were found.
+        my $subgroup_load_time = $subgroup_load_time{$group_name}{$subgroup_name};
+        if ($subgroup_load_time > time) {
+          $sleep_till_time = $subgroup_load_time unless $sleep_till_time;
+          if ($subgroup_load_time < $sleep_till_time) {
+            $sleep_till_time = $subgroup_load_time;
+          }
+          next unless $found_new_files;
+        }
 
-      if ($opt_verbose) {
-        print "Loading new data", $group ? " from $group" : "", ".\n";
-      }
+        if ($opt_verbose) {
+          print "Loading new data",
+                $subgroup_name ? " from $subgroup_name" : "", ".\n";
+        }
 
-      my %this_group_rrds;
-      my $number_new_data_points = 0;
-      $group_load_time = 1e20;
-      foreach my $filename (@{$group_files_ref->{$group}}) {
-        my $source_file = $new_found_files_ref->{$filename};
-        my $number      = $source_file->load_new_data;
-        $number_new_data_points += $number;
-        if ($number) {
-          foreach my $rrd ($source_file->rrds) {
-            $this_group_rrds{$rrd} = $rrd_data_files_ref->{$rrd};
+        my %this_subgroup_rrds;
+        my $number_new_data_points             = 0;
+        my $number_new_data_points_since_flush = 0;
+        $subgroup_load_time                    = 1e20;
+        my $previous_fid;
+        foreach my $fid (@{$subgroup_fids_ref->{$group_name}{$subgroup_name}}) {
+          # Determine if the currently loaded data should be flushed.
+          if (defined $previous_fid) {
+            local $Orca::Config::a = $fid;
+            local $Orca::Config::b = $previous_fid;
+            if (&{$config_groups{$group_name}{filename_compare}} > 1 and
+                $number_new_data_points_since_flush) {
+              if ($opt_verbose) {
+                print "Flushing new data",
+                       $subgroup_name ? " from $subgroup_name" : "", ".\n";
+              }
+              foreach my $rrd (sort values %this_subgroup_rrds) {
+                $rrd->flush_data;
+              }
+              save_old_state($config_options{state_file},
+                             $new_found_files_ref);
+              $number_new_data_points_since_flush = 0;
+              $need_to_save_state                 = 0;
+            }
           }
-          if ($opt_verbose) {
-            printf "  Read %5d data point%s from `$filename'.\n",
-              $number, $number > 1 ? 's' : '';
+          $previous_fid   = $fid;
+          my $source_file = $new_found_files_ref->{$fid};
+          my $number      = $source_file->load_new_data;
+          $number_new_data_points             += $number;
+          $number_new_data_points_since_flush += $number;
+          if ($number) {
+            foreach my $rrd ($source_file->rrds) {
+              $this_subgroup_rrds{$rrd} = $rrd_data_files_ref->{$rrd};
+            }
+            if ($opt_verbose) {
+              printf "  Read %5d data point%s from `$sfile_fids[$fid]'.\n",
+                $number, $number > 1 ? 's' : '';
+            }
           }
+          my $load_time       = $source_file->next_load_time;
+          $subgroup_load_time = $load_time if $load_time < $subgroup_load_time;
         }
-        my $load_time    = $source_file->next_load_time;
-        $group_load_time = $load_time if $load_time < $group_load_time;
-      }
 
-      # Update the load time for this group.
-      $group_load_time{$group} = $group_load_time;
+        # Update the load time for this subgroup.
+        $subgroup_load_time{$group_name}{$subgroup_name} = $subgroup_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.
-      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;
-      }
+        # Now that the source data files have been read, recalculate
+        # the time to sleep to if the load time for this subgroup is
+        # in the future.
+        if (time < $subgroup_load_time) {
+          $sleep_till_time = $subgroup_load_time unless $sleep_till_time;
+          if ($subgroup_load_time < $sleep_till_time) {
+            $sleep_till_time = $subgroup_load_time;
+          }
+        }
 
-      next unless $number_new_data_points;
-      $updated_source_files = 1;
+        next unless $number_new_data_points;
 
-      # 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";
-      }
-      foreach my $rrd (sort {$a->name cmp $b->name} values %this_group_rrds) {
-        $rrd->flush_data;
-        next if $opt_rrd_update_only;
-        foreach my $gif ($rrd->created_gifs) {
-          next if $gif->rrds > 1;
-          $gif->plot;
+        # Flush the data that has been loaded for each plot.  To keep
+        # the RRD that was just created in the system's cache, plot
+        # any images that only depend on this RRD, since images 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 and updating ", uc($IMAGE_SUFFIX),
+                $subgroup_name ? "s from $subgroup_name" : "s", ".\n";
+        }
+        foreach my $rrd (sort {$a->name cmp $b->name}
+                              values %this_subgroup_rrds) {
+          $rrd->flush_data;
+          next if $opt_rrd_update_only;
+          foreach my $image ($rrd->created_images) {
+            next if $image->rrds > 1;
+            $image->plot;
+          }
         }
+        save_old_state($config_options{state_file}, $new_found_files_ref);
+        $need_to_save_state = 0;
       }
     }
 
-#    system("/bin/ps -p $$ -o\"rss vsz pmem time user pid comm\"");
-
-    # Save the current state of the source data files.
-    if ($found_new_files or $updated_source_files) {
-      &save_state($config_options->{state_file}, $new_found_files_ref);
+    # Save the state if any new data was loaded or new files were found.
+    if ($need_to_save_state) {
+      save_old_state($config_options{state_file}, $new_found_files_ref);
     }
 
-    # Create the HTML and GIF files now.
+    # Create the HTML and image files now.
     unless ($opt_rrd_update_only) {
-      # Plot the data in each gif.
-      print "Updating " . uc($IMAGE_SUFFIX). "s.\n" if $opt_verbose;;
-#      system("/bin/ps -p $$ -o\"rss vsz pmem time user pid comm\"");
-      foreach my $gif (@{$image_files_ref->{list}}) {
-        $gif->plot;
+      # Plot the data in each image.
+      print "Updating ", uc($IMAGE_SUFFIX), "s.\n" if $opt_verbose;
+      foreach my $image (@{$image_files_ref->{list}}) {
+        $image->plot;
       }
-#      system("/bin/ps -p $$ -o\"rss vsz pmem time user pid comm\"");
 
       # Make the HTML files.
       if ($found_new_files) {
-        &create_html_files($config_options,
-                           $config_files,
-                           $config_plots,
-                           $new_found_files_ref,
-                           $group_files_ref,
+        &create_html_files($new_found_files_ref,
+                           $subgroup_fids_ref,
                            $image_files_ref);
         $found_new_files = 0;
       }
@@ -2168,7 +407,7 @@
     # 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});
+    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;
@@ -2201,11 +440,11 @@
   $string;
 }
 
-# Sort group names depending upon the type of characters in the
+# Sort subgroup names depending upon the type of characters in the
 # group's name.
-sub sort_group_names {
-  my $a_name = ref($a) ? $a->group : $a;
-  my $b_name = ref($b) ? $b->group : $b;
+sub sort_subgroup_names {
+  my $a_name = ref($a) ? $a->subgroup_name : $a;
+  my $b_name = ref($b) ? $b->subgroup_name : $b;
 
   # If both names are purely digits, then do a numeric comparison.
   if ($a_name =~ /^[-]?\d+$/ and $b_name =~ /[-]?\d+$/) {
@@ -2220,8 +459,7 @@
     my $return = $a_head cmp $b_head;
     if ($return) {
       return $return;
-    }
-    else {
+    } else {
       return $a_digits <=> $b_digits;
     }
   }
@@ -2230,27 +468,24 @@
 }
 
 # Create all of the different HMTL files with all of the proper HREFs
-# to the GIFs.
+# to the images.
 sub create_html_files {
-  my ($config_options,
-      $config_files,
-      $config_plots,
-      $found_files_ref,
-      $group_files_ref,
+  my ($found_files_ref,
+      $subgroup_fids_ref,
       $image_files_ref) = @_;
 
-  my $html_dir         = $config_options->{html_dir};
+  my $html_dir         = $config_options{html_dir};
   my $index_filename   = "$html_dir/index.html";
 
   print "Creating HTML files in `$html_dir/'.\n" if $opt_verbose;
 
   # Create the main HTML index.html file.
   my $index_html = Orca::HTMLFile->new($index_filename,
-                                       $config_options->{html_top_title},
-                                       $config_options->{html_page_header},
-                                       $config_options->{html_page_footer});
+                                       $config_options{html_top_title},
+                                       $config_options{html_page_header},
+                                       $config_options{html_page_footer});
   unless ($index_html) {
-    warn "$0: warning: cannot open `$index_filename' for writing: $!\n";
+    warn "$0: warning: cannot create Orca::HTMLFile object: $@.\n";
     return;
   }
   $index_html->print("<hr>\n<font size=\"-2\">");
@@ -2263,117 +498,124 @@
   # images for that subgroup.  Also create an HTML file for different time
   # span images (i.e., daily, monthly, etc).
 
-  # 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 there is only one group and that group
-  # does not have a name, then give the group the name Everything.
+  # Go through each subgroup.  If there is only one subgroup and that
+  # subgroup does not have a name, then give the subgroup 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;
+  # and in HTML content.  Use the original subgroup name as a hash key.
+  my $number_subgroups = 0;
+  foreach my $group_name (keys %$subgroup_fids_ref) {
+    $number_subgroups += keys %{$subgroup_fids_ref->{$group_name}};
+  }
   $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 = escape_name($html_group);
-    my $element = "<table border=2><tr><td><b>$html_group</b></td></tr>\n<tr><td>\n";
-    foreach my $plot_type (@gif_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 various time span HTML files for this subgroup.
-    my @html_files;
-    foreach my $plot_type (@gif_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 various time span HTML files add HREFs to the
-    # other date span HTML files in the same subgroup.
-    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 images now that have the same subgroup name as the
-    # HTML files that are being created.  Make sure the images appear
-    # in the files in the order listed in the configuration file.
-    my @gifs = sort {$a->{_plot_ref}{_index} <=> $b->{_plot_ref}{_index}}
-               grep {$group eq $_->group} @{$image_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 $group_name (sort keys %$subgroup_fids_ref) {
+    foreach my $subgroup_name (sort sort_subgroup_names keys
+                               %{$subgroup_fids_ref->{$group_name}}) {
+      my $html_subgroup_name = ($number_subgroups == 1 and !$subgroup_name) ? 'Everything' : $subgroup_name;
+
+      # Create the HTML code for the main index.html file.
+      my $subgroup_basename = escape_name($html_subgroup_name);
+      my $element = "<table border=2><tr><td><b>$html_subgroup_name</b></td></tr>\n<tr><td>\n";
+      foreach my $plot_type (@IMAGE_PLOT_TYPES) {
+        $element      .= "<a href=\"$subgroup_basename-$plot_type.html\">";
+        my $Plot_Type  = Capatialize($plot_type);
+        $element      .= "$Plot_Type</a><br>\n";
+      }
+      $element .= "<a href=\"$subgroup_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 various time span HTML files for this subgroup.
+      my @html_files;
+      foreach my $plot_type (@IMAGE_PLOT_TYPES, 'all') {
+        my $href      = "$subgroup_basename-$plot_type.html";
+        my $filename  = "$html_dir/$href";
+        my $Plot_Type = Capatialize($plot_type);
+        my $fd = Orca::HTMLFile->new($filename,
+                                     "$Plot_Type $html_subgroup_name",
+                                     $config_options{html_page_header},
+                                     $config_options{html_page_footer});
+        unless ($fd) {
+          warn "$0: warning: cannot create Orca::HTMLFile object: $@.\n";
+          next;
+        }
+        push (@html_files, {fd        => $fd,
+                            href      => $href,
+                            plot_type => $plot_type,
+                            Plot_Type => $Plot_Type});
+      }
+
+      # At the top of the various time span HTML files add HREFs to the
+      # other date span HTML files in the same subgroup.
+      my $href_html;
+      foreach my $plot_type (@html_files) {
+        $href_html .= "<a href=\"$plot_type->{href}\">" .
+                      "$plot_type->{Plot_Type} $subgroup_name</a><br>\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=\"" . escape_name($name) . ".html\"";
-      my $sub_dir  = $config_files->{$gif->files_key}{sub_dir};
-      my $gif_size = $gif->image_src_size;
-
-      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");
+      # Use only those images now that have the same subgroup name as
+      # the HTML files that are being created.  Make sure the images
+      # appear in the files in the order listed in the configuration
+      # file.
+      my @images = sort {$a->plot_ref->{_index} <=> $b->plot_ref->{_index}}
+                   grep {$subgroup_name eq $_->subgroup_name} @{$image_files_ref->{list}};
+      if (@images > 1) {
+        my $href_html = "<hr>";
+        for (my $i=0; $i<@images; ++$i) {
+          $href_html .= "<a href=\"#$i\">[" .
+                        replace_subgroup_name($images[$i]->plot_ref->{title},'') .
+                        "]</a><spacer size=10>\n";
+        }
+        foreach my $html_file (@html_files) {
+          $html_file->{fd}->print($href_html);
+        }
       }
 
-      # 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}.$IMAGE_SUFFIX";
-        $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);
-      }
-    }
+      # Add the images to the HTML files.
+      for (my $i=0; $i<@images; ++$i) {
+        my $image      = $images[$i];
+        my $name       = $image->name;
+        my $title      = replace_subgroup_name($image->plot_ref->{title},
+                                               $image->subgroup_name);
+        my $href       = "href=\"" . escape_name($name) . ".html\"";
+        my $sub_dir    = $config_groups{$image->group_name}{sub_dir};
+        my $image_size = $image->image_src_size;
+
+        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 images 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 $image_filename = "$name-$html_files[$j]{plot_type}.$IMAGE_SUFFIX";
+          $image_filename    = "$subgroup_name/$image_filename" if $sub_dir;
+          my $html = "<a $href><img src=\"$image_filename\" $image_size " .
+                     "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");
+        foreach my $html_file (@html_files) {
+          $html_file->{fd}->print("<hr>\n");
+        }
     }
   }
 
-  # If there are any remaining groups to display, do it now.
+  # If there are any remaining subgroups to display, do it now.
   if (@table_columns) {
     $index_html->print("<tr valign=top>" .
                        join('', @table_columns) .
@@ -2383,13 +625,13 @@
                      "<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.
+  # created that contain the HREFs to the proper images.  The HTML files
+  # created here HREF to the images 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.
+  # images that show that plot.  Use the @images_by_type array to keep
+  # the ordering in the type of images and the %images_by_type to hold
+  # references to an array for each type of image.
   $index_html->print("<table>\n");
 
   # This sets the number of plot types to place into a single row in
@@ -2398,9 +640,9 @@
   @table_columns        = ();
 
   # Go through all of the configured plots.
-  for (my $i=0; $i<@$config_plots; ++$i) {
+  for (my $i=0; $i<@config_plots; ++$i) {
 
-    next unless @{$config_plots->[$i]{creates}};
+    next unless @{$config_plots[$i]{creates}};
 
     # Create an ordered list of images sorted on the legend name for
     # each image.  Remember, each image represented here actually
@@ -2410,26 +652,25 @@
     # The %legends hash is keyed by the legend name with no subgroup
     # substitution and contains a reference to an array of image that
     # have the same legend name.
-    my %gif_legend_no_subgroup;
-    my %same_legends_gif_list;
-    foreach my $gif (@{$config_plots->[$i]{creates}}) {
-      my $legend_no_subgroup = replace_group_name($gif->plot_ref->{title}, '');
-      $gif_legend_no_subgroup{$gif} = $legend_no_subgroup; 
-      
-      unless (defined $same_legends_gif_list{$legend_no_subgroup}) {
-        $same_legends_gif_list{$legend_no_subgroup} = [];
-      }
-      push(@{$same_legends_gif_list{$legend_no_subgroup}}, $gif);
-    }
-
-    # 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.
-    my @gifs;
-    foreach my $legend_no_subgroup (sort keys %same_legends_gif_list) {
-      @{$same_legends_gif_list{$legend_no_subgroup}} =
-        sort sort_group_names @{$same_legends_gif_list{$legend_no_subgroup}};
-      push(@gifs, @{$same_legends_gif_list{$legend_no_subgroup}});
+    my %image_legend_no_subgroup;
+    my %same_legends_image_list;
+    foreach my $image (@{$config_plots[$i]{creates}}) {
+      my $legend_no_subgroup = replace_subgroup_name($image->plot_ref->{title}, '');
+      $image_legend_no_subgroup{$image} = $legend_no_subgroup; 
+      unless (defined $same_legends_image_list{$legend_no_subgroup}) {
+        $same_legends_image_list{$legend_no_subgroup} = [];
+      }
+      push(@{$same_legends_image_list{$legend_no_subgroup}}, $image);
+    }
+
+    # Put together the correctly ordered list of images using the array
+    # references in the legends hash.  Sort the images using the special
+    # sorting routine for subgroup names.
+    my @images;
+    foreach my $legend_no_subgroup (sort keys %same_legends_image_list) {
+      @{$same_legends_image_list{$legend_no_subgroup}} =
+        sort sort_subgroup_names @{$same_legends_image_list{$legend_no_subgroup}};
+      push(@images, @{$same_legends_image_list{$legend_no_subgroup}});
     }
 
     # This hash keyed by legend name holds an array of references to a
@@ -2438,10 +679,10 @@
 
     # Now for each set of time span (i.e., daily, weekly, etc) images, go
     # through and create the correct HTML files.
-    foreach my $gif (@gifs) {
+    foreach my $image (@images) {
 
-      my $name_with_subgroup = escape_name($gif->no_group_name);
-      my $legend_no_subgroup = $gif_legend_no_subgroup{$gif};
+      my $no_subgroup_name   = escape_name($image->no_subgroup_name);
+      my $legend_no_subgroup = $image_legend_no_subgroup{$image};
 
       # If this is the first time that this legend has been seen in
       # for creating the proper HTML files, then create the new HTML
@@ -2451,16 +692,16 @@
         # Now create the HTML files for the time span plots.  Use the
         # legend name to create this list.
         $legend_html_files{$legend_no_subgroup} = [];
-        foreach my $plot_type (@gif_plot_type, 'all') {
-          my $href      = "$name_with_subgroup-$plot_type.html";
+        foreach my $plot_type (@IMAGE_PLOT_TYPES, 'all') {
+          my $href      = "$no_subgroup_name-$plot_type.html";
           my $filename  = "$html_dir/$href";
           my $Plot_Type = Capatialize($plot_type);
           my $fd = Orca::HTMLFile->new($filename,
                                        "$Plot_Type $legend_no_subgroup",
-                                       $config_options->{html_page_header},
-                                       "<hr>\n$config_options->{html_page_footer}");
+                                       $config_options{html_page_header},
+                                       "<hr>\n$config_options{html_page_footer}");
           unless ($fd) {
-            warn "$0: warning: cannot open `$filename' for writing: $!\n";
+            warn "$0: warning: cannot create Orca::HTMLFile object: $@.\n";
             next;
           }
           push(@{$legend_html_files{$legend_no_subgroup}},
@@ -2481,14 +722,14 @@
         }
 
         # 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
+        # subgroups in the HTML file.  This makes traversing the HTML
+        # page easier.  Do this if there are two or more subgroups in
         # this HTML page.
-        if (@{$same_legends_gif_list{$legend_no_subgroup}} > 1) {
+        if (@{$same_legends_image_list{$legend_no_subgroup}} > 1) {
           $href_html .= "<hr>\n";
-          foreach my $legend_gif (@{$same_legends_gif_list{$legend_no_subgroup}}) {
-            my $group = $legend_gif->group;
-            $href_html .= "<a href=\"#$group\">[$group]</a><spacer size=10>\n";
+          foreach my $legend_image (@{$same_legends_image_list{$legend_no_subgroup}}) {
+            my $subgroup = $legend_image->subgroup_name;
+            $href_html  .= "<a href=\"#$subgroup\">[$subgroup]</a><spacer size=10>\n";
           }
         }
         foreach my $html_file (@legend_html_files) {
@@ -2499,12 +740,12 @@
         # to these other HTML files.  If the configuration file contains
         # an href for information on this plot, then include the href here.
         my $element = "<td><b>$legend_no_subgroup";
-        if (my $legend_href = $config_plots->[$i]{href}) {
+        if (my $legend_href = $config_plots[$i]{href}) {
           $element .= " [<a href=\"$legend_href\">Info</a>]";
         }
         $element .= "</b></td>\n";
-        foreach my $plot_type (@gif_plot_type, 'all') {
-          $element .= "<td><a href=\"$name_with_subgroup-$plot_type.html\">";
+        foreach my $plot_type (@IMAGE_PLOT_TYPES, 'all') {
+          $element .= "<td><a href=\"$no_subgroup_name-$plot_type.html\">";
           $element .= Capatialize($plot_type) . "</a></td>\n";
         }
         push(@table_columns, $element);
@@ -2517,45 +758,44 @@
       # At this point the HTML files for this set of of images have been
       # opened.  Now create the summary HTML file that contains only the
       # images for a particular plot for a particular subgroup.
-      my $with_group_name   = escape_name($gif->name);
-      my $legend_with_group = replace_group_name($gif->plot_ref->{title},
-                                                 $gif->group);
-      my $summarize_name = "$html_dir/$with_group_name.html";
-      my $summarize_html = Orca::HTMLFile->new($summarize_name,
-                                               $legend_with_group,
-                                               $config_options->{html_page_header},
-                                               $config_options->{html_page_footer});
+      my $with_subgroup_name   = escape_name($image->name);
+      my $legend_with_subgroup = replace_subgroup_name($image->plot_ref->{title},
+                                                       $image->subgroup_name);
+      my $summarize_name       = "$html_dir/$with_subgroup_name.html";
+      my $summarize_html       = Orca::HTMLFile->new($summarize_name,
+                                                     $legend_with_subgroup,
+                                                     $config_options{html_page_header},
+                                                     $config_options{html_page_footer});
       unless ($summarize_html) {
-        warn "$0: warning: cannot open `$summarize_name' for writing: $!\n";
+        warn "$0: warning: cannot create Orca::HTMLFile object: $@.\n";
         next;
       }
-      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->image_src_size;
-      foreach my $plot_type (@gif_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.$IMAGE_SUFFIX\"",
-                               $gif_size,
-                               "alt=\"$Plot_Type $legend_with_group\">\n");
+      my $sub_dir        = $config_groups{$image->group_name}{sub_dir};
+      my $image_filename = $with_subgroup_name;
+      $image_filename    = $image->subgroup_name . "/$image_filename" if $sub_dir;
+      my $image_size     = $image->image_src_size;
+      foreach my $plot_type (@IMAGE_PLOT_TYPES) {
+        my $Plot_Type    = Capatialize($plot_type);
+        $summarize_html->print("<hr>\n<h2>$Plot_Type $legend_with_subgroup</h2>\n",
+                               "<img src=\"$image_filename-$plot_type.$IMAGE_SUFFIX\"",
+                               $image_size,
+                               "alt=\"$Plot_Type $legend_with_subgroup\">\n");
       }
 
       # Now add the images into each HTML file.
-      my $name  = $gif->name;
-      my $group = $gif->group;
-
-      my $href = "href=\"$with_group_name.html\"";
+      my $name     = $image->name;
+      my $subgroup = $image->subgroup_name;
+      my $href     = "href=\"$with_subgroup_name.html\"";
 
       my @legend_html_files = @{$legend_html_files{$legend_no_subgroup}};
-      $legend_html_files[-1]{fd}->print("<hr>\n<h2><a ${href} name=\"$group\">$group $legend_no_subgroup</a></h2>\n");
+      $legend_html_files[-1]{fd}->print("<hr>\n<h2><a ${href} name=\"$subgroup\">$subgroup $legend_no_subgroup</a></h2>\n");
       for (my $i=0; $i<@legend_html_files-1; ++$i) {
-        my $Plot_Type    = $legend_html_files[$i]{Plot_Type};
-        my $gif_filename = "$name-$legend_html_files[$i]{plot_type}.$IMAGE_SUFFIX";
-        $gif_filename    = "$group/$gif_filename" if $sub_dir;
-        my $html = "<a $href><img src=\"$gif_filename\" $gif_size " .
-                   "alt=\"$Plot_Type $group $legend_no_subgroup\"></a>\n";
-        $legend_html_files[$i]{fd}->print("<hr>\n<h2><a ${href} name=\"$group\">$Plot_Type $group $legend_no_subgroup</a></h2>\n");
+        my $Plot_Type      = $legend_html_files[$i]{Plot_Type};
+        my $image_filename = "$name-$legend_html_files[$i]{plot_type}.$IMAGE_SUFFIX";
+        $image_filename    = "$subgroup/$image_filename" if $sub_dir;
+        my $html = "<a $href><img src=\"$image_filename\" $image_size " .
+                   "alt=\"$Plot_Type $subgroup $legend_no_subgroup\"></a>\n";
+        $legend_html_files[$i]{fd}->print("<hr>\n<h2><a ${href} name=\"$subgroup\">$Plot_Type $subgroup $legend_no_subgroup</a></h2>\n");
         $legend_html_files[$i]{fd}->print($html);
         $legend_html_files[-1]{fd}->print($html);
       }
@@ -2568,59 +808,6 @@
   $index_html->print("\n</table>\n\n</font>\n<hr>\n");
 }
 
-sub perl_glob {
-  my $regexp = shift;
-
-  # 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.
-  $regexp =~ s:/{2,}:/:g;
-
-  # If the regular expression begins with a /, then remove it from the
-  # 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.
-  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.
-  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 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 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.  Make sure not to
-  # process any directories named `..'.
-  my @results;
-  my $new_regexp = join('/', @regexp_elements);
-  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));
-  }
-
-  return @results;
-}
-
 # Email the list of people a message.
 sub email_message {
   my ($people, $subject) = @_;
@@ -2631,27 +818,26 @@
     print SENDMAIL <<"EOF";
 To: $people
 Subject: Orca: $subject
- 
+
 Orca: $subject
 EOF
-    close(SENDMAIL) or
-      warn "$0: warning: sendmail did not close: $!\n";
-  }
-  else {
+  close(SENDMAIL) or
+    warn "$0: warning: sendmail did not close: $!\n";
+  } else {
     warn "$0: warning: cannot fork for sendmail: $!\n";
   }
 }
 
-# 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) = @_;
+# Replace any %g with the subgroup and any %G's with a capitalized
+# version of the subgroup in the title string with the subgroup name.
+sub replace_subgroup_name {
+  my ($title, $subgroup) = @_;
 
-  my $Group = $group;
-  substr($Group, 0, 1) = uc(substr($Group, 0, 1));
+  my $Subgroup = $subgroup;
+  substr($Subgroup, 0, 1) = uc(substr($Subgroup, 0, 1));
 
-  $title =~ s/%g/$group/ge;
-  $title =~ s/%G/$Group/ge;
+  $title =~ s/%g/$subgroup/ge;
+  $title =~ s/%G/$Subgroup/ge;
   $title =~ s/^\s+//;
   $title =~ s/\s+$//;
   $title;
@@ -2702,882 +888,177 @@
   $name;
 }
 
-# Return an list of the unique elements of a list.
-sub unique {
-  my %a;
-  my @unique;
-  foreach my $element (@_) {
-    unless (defined $a{$element}) {
-      push(@unique, $element);
-      $a{$element} = 1;
-    }
-  }
-  @unique;
+# Replace special characters from key names, remove redundant characters,
+# and shorten the names so the maximum path name is not exceeded.
+sub old_escape_name {
+  my $name = shift;
+  $name =~ s/:/_/g;
+  $name =~ s:/:_per_:g;
+  $name =~ s:\s+:_:g;
+  $name =~ s:%:_percent_:g;
+  $name =~ s:#:_number_:g;
+  $name =~ s:\*:_X_:g;
+  $name =~ s:([_,]){2,}:$1:g;
+
+  # Remove trailing _'s.
+  $name =~ s:_+$::;
+  $name =~ s:_+,:,:g;
+  $name;
 }
 
 sub find_files {
-  unless (@_ == 8) {
+  unless (@_ == 4) {
     confess "$0: find_files passed wrong number of arguments.\n";
   }
 
   my ($config_filename,
-      $config_options,
-      $config_files,
-      $config_plots,
-      $saved_source_file_state,
       $old_found_files_ref,
       $rrd_data_files_ref,
       $image_files_ref) = @_;
 
-  my $new_found_files_ref = {};
-  my $group_files         = {};
-  my $found_new_files     = 0;
-
-  foreach my $files_key (sort keys %$config_files) {
-    # Find all the files matching the regular expression.
-    my @filenames;
-    foreach my $regexp (@{$config_files->{$files_key}{find_files}}) {
-      push(@filenames, grep {-r $_} perl_glob($regexp));
+  my %new_found_files;
+  my %subgroup_fids;
+  my $found_new_files = 0;
+
+  foreach my $group_name (sort keys %config_groups) {
+    # Find all the readable files matching the regular expression.
+    my @fids;
+    foreach my $regexp (@{$config_groups{$group_name}{find_files}}) {
+      push(@fids, perl_glob($regexp));
     }
-    unless (@filenames) {
-      warn "$0: warning: no files found for `find_files' for `files $files_key' in `$config_filename'.\n";
+    unless (@fids) {
+      warn "$0: warning: no files found for `find_files' for `group $group_name' in `$config_filename'.\n";
       next;
     }
 
-    # 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)) {
-      # Find the group that the files belong in.
-      my $group = undef;
-      foreach my $regexp (@{$config_files->{$files_key}{find_files}}) {
+    # Calculate which subgroup the file belongs in and create a hash listing
+    # the filenames for each group.
+    my %tmp_fids_by_subgroup;
+    my %tmp_subgroup_by_fid;
+    @fids = unique(@fids);
+    foreach my $fid (@fids) {
+      # Find the subgroup that the files belong in.
+      my $filename = $sfile_fids[$fid];
+      my $subgroup = undef;
+      foreach my $regexp (@{$config_groups{$group_name}{find_files}}) {
         my @result = ($filename =~ $regexp);
         if (@result) {
           # 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);
+          $subgroup = join('_', grep {length($_)} @result);
           last;
         }
       }
-      unless (defined $group) {
-        warn "$0: warning: internal error: found `$filename' but no regexp match for it.\n";
+      unless (defined $subgroup) {
+        warn "$0: warning: internal error: found `$filename' but no ",
+             "regexp match for it.\n";
         next;
       }
-      unless (defined $tmp_files_by_group{$group}) {
-        $tmp_files_by_group{$group} = [];
+      unless (defined $tmp_fids_by_subgroup{$subgroup}) {
+        $tmp_fids_by_subgroup{$subgroup} = [];
       }
-      push(@{$tmp_files_by_group{$group}}, $filename);
-      $tmp_group_by_file{$filename} = $group;
+      push(@{$tmp_fids_by_subgroup{$subgroup}}, $fid);
+      $tmp_subgroup_by_fid{$fid} = $subgroup;
     }
 
-    # Create a new list of filenames sorted by group name and inside
-    # each group sorted by filename.  This will cause the created
-    # plots to appear in group order.
-    @filenames = ();
-    foreach my $key (sort keys %tmp_files_by_group) {
-      push(@filenames, sort @{$tmp_files_by_group{$key}});
+    # Create a new list of filenames sorted by subgroup name and
+    # inside each subgroup sorted using the filename_compare
+    # configuration option function or by the Perl cmp function.  This
+    # will cause the created plots to appear in subgroup order.  The
+    # compare subroutine expects the input in the $a and $b package
+    # variables.  Since the subroutine was eval'ed in the Orca::Config
+    # package, the sort subroutine needs be in that package.
+    @fids = ();
+    {
+      local *Orca::Config::fc = $config_groups{$group_name}{filename_compare};
+      foreach my $subgroup (sort keys %tmp_fids_by_subgroup) {
+        push(@fids,
+             sort Orca::Config::fc @{$tmp_fids_by_subgroup{$subgroup}});
+      }
     }
 
     # Now for each file, create the Orca::SourceDataFile object that
     # manages that file and the images that are generated from the
     # file.  Delete from the list of filenames those files that have
     # not successfully created Orca::SourceDataFile objects.
-    for (my $i=0; $i<@filenames;) {
-      my $filename = $filenames[$i];
+    for (my $i=0; $i<@fids;) {
+      my $fid = $fids[$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 > 2;
+      # same file is being used in another group.
+      unless (defined $new_found_files{$fid}) {
+        if (defined $old_found_files_ref->{$fid}) {
+          $new_found_files{$fid} = $old_found_files_ref->{$fid};
+        } else {
+          print "  $sfile_fids[$fid]\n" if $opt_verbose > 2;
           my $data_file =
-            Orca::SourceFile->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);
+            Orca::SourceFile->new($fid,
+                                  $config_groups{$group_name}{interval},
+                                  $config_options{late_interval},
+                                  $config_groups{$group_name}{reopen},
+                                  $config_groups{$group_name}{column_description},
+                                  $config_groups{$group_name}{date_source},
+                                  $config_groups{$group_name}{date_format},
+                                  $config_options{warn_email});
           unless ($data_file) {
-            warn "$0: warning: cannot process `$filename'.\n";
-            splice(@filenames, $i, 1);
+            warn "$0: warning: cannot process `$sfile_fids[$fid]'.\n";
+            splice(@fids, $i, 1);
             next;
           }
-          $new_found_files_ref->{$filename} = $data_file;
+          $new_found_files{$fid} = $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_groups($files_key);
+    # Register with each source data file the groups that use it.
+    foreach my $fid (@fids) {
+      $new_found_files{$fid}->add_groups($group_name);
     }
 
     # 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,
-                                                   $config_plots,
-                                                   $files_key,
-                                                   $group,
-                                                   $rrd_data_files_ref,
-                                                   $image_files_ref);
-      unless (defined $group_files->{$group}) {
-        $group_files->{$group} = [];
+    foreach my $fid (@fids) {
+      my $subgroup_name = $tmp_subgroup_by_fid{$fid};
+      $new_found_files{$fid}->add_plots($group_name,
+                                        $subgroup_name,
+                                        $rrd_data_files_ref,
+                                        $image_files_ref);
+      unless (defined $subgroup_fids{$group_name}{$subgroup_name}) {
+        $subgroup_fids{$group_name}{$subgroup_name} = [];
       }
-      push(@{$group_files->{$group}}, $filename);
+      push(@{$subgroup_fids{$group_name}{$subgroup_name}}, $fid);
     }
   }
-  my @found_files = keys %$new_found_files_ref;
+  my @found_files = keys %new_found_files;
 
   die "$0: no data source files found.\n" unless @found_files;
 
-  return ($found_new_files,
-          $new_found_files_ref,
-          $group_files);
-}
-
-# This loads the old source file state information.
-my @save_state_keys;
-sub load_state {
-  my $state_file = shift;
-
-  my %state;
-
-  unless (@save_state_keys) {
-    @save_state_keys = qw(_filename _last_data_time _last_read_time);
-  }
-
-  unless (open(STATE, $state_file)) {
-    warn "$0: warning: cannot open state file `$state_file' for reading: $!\n";
-    return \%state;
-  }
-
-  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.
-  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>) {
-    my @line = split;
-    if (@line != @keys) {
-      warn "$0: inconsistent number of elements on line $. of `$state_file'.\n";
-      next;
-    }
-
-    my $filename = $line[0];
-    for (my $i=1; $i<@keys; ++$i) {
-      $state{$filename}{$keys[$i]} = $line[$i];
-    }
-  }
-
-  close(STATE) or
-    warn "$0: warning: cannot close `$state_file' for reading: $!\n";
-
-  \%state;
-}
-
-# Write the state information for the source data files.
-sub save_state {
-  my ($state_file, $state_ref) = @_;
-
-  print "Saving state into `$state_file'.\n" if $opt_verbose;
-
-  if (open(STATE, "> $state_file.tmp")) {
-
-    print STATE "@save_state_keys\n";
-
-    foreach my $filename (sort keys %$state_ref) {
-      foreach my $key (@save_state_keys) {
-        print STATE $state_ref->{$filename}{$key}, ' ';
-      }
-      print STATE "\n";
-    }
-
-    close(STATE) or
-      warn "$0: warning: cannot close `$state_file' for writing: $!\n";
-
-    rename("$state_file.tmp", $state_file) or
-      warn "$0: warning: cannot rename `$state_file.tmp' to `$state_file': $!\n";
-  }
-  else {
-    warn "$0: warning: cannot open state file `$state_file.tmp' for writing: $!\n";
-  }
-}
-
-my @cc_required_options;
-my @cc_required_files;
-my @cc_required_plots;
-my @cc_optional_options;
-my @cc_optional_files;
-my @cc_optional_plots;
-my @cc_default_colors;
-
-sub get_color {
-  $cc_default_colors[$_[0] % @cc_default_colors];
-}
-
-sub check_config {
-  my ($config_filename, $config_options, $config_files, $config_plots) = @_;
-
-  unless (@cc_required_options) {
-    @cc_required_options   = qw(html_dir
-                                rrd_dir
-                                state_file);
-    @cc_required_files     = qw(column_description
-                                date_source
-                                find_files
-                                interval);
-    @cc_required_plots     = qw(data
-                                source);
-    @cc_optional_options   = qw(expire_images
-                                html_page_footer
-                                html_page_header
-                                html_top_title
-                                late_interval
-                                sub_dir
-                                warn_email);
-    @cc_optional_files     = qw(reopen);
-    @cc_optional_plots     = qw(flush_regexps
-                                href
-                                plot_width
-                                plot_height);
-    # This is a special variable that gets used in add_plots.
-    @cc_default_colors   =     ('00ff00',	# Green
-                                '0000ff',	# Blue
-                                'ff0000',	# Red
-                                'a020f0',	# Magenta
-                                'ffa500',	# Orange
-                                'a52a2a',	# Brown
-                                '00ffff',	# Cyan
-                                '00aa00',	# Dark Green
-                                'eeee00',	# Yellow
-                                '5e5e5e',	# Dark Gray
-                                '0000aa');	# Dark Blue
-  }
-
-  # If rrd_dir is not set, then use base_dir.  Only die if both are
-  # not set.
-  unless (defined $config_options->{rrd_dir}) {
-    if (defined $config_options->{base_dir}) {
-      $config_options->{rrd_dir} = $config_options->{base_dir};
-    }
-    else {
-      die "$0: error: must define `rrd_dir' in `$config_filename'.\n";
-    }
-  }
-
-  # Check that we the required options are satisfied.
-  foreach my $option (@cc_required_options) {
-    unless (defined $config_options->{$option}) {
-      die "$0: error: must define `$option' in `$config_filename'.\n";
-    }
-  }
-
-  # Check if the html_dir and rrd_dir directories exist.
-  foreach my $dir_key ('html_dir', 'rrd_dir') {
-    my $dir = $config_options->{$dir_key};
-    die "$0: error: please create $dir_key `$dir'.\n" unless -d $dir;
-  }
-
-  # Set any optional options to '' if it isn't defined.
-  foreach my $option (@cc_optional_options) {
-    unless (defined $config_options->{$option}) {
-      $config_options->{$option} = '';
-    }
-  }
-
-  # Late_interval is a valid mathematical expression. Replace the word
-  # interval with $_[0].  Try the subroutine to make sure it works.
-  unless ($config_options->{late_interval}) {
-    $config_options->{late_interval} = 'interval';
-  }
-  my $expr = "sub { $config_options->{late_interval}; }";
-  $expr =~ s/interval/\$_[0]/g;
-  my $sub;
-  {
-    local $SIG{__DIE__}  = 'DEFAULT';
-    local $SIG{__WARN__} = \&::die_when_called;
-    $sub = eval $expr;
-  }
-  die "$0: cannot evaluate command for `late_interval' on\n   $expr\nOutput: $@\n" if $@;
-  {
-    local $SIG{__DIE__}  = 'DEFAULT';
-    local $SIG{__WARN__} = \&::die_when_called;
-    eval '&$sub(3.1415926) + 0;';
-  }
-  die "$0: cannot execute command for `late_interval' on\n$expr\nOutput: $@\n" if $@;
-  $config_options->{late_interval} = $sub;
-
-  # Convert the list of find_times into an array of fractional hours.
-  my @find_times;
-  unless (defined $config_options->{find_times}) {
-    $config_options->{find_times} = '';
-  }
-  foreach my $find_time (split(' ', $config_options->{find_times})) {
-    if (my ($hours, $minutes) = $find_time =~ /^(\d{1,2}):(\d{2})/) {
-      # Because of the regular expression match we're doing, the hours
-      # and minutes will only be positive, so check for hours > 23 and
-      # minutes > 59.
-      unless ($hours < 24) {
-        warn "$0: warning: ignoring find_times `$find_time': hours must be less than 24.\n";
-        next;
-      }
-      unless ($minutes < 60) {
-        warn "$0: warning: ignoring find_times `$find_time': minutes must be less than 60.\n";
-        next;
-      }
-      push(@find_times, $hours + $minutes/60.0);
-    }
-    else {
-      warn "$0: warning: ignoring find_times `$find_time': illegal format.\n";
-    }
-  }
-  $config_options->{find_times} = [ sort { $a <=> $b } @find_times ];
-
-  # There must be at least one group.
-  unless (keys %$config_files) {
-    die "$0: error: must define at least one `group' in `$config_filename'.\n";
-  }
-
-  # For each group there are required options.  Convert the
-  # unblessed reference to a hash to a Orca::Config::FilesGroup
-  # object.
-  foreach my $files_key (keys %$config_files) {
-    my $files_group = Orca::Config::FilesGroup->new($config_files->{$files_key});
-    $config_files->{$files_key} = $files_group;
-
-    foreach my $option (@cc_required_files) {
-      unless (defined $files_group->{$option}) {
-        die "$0: error: must define `$option' for `group $files_key' in `$config_filename'.\n";
-      }
-    }
-
-    # Optional group options will be set to '' here if they haven't
-    # been set by the user.
-    foreach my $option (@cc_optional_files) {
-      unless (defined $files_group->{$option}) {
-        $files_group->{$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.
-    my $date_source = $files_group->{date_source}[0];
-    if ($date_source eq 'column_name') {
-      unless (@{$files_group->{date_source}} == 2) {
-        die "$0: error: incorrect number of arguments for `date_source' for `group $files_key'.\n";
-      }
-      unless (defined $files_group->{date_format}) {
-        die "$0: error: must define `date_format' with `date_source columns ...' for `group $files_key'.\n";
-      }
-    }
-    else {
-      unless ($date_source eq 'file_mtime') {
-        die "$0: error: illegal argument for `date_source' for `group $files_key'.\n";
-      }
-    }
-    $files_group->{date_source}[0] = $date_source;
-
-    # 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.  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;
-    my $number_finds = @{$files_group->{'find_files'}};
-    for (my $i=0; $i<$number_finds; ++$i) {
-      my $orig_find = $files_group->{'find_files'}[$i];
-      my $find = $orig_find;
-      $find =~ s:^\\./::;
-      $find =~ s:/\\./:/:g;
-      $find = $orig_find unless $find;
-      $files_group->{'find_files'}[$i] = $find;
-      my $test_string      = 'abcdefg';
-      local $SIG{__DIE__}  = 'DEFAULT';
-      local $SIG{__WARN__} = \&::die_when_called;
-      eval { $test_string =~ /$find/ };
-      die "$0: error: illegal regular expression in `find_files $orig_find' for `group $files_key' in `$config_filename':\n$@\n" if $@;
-      $find_files{$find} = 1;
-      $sub_dir = 1 if $find =~ m:\(.+\):;
-    }
-    $files_group->{'find_files'} = [sort keys %find_files];
-    $files_group->{sub_dir}      = $sub_dir || $config_options->{sub_dir};
-  }
-
-  # There must be at least one plot.
-  unless (@$config_plots) {
-    die "$0: error: must define at least one `plot' in `$config_filename'.\n";
-  }
-
-  # Foreach plot there are required options.  Create default options
-  # if the user has not done so.
-  for (my $i=0; $i<@$config_plots; ++$i) {
-    my $plot = Orca::Config::Plot->new($config_plots->[$i]);
-    $config_plots->[$i] = $plot;
-
-    my $j = $i + 1;
-    foreach my $option (@cc_required_plots) {
-      unless (defined $plot->{$option}) {
-        die "$0: error: must define `$option' for `plot' #$j in `$config_filename'.\n";
-      }
-    }
-
-    # Create an array for each plot that will have a list of GIFs that
-    # were generated from this plot.
-    $plot->{creates} = [];
-
-    # Optional options will be set to '' here if they haven't been set
-    # by the user.
-    foreach my $option (@cc_optional_plots) {
-      unless (defined $plot->{$option}) {
-        $plot->{$option} = '';
-      }
-    }
-
-    # Set the default plot width and height.
-    $plot->{plot_width}  = 500 unless $plot->{plot_width};
-    $plot->{plot_height} = 125 unless $plot->{plot_height};
-
-    # Make sure the base is either 1000 or 1024.
-    if (defined $plot->{base} && length($plot->{base})) {
-      if ($plot->{base} != 1000 and $plot->{base} != 1024) {
-        die "$0: error: plot #$j must define base to be either 1000 or 1024.\n";
-      }
-    }
-    else {
-      $plot->{base} = 1000;
-    }
-
-    # Set the plot minimum and maximum values to U unless they are
-    # set.
-    unless (defined $plot->{data_min}) {
-      $plot->{data_min} = 'U';
-    }
-    unless (defined $plot->{data_max}) {
-      $plot->{data_max} = 'U';
-    }
-
-    # The data type must be either gauge, absolute, or counter.
-    if (defined $plot->{data_type}) {
-      my $type = substr($plot->{data_type}, 0, 1);
-      if ($type eq 'g' or $type eq 'G') {
-        $plot->{data_type} = 'GAUGE';
-      }
-      elsif ($type eq 'c' or $type eq 'C') {
-        $plot->{data_type} = 'COUNTER';
-      }
-      elsif ($type eq 'a' or $type eq 'A') {
-        $plot->{data_type} = 'ABSOLUTE';
-      }
-      elsif ($type eq 'd' or $type eq 'D') {
-        $plot->{data_type} = 'DERIVE';
-      }
-      else {
-        die "$0: error: `data_type $plot->{data_type}' for `plot' #$j in `$config_filename' must be gauge, counter, derive, or absolute.\n";
-      }
-    }
-    else {
-      $plot->{data_type} = 'GAUGE';
-    }
-
-    # The data source needs to be a valid group key.
-    my $source = $plot->{source};
-    unless (defined $config_files->{$source}) {
-      die "$0: error: plot #$j `source $source' references non-existant `group' in `$config_filename'.\n";
-    }
-    unless ($plot->{source}) {
-      die "$0: error: plot #$j `source $source' requires one group argument in `$config_filename'.\n";
-    }
-
-    # Set the legends of any columns not defined.
-    unless (defined $plot->{legend}) {
-      $plot->{legend} = [];
-    }
-    my $number_datas = @{$plot->{data}};
-    for (my $k=@{$plot->{legend}}; $k<$number_datas; ++$k) {
-      $plot->{legend}[$k] = "@{$plot->{data}[$k]}";
-    }
-
-    # Set the colors of any data not defined.
-    unless (defined $plot->{color}) {
-      $plot->{color} = [];
-    }
-    for (my $k=@{$plot->{color}}; $k<$number_datas; ++$k) {
-      $plot->{color}[$k] = get_color($k);
-    }
-
-    # Check each line type setting.
-    for (my $k=0; $k<$number_datas; ++$k) {
-      if (defined $plot->{line_type}[$k]) {
-      my $line_type = $plot->{line_type}[$k];
-        if ($line_type =~ /^line([123])$/i) {
-          $line_type = "LINE$1";
-        }
-        elsif ($line_type =~ /^area$/i) {
-          $line_type = 'AREA';
-        }
-        elsif ($line_type =~ /^stack$/i) {
-          $line_type = 'STACK';
-        }
-        else {
-          die "$0: error: plot #$j illegal `line_type' `$line_type'.\n";
-        }
-        $plot->{line_type}[$k] = $line_type;
-      }
-      else {
-        $plot->{line_type}[$k] = 'LINE1';
-      }
-    }
-
-    # If the generic y_legend is not set, then set it equal to the
-    # first legend.
-    unless (defined $plot->{y_legend}) {
-      $plot->{y_legend} = $plot->{legend}[0];
-    }
-
-    # If the title is not set, then set it equal to all of the legends
-    # with the group name prepended.
-    unless (defined $plot->{title}) {
-      my $title = '%G ';
-      for (my $k=0; $k<$number_datas; ++$k) {
-        $title .= $plot->{legend}[$k];
-        $title .= " & " if $k < $number_datas-1;
-      }
-      $plot->{title} = $title;
-    }
-  }
+  # Now that all the source data files have been loaded, empty the state
+  # object loaded from disk.
+  undef %$orca_old_state;
 
-  # Create the necessary GIF files in the HTML directory unless only
-  # RRD files should be updated.  This should include orga.gif and
-  # rrdtool.gif.  Convert the hexadecimal forms stored in the DATA
-  # section to the raw GIF form on disk.
-  return if $opt_rrd_update_only;
-  my $gif_filename = '';
-  while (<main::DATA>) {
-    chomp;
-    if ($gif_filename) {
-      if (/CLOSE/) {
-        close(ORCA_WRITE) or
-          warn "$0: error in closing `$gif_filename' for writing: $!\n";
-        $gif_filename = '';
-      }
-      else {
-        chomp;
-        print ORCA_WRITE pack('h*', $_);
-      }
-    }
-    elsif (/OPEN (.*)/) {
-      $gif_filename = "$config_options->{html_dir}/$1";
-      print "Creating $1.\n" if $opt_verbose;
-      unless (open(ORCA_WRITE, ">$gif_filename")) {
-        warn "$0: cannot open `$gif_filename' for writing: $!\n";
-        $gif_filename = '';
-      }
-    }
-  }
-  if ($gif_filename) {
-    close(ORCA_WRITE) or
-      warn "$0: error in closing `$gif_filename' for writing: $!\n";
-    $gif_filename = '';
-  }
+  return ($found_new_files,
+          \%new_found_files,
+          \%subgroup_fids);
 }
 
-# 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;
-
-# The following options go into the options and files hashes.  If you
-# add any elements to pcl_plot_append_elements, make sure up update
-# Orca::SourceFile::add_plots.
-my @pcl_option_elements;
-my @pcl_file_elements;
-my @pcl_plot_elements;
-my @pcl_plot_append_elements;
-my @pcl_filepath_elements;
-my @pcl_no_arg_elements;
-my @pcl_keep_as_array_options;
-my @pcl_keep_as_array_files;
-my @pcl_keep_as_array_plots;
-
-sub process_config_line {
-  my ($config_filename, $line_number, $line,
-      $config_options, $config_files, $config_plots) = @_;
-
-  unless (@pcl_option_elements) {
-    $pcl_files_key              = '';
-    $pcl_plot_index             = '-0';
-    @pcl_option_elements        = qw(base_dir
-                                     expire_images
-                                     find_times
-                                     html_dir
-                                     html_page_footer
-                                     html_page_header
-                                     html_top_title
-                                     late_interval
-                                     rrd_dir
-                                     state_file
-                                     sub_dir
-                                     warn_email);
-    @pcl_file_elements          = qw(column_description
-                                     date_format
-                                     date_source
-                                     find_files
-                                     interval
-                                     reopen);
-    @pcl_plot_elements          = qw(base
-                                     color
-                                     data
-                                     data_min
-                                     data_max
-                                     data_type
-                                     flush_regexps
-                                     href
-                                     legend
-                                     line_type
-                                     logarithmic
-                                     plot_height
-                                     plot_min
-                                     plot_max
-                                     plot_width
-                                     required
-                                     rigid_min_max
-                                     source
-                                     title
-                                     y_legend);
-    @pcl_plot_append_elements   = qw(color
-                                     data
-                                     legend
-                                     line_type);
-    @pcl_filepath_elements      = qw(find_files
-                                     html_dir
-                                     rrd_dir
-                                     state_file);
-    @pcl_no_arg_elements        = qw(flush_regexps
-                                     logarithmic
-                                     required
-                                     rigid_min_max);
-   @pcl_keep_as_array_options   = qw();
-   @pcl_keep_as_array_files     = qw(column_description
-                                     date_source
-                                     find_files);
-   @pcl_keep_as_array_plots     = qw(data);
-  }
-
-  # Take the line and split it and make the first element lowercase.
-  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.
-  if ($key ne '}') {
-    if (grep { $key eq $_} @pcl_no_arg_elements) {
-      push(@line, 1) unless @line;
-    }
-    else {
-      unless (@line) {
-        warn "$0: warning: option `$key' needs arguments in `$config_filename' line $line_number.\n";
-        return;
-      }
-    }
-  }
-
-  # 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 (grep {$key eq $_} @pcl_filepath_elements) {
-    foreach my $path (@line) {
-      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.
-  if ($pcl_files_key) {
-    if ($key eq '}') {
-      $pcl_files_key = '';
-      return;
-    }
-    unless (grep {$key eq $_} @pcl_file_elements) {
-      warn "$0: warning: directive `$key' unknown for group at line $line_number in `$config_filename'.\n";
-      return;
-    }
-
-    if (defined $config_files->{$pcl_files_key}{$key}) {
-      warn "$0: warning: `$key' for files already defined at line $line_number in `$config_filename'.\n";
-    }
-    if (grep {$key eq $_} @pcl_keep_as_array_files) {
-      $config_files->{$pcl_files_key}{$key} = [ @line ];
-    }
-    else {
-      $config_files->{$pcl_files_key}{$key} = $value;
-    }
-    return;
-  }
-
-  # Handle options for plot.
-  if ($pcl_plot_index !~ /^-/) {
-    if ($key eq '}') {
-      ++$pcl_plot_index;
-      $pcl_plot_index = "-$pcl_plot_index";
-      return;
-    }
-    unless (grep {$key eq $_} @pcl_plot_elements) {
-      warn "$0: warning: directive `$key' unknown for plot at line $line_number in `$config_filename'.\n";
-      return;
-    }
-
-    # Handle those elements that can just append.
-    if (grep { $key eq $_ } @pcl_plot_append_elements) {
-      unless (defined $config_plots->[$pcl_plot_index]{$key}) {
-        $config_plots->[$pcl_plot_index]{$key} = [];
-      }
-      if (grep {$key eq $_} @pcl_keep_as_array_plots) {
-        push(@{$config_plots->[$pcl_plot_index]{$key}}, [ @line ]);
-      }
-      else {
-        push(@{$config_plots->[$pcl_plot_index]{$key}}, $value);
-      }
-      return;
-    }
-
-    if (defined $config_plots->[$pcl_plot_index]{$key}) {
-      warn "$0: warning: `$key' for plot already defined at line $line_number in `$config_filename'.\n";
-      return;
-    }
-    if (grep {$key eq $_} @pcl_keep_as_array_plots) {
-      $config_plots->[$pcl_plot_index]{$key} = [ @line ];
-    }
-    else {
-      $config_plots->[$pcl_plot_index]{$key} = $value;
-    }
-    return;
-  }
-
-  # Take care of generic options.
-  if (grep {$key eq $_} @pcl_option_elements) {
-    if (grep {$key eq $_} @pcl_keep_as_array_options) {
-      $config_options->{$key} = [ @line ];
-    }
-    else {
-      $config_options->{$key} = $value;
-    }
-    return;
-  }
-
-  # Take care of files to watch.
-  if ($key eq 'group') {
-    unless (@line) {
-      die "$0: error: group needs a group name followed by { at line $line_number in `$config_filename'.\n"
-    }
-    $pcl_files_key = shift(@line);
-    unless (@line == 1 and $line[0] eq '{' ) {
-      warn "$0: warning: '{' required after `group $pcl_files_key' at line $line_number in `$config_filename'.\n";
-    }
-    if (defined $config_files->{$pcl_files_key}) {
-      warn "$0: warning: `group $key' at line $line_number in `$config_filename' previously defined.\n";
-    }
-    return;
-  }
-
-  # Take care of plots to make.  Include in each plot its index.
-  if ($key eq 'plot') {
-    $pcl_plot_index =~ s:^-::;
-    $config_plots->[$pcl_plot_index]{_index} = $pcl_plot_index;
-    unless (@line == 1 and $line[0] eq '{') {
-      warn "$0: warning: '{' required after `plot' at line $line_number in `$config_filename'.\n";
-    }
-    return;
+# Print a message on the statistics of this running process.
+sub running_stats {
+  my $ps_self = '@PS_SELF@';
+  if ($ps_self) {
+    $ps_self =~ s/PID/$$/g;
+    system($ps_self);
   }
+  if ($opt_verbose) {
+    my $time_span = time - $start_time;
+    my $minutes   = int($time_span/60);
+    my $seconds   = $time_span - 60*$minutes;
 
-  warn "$0: warning: unknown directive `$key' at line $line_number in `$config_filename'.\n";
-}
-
-sub load_config {
-  my $config_filename = shift;
-
-  open(CONFIG, $config_filename) or
-    die "$0: error: cannot open `$config_filename' for reading: $!\n";
-
-  # These values hold the information from the config file.
-  my %options;
-  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.
-  my $complete_line = '';
-  my $line_number = 1;
-  while (<CONFIG>) {
-    chomp;
-    # Skip lines that begin with #.
-    next if /^#/;
-
-    # If the line begins with whitespace, then append it to the
-    # previous line.
-    if (/^\s+/) {
-      $complete_line .= " $_";
-      next;
-    }
-
-    # Process the previously read line.
-    if ($complete_line) {
-      process_config_line($config_filename, $line_number, $complete_line,
-                          \%options, \%files, \@plots);
-    }
-
-    # Now save this read line.
-    $complete_line = $_;
-    $line_number = $.;
+    printf "Current running time is %d:%02d minutes.\n", $minutes, $seconds;
   }
-  process_config_line($config_filename, $line_number, $complete_line,
-                      \%options, \%files, \@plots) if $complete_line;
-
-  close(CONFIG) or
-    warn "$0: error in closing `$config_filename': $!\n";
-
-  (\%options, \%files, \@plots);
 }
 
 __END__
@@ -3622,8 +1103,8 @@
     based on when the file was last updated.
 
 Orca is similar to but substantially different from other tools that
-record and display hourly, daily, monthly, and yearly data, such as MRTG
-and Cricket.  To see these other tools, examine
+record and display hourly, daily, monthly, and yearly data, such as
+MRTG and Cricket.  To see these other tools, examine
 
   http://ee-staff.ethz.ch/~oetiker/webtools/mrtg/mrtg.html
 
@@ -3637,8 +1118,8 @@
 
   http://www.gps.caltech.edu/~blair/orca/orca-example/
 
-Please inform me of any other sites using Orca and I will include
-them here.
+Please inform me of any other sites using Orca and I will include them
+here.
 
 =head1 COMMAND LINE OPTIONS
 
@@ -3648,54 +1129,57 @@
 instead of PNGs.  You may not want to generate GIFs since PNGs are 1/3
 the size of GIFs and take less time to generate.
 
-B<-o>: Once.  This tells Orca to go through the steps of finding files,
-updating the RRDs, updating the PNGs, and creating the HTML files once.
-Normally, Orca loops continuously looking for new and updated files.
-
-B<-r>: RRD only.  Have Orca only update its RRD files.  Do not generate
-any HTML or PNG files.  This is useful if you are loading in a large
-amount of data in several invocations of Orca and do not want to create
-the HTML and PNG files in each run since it is time consuming.
+B<-o>: Once.  This tells Orca to go through the steps of finding
+files, updating the RRDs, updating the PNGs, and creating the HTML
+files once.  Normally, Orca loops continuously looking for new and
+updated files.
+
+B<-r>: RRD only.  Have Orca only update its RRD files.  Do not
+generate any HTML or PNG files.  This is useful if you are loading in
+a large amount of data in several invocations of Orca and do not want
+to create the HTML and PNG files in each run since it is time
+consuming.
 
 B<-v>: Verbose.  Have Orca spit out more verbose messages.  As you add
-more B<-v>'s to the command line, more messages are sent out.  Any more
-than three B<-v>'s are not used by Orca.
+more B<-v>'s to the command line, more messages are sent out.  Any
+more than three B<-v>'s are not used by Orca.
 
-After the command line options are listed, Orca takes one more argument
-which is the name of the configuration file to use.  Sample configuration
-files can be found in the sample_configs directory with the distribution
-of this tool.
+After the command line options are listed, Orca takes one more
+argument which is the name of the configuration file to use.  Sample
+configuration files can be found in the sample_configs directory with
+the distribution of this tool.
 
 =head1 RECOGNIZED SIGNALS
 
-Orca, when it received the HUP signal, will look for new source data files
-the next time it runs through the main loop.  If you have a constantly
-running Orca, this is a simpler and faster solution than restarting Orca,
-which takes time to reread all the source files.
+Orca, when it received the HUP signal, will look for new source data
+files the next time it runs through the main loop.  If you have a
+constantly running Orca, this is a simpler and faster solution than
+restarting Orca, which takes time to reread all the source files.
 
 =head1 ARCHITECTURE ISSUES
 
 Because Orca is extremely IO intensive, I recommend that the host that
 locally mounts the RRD data files be the same machine that runs Orca.
-In addition, the HTML and image files that Orca creates also require
-a good amount of IO.  The machine running Orca should always have
-the B<rrd_dir> directory locally mounted.  It is more important this
-B<rrd_dir> be locally stored than B<html_dir> for performance concerns.
-The two options B<html_dir> and B<rrd_dir> are described in more detail
-below.
+In addition, the HTML and image files that Orca creates also require a
+good amount of IO.  The machine running Orca should always have the
+B<rrd_dir> directory locally mounted.  It is more important this
+B<rrd_dir> be locally stored than B<html_dir> for performance
+concerns.  The two options B<html_dir> and B<rrd_dir> are described in
+more detail below.
 
 =head1 INSTALLATION AND CONFIGURATION
 
 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 last
-key's value.
+a line.  Lines that begin with whitespace are concatenated onto the
+last key's value.
 
-There are three main groups of options in a Orca confg: general options,
-file specific options, and plot specific options.  General options may
-be used by the file and plot specific options.  If an option is required,
-then it is only placed one time into the configuration file.
+There are three main groups of options in a Orca confg: general
+options, file specific options, and plot specific options.  General
+options may be used by the file and plot specific options.  If an
+option is required, then it is only placed one time into the
+configuration file.
 
 General options break down into two main groups, required and options.
 These are the required options:
@@ -3706,48 +1190,49 @@
 
 =item B<state_file> I<filename>
 
-For Orca to work efficiently, it saves the last modification time of all
-input data files and the Unix epoch time when they were last read by
-Orca into a state file.  The value for B<state_file> must be a valid,
-writable filename.  If I<filename> does not begin with a / and the
-B<base_dir> option was set, then the B<base_dir> directory will be
+For Orca to work efficiently, it saves the last modification time of
+all input data files and the Unix epoch time when they were last read
+by Orca into a state file.  The value for B<state_file> must be a
+valid, writable filename.  If I<filename> does not begin with a / and
+the B<base_dir> option was set, then the B<base_dir> directory will be
 prepended to the I<filename>.
 
-Each entry for a data input file is roughly 100 bytes, so for small sites,
-this file will not be large.
+Each entry for a data input file is roughly 100 bytes, so for small
+sites, this file will not be large.
 
 =item B<html_dir> I<directory>
 
-B<html_dir> specifies the root directory for the main index.html and all
-underlying HTML and PNG files that Orca generates.  This should not be a
-directory that normal users will edit.  Ideally this directory should be
-on a disk locally attached to the host running Orca, but is not necessary.
+B<html_dir> specifies the root directory for the main index.html and
+all underlying HTML and PNG files that Orca generates.  This should
+not be a directory that normal users will edit.  Ideally this
+directory should be on a disk locally attached to the host running
+Orca, but is not necessary.
 
 If I<directory> does not begin with a / and the B<base_dir> option was
 set, then the B<base_dir> directory will be prepended to I<directory>.
 
 =item B<rrd_dir> I<directory>
 
-B<rrd_dir> specifies the root directory for the location of the RRD data
-files that Orca generates.  For best performance, this directory should
-be on a disk locally attached to the host running Orca.  Otherwise,
-the many IO operations that Orca performs will be greatly slowed down.
-It is more important this B<rrd_dir> be locally stored than B<html_dir>
-for performance concerns.
+B<rrd_dir> specifies the root directory for the location of the RRD
+data files that Orca generates.  For best performance, this directory
+should be on a disk locally attached to the host running Orca.
+Otherwise, the many IO operations that Orca performs will be greatly
+slowed down.  It is more important this B<rrd_dir> be locally stored
+than B<html_dir> for performance concerns.
 
 If I<directory> does not begin with a / and the B<base_dir> option was
 set, then the B<base_dir> directory will be prepended to I<directory>.
 
-If B<rrd_dir> is not defined, then B<base_dir> will be used as B<rrd_dir>.
-Orca will quit with an error if both B<rrd_dir> and B<base_dir> are
-not set.
+If B<rrd_dir> is not defined, then B<base_dir> will be used as
+B<rrd_dir>.  Orca will quit with an error if both B<rrd_dir> and
+B<base_dir> are not set.
 
 =item B<base_dir> I<directory>
 
-If B<base_dir> is set, then it is used to prepend to any file or directory
-based names that do not begin with /.  These are currently B<state_file>,
-B<html_dir>, B<rrd_dir>, and the B<find_files> option in the B<group>
-options.
+If B<base_dir> is set, then it is used to prepend to any file or
+directory based names that do not begin with /.  These are currently
+B<state_file>, B<html_dir>, B<rrd_dir>, and the B<find_files> option
+in the B<group> options.
 
 =back
 
@@ -3757,14 +1242,15 @@
 
 =item B<late_interval> I<Perl expression>
 
-B<late_interval> is used to calculate the time interval between a file's
-last modification time and the time when that file is considered to
-be late for an update.  In this case, an email message may be sent
-out using the B<warn_email> addresses.  Because different input files
-may be updated at different rates, B<late_interval> takes an arbitrary
-Perl expression, including mathematical expressions, as its argument.
-If the word I<interval> occurs in the mathematical expression it is
-replaced with the sampling interval of the input data file in question.
+B<late_interval> is used to calculate the time interval between a
+file's last modification time and the time when that file is
+considered to be late for an update.  In this case, an email message
+may be sent out using the B<warn_email> addresses.  Because different
+input files may be updated at different rates, B<late_interval> takes
+an arbitrary Perl expression, including mathematical expressions, as
+its argument.  If the word I<interval> occurs in the mathematical
+expression it is replaced with the sampling interval of the input data
+file in question.
 
 This is useful for allowing the data files to update somewhat later
 than they would in an ideal world.  For example, to add a 10% overhead
@@ -3778,8 +1264,8 @@
 
 =item B<warn_email> I<email_address> [I<email_address> ...]
 
-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.
+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 following circumstances:
 
   1) When a file did exist and now is gone.
@@ -3791,8 +1277,8 @@
 
 If B<expire_images> is set then .meta files will be created for all
 generated PNG files.  If the Apache web server 1.3.2 or greater is
-being used, then the following modifications must added to srm.conf
-or httpd.conf.
+being used, then the following modifications must added to srm.conf or
+httpd.conf.
 
   < 
   < #MetaDir .web
@@ -3821,8 +1307,9 @@
 
 =item B<html_top_title> I<text> ...
 
-The I<text> is placed at the top of the main index.html that Orca creates.
-By default, no addition text is placed at the top of the main index.html.
+The I<text> is placed at the top of the main index.html that Orca
+creates.  By default, no addition text is placed at the top of the
+main index.html.
 
 =item B<html_page_header> I<text> ...
 
@@ -3831,14 +1318,15 @@
 
 =item B<html_page_footer> I<text> ...
 
-The I<text> is placed at the bottom of each HTML file that Orca creates.
-By default, no additional text is placed at the bottom of each HTML file.
+The I<text> is placed at the bottom of each HTML file that Orca
+creates.  By default, no additional text is placed at the bottom of
+each HTML file.
 
 =item B<sub_dir> I<directory>
 
-In certain cases Orca will not create sub directories for the different
-groups of files that it processes.  If you wish to force Orca to create
-sub directories, then do this
+In certain cases Orca will not create sub directories for the
+different groups of files that it processes.  If you wish to force
+Orca to create sub directories, then do this
 
   sub_dir 1
 
@@ -3846,10 +1334,10 @@
 
 =head2 Group Options
 
-The next step in configuring Orca is telling where to find the files to
-use as input, a description of the columns of data comprising the file,
-the interval at which the file is updated, and where the measurement
-time is stored in the file.  This is stored into a group.
+The next step in configuring Orca is telling where to find the files
+to use as input, a description of the columns of data comprising the
+file, the interval at which the file is updated, and where the
+measurement time is stored in the file.  This is stored into a group.
 
 A generic example of a group and its options are:
 
@@ -3869,11 +1357,11 @@
   }
 
 The key for a group, in this example GROUP_NAME1 and GROUP_NAME2, is a
-descriptive name that is unique for all files and is used later when the
-plots to create are defined.  Files that share the same general format
-of column data may be grouped together.  The options for a particular
-group must be enclosed in the curly brackets {}'s.  An unlimited number
-of groups may be listed.
+descriptive name that is unique for all files and is used later when
+the plots to create are defined.  Files that share the same general
+format of column data may be grouped together.  The options for a
+particular group must be enclosed in the curly brackets {}'s.  An
+unlimited number of groups may be listed.
 
 =head2 Required Group Options
 
@@ -3881,12 +1369,12 @@
 
 =item B<find_files> I<path|regexp> [I<path|regexp> ...]
 
-The B<find_files> option tells Orca what data files to use as its input.
-The arguments to B<find_files> may be a simple filename, a complete
-path to a filename, or a regular expression to find files.  The regular
-expression match is not the normal shell globbing that the Bourne shell, C
-shell or other shells use.  Rather, Orca uses the Perl regular expressions
-to find files.  For example:
+The B<find_files> option tells Orca what data files to use as its
+input.  The arguments to B<find_files> may be a simple filename, a
+complete path to a filename, or a regular expression to find files.
+The regular expression match is not the normal shell globing that the
+Bourne shell, C shell or other shells use.  Rather, Orca uses the Perl
+regular expressions to find files.  For example:
 
   find_files /data/source1 /data/source2
 
@@ -3898,14 +1386,15 @@
 and both data files will be used.
 
 In the two above examples, Orca will assume that both data files
-represent data from the same source.  If this is not the case, such
-as source1 is data from one place and source2 is data from another
-place, then Orca needs to be told to treat the data from each file as
-distinct data sources.  This be accomplished in two ways.  The first is
-by creating another group { ... } set.  However, this requires copying
-all of the text and makes maintenance of the configuration file complex.
-The second and recommend approach is to place ()'s around parts of the
-regular expression to tell Orca how to distinguish the two data files:
+represent data from the same source.  If this is not the case, such as
+source1 is data from one place and source2 is data from another place,
+then Orca needs to be told to treat the data from each file as
+distinct data sources.  This be accomplished in two ways.  The first
+is by creating another group { ... } set.  However, this requires
+copying all of the text and makes maintenance of the configuration
+file complex.  The second and recommend approach is to place ()'s
+around parts of the regular expression to tell Orca how to distinguish
+the two data files:
 
   find_files /data/(source\d)
 
@@ -3921,17 +1410,26 @@
   /data/solaris-2.5.1/sunridge/percol-1998-12-01.gz
   /data/solaris-2.5.1/sunridge/percol-1998-12-02
 
-and treat the files in the olympia and sunridge directories as distinct,
-but the files within each directory as from the same data source.
-
-If any of the paths or regular expressions given to B<find_files> do not
-begin with a / and the B<base_dir> option was set, then the B<base_dir>
-directory will be prepended to the path or regular expression.
+and treat the files in the olympia and sunridge directories as
+distinct, but the files within each directory as from the same data
+source.
+
+You'll notice that all but the first () has the form (?:...).  This
+tells Perl to match the expression but not save the matched text in
+the $1, $2, variables.  Orca uses the matched text to generate a
+subgroup name, which is used to place files into different subgroups.
+Here, only the hostname should be used to generate a subgroup name,
+hence all the (?:...) for matching anything else.
+
+If any of the paths or regular expressions given to B<find_files> do
+not begin with a / and the B<base_dir> option was set, then the
+B<base_dir> directory will be prepended to the path or regular
+expression.
 
 =item B<interval> I<seconds>
 
-The B<interval> options takes the number of seconds between updates for
-the input data files listed in this group.
+The B<interval> options takes the number of seconds between updates
+for the input data files listed in this group.
 
 =item B<column_description> I<column_name> [I<column_name> ...]
 
@@ -3950,11 +1448,12 @@
 
   column_description first_line
 
-This informs Orca that it should read the first line of all the input data
-files for the column description.  Orca can handle different files in the
-same group that have different number of columns and column descriptions.
-The only limitation here is that column descriptions are white space
-separated and therefore, no spaces are allowed in the column descriptions.
+This informs Orca that it should read the first line of all the input
+data files for the column description.  Orca can handle different
+files in the same group that have different number of columns and
+column descriptions.  The only limitation here is that column
+descriptions are white space separated and therefore, no spaces are
+allowed in the column descriptions.
 
 =item B<date_source> column_name I<column_name>
 
@@ -3963,26 +1462,71 @@
 The B<date_source> option tells Orca where time and date of the
 measurement is located.  The first form of the B<date_source> options
 lists the column name as given to B<column_description> that contains
-the Unix epoch time.  The second form with the file_mtime argument tells
-Orca that the date and time for any new data in the file is the last
-modification time of the file.
+the Unix epoch time.  The second form with the file_mtime argument
+tells Orca that the date and time for any new data in the file is the
+last modification time of the file.
 
 =item B<date_format> I<string>
 
 The B<date_format> option is only required if the column_name argument
-to B<date_source> is used.  Current, this argument is not used by Orca.
+to B<date_source> is used.  Current, this argument is not used by
+Orca.
 
 =back
 
-=head2 Optional Files Options
+=head2 Optional Group Options
 
 =over 4
 
+=item B<filename_compare> I<Perl subroutine>
+
+The B<filename_compare> option is used to sort the found filenames in
+a particular group.  This function must be written as though it were
+being passed to the Perl sort() function, which takes the two items to
+compare in the package global $a and $b variables instead of the @_
+array.
+
+Use of this option has an additional effect on letting Orca know when
+it can flush data to the RRD files.  It determines this when it
+compares the previously loaded filename to the filename about to be
+loaded using the B<filename_compare> function.  If the result of the
+comparison is greater than 1, then the data is flushed.  If the
+comparison is equal to or less than 1, then the data is not flushed.
+Orca uses a value of 1 instead of 0 since there are cases when the
+filenames should still be ordered but not flushed.
+
+For example, the orcallator.cfg file uses the following subroutine for
+filenames of the form "orcallator-2000-02-14":
+
+  sub {
+    my ($ay, $am, $ad) = $a =~ /-(\d{4})-(\d\d)-(\d\d)/;
+    my ($by, $bm, $bd) = $b =~ /-(\d{4})-(\d\d)-(\d\d)/;
+    if (my $c = (( $ay       <=>  $by) ||
+                 ( $am       <=>  $bm) ||
+                 (($ad >> 3) <=> ($bd >> 3)))) {
+      return 2*$c;
+    }
+    $ad <=> $bd;
+  }
+
+When Orca is about to load a new data file it compares the new
+filename with the previous name.  Using this function, if the year, or
+month is different, then data gets flushed.  If these two are equal
+but the day divided by 8 is different, then the data gets flushed.  So
+loading orcallator-2000-02-14 followed by orcallator-2000-02-15 will
+not cause a flush but when orcallator-2000-02-16 is about to be
+loaded, previously loaded data will be flushed.
+
+If the B<filename_compare> option is not used, then the filenames are
+sorted using the Perl <=> operator and data is not flushed until all
+of it is loaded.
+
 =item B<reopen> 1
 
-Using the B<reopen> option for a group instructs Orca to close and reopen
-any input data files when there is new data to be read.  This is of most
-use when an input data file is erased and rewritten by some other process.
+Using the B<reopen> option for a group instructs Orca to close and
+reopen any input data files when there is new data to be read.  This
+is of most use when an input data file is erased and rewritten by some
+other process.
 
 =back
 
@@ -4008,17 +1552,17 @@
 Unlike the group, there is no key for generating a plot.  An unlimited
 number of plots can be created.
 
-Some of the plot options if they have the two characters %g or %G
-will perform a substitution of this substring with the group name from
-the find_files ()'s matching.  %g gets replaced with the exact match
-from () and %G gets replaced with the first character capitalized.
-For example, if
+Some of the plot options if they have the two characters %g or %G will
+perform a substitution of this substring with the group name from the
+find_files ()'s matching.  %g gets replaced with the exact match from
+() and %G gets replaced with the first character capitalized.  For
+example, if
 
   find_files /(olympia)/data
 
-was used to locate a file, then %g will be replaced with olympia and %G
-replaced with Olympia.  This substitution is performed on the B<title>
-and B<legend> plot options.
+was used to locate a file, then %g will be replaced with olympia and
+%G replaced with Olympia.  This substitution is performed on the
+B<title> and B<legend> plot options.
 
 =head2 Required Plot Options
 
@@ -4034,18 +1578,19 @@
 
 =item B<data> I<regular expression>
 
-The B<data> plot option tells Orca the data sources to use to place
-in a single PNG plot.  At least one B<data> option is required for a
-particular plot and as many as needed may be placed into a single plot.
+The B<data> plot option tells Orca the data sources to use to place in
+a single PNG plot.  At least one B<data> option is required for a
+particular plot and as many as needed may be placed into a single
+plot.
 
 Two forms of arguments to B<data> are allowed.  The first form allows
 arbitrary Perl expressions, including mathematical expressions, that
-result in a number as a data source to plot.  The expression may contain
-the names of the columns as found in the group given to the B<source>
-option.  The column names must be separated with white space from any
-other characters in the expression.  For example, if you have number of
-bytes per second input and output and you want to plot the total number
-of bits per second, you could do this:
+result in a number as a data source to plot.  The expression may
+contain the names of the columns as found in the group given to the
+B<source> option.  The column names must be separated with white space
+from any other characters in the expression.  For example, if you have
+number of bytes per second input and output and you want to plot the
+total number of bits per second, you could do this:
 
   plot {
   source	bytes_per_second
@@ -4056,10 +1601,11 @@
 expression and plotting all of those columns that match the regular
 expression in a single plot.  To tell Orca that a regular expression
 is being used, then only a single non whitespace separated argument to
-B<data> is allowed.  In addition, the argument must contain at least one
-set of parentheses ()'s.  When a regular expression matches a column name,
-the portion of the match in the ()'s is placed into the normal Perl $1,
-$2, etc variables.  Take the following configuration for example:
+B<data> is allowed.  In addition, the argument must contain at least
+one set of parentheses ()'s.  When a regular expression matches a
+column name, the portion of the match in the ()'s is placed into the
+normal Perl $1, $2, etc variables.  Take the following configuration
+for example:
 
   group throughput {
   find_files /data/solaris.*/(.*)/percol-\d{4}-\d{2}-\d{2}
@@ -4104,15 +1650,17 @@
   /data/solaris-2.5.1/sunridge/percol-1998-12-01
   /data/solaris-2.5.1/sunridge/percol-1998-12-02
 
-then separate plots will be created for olympia and sunridge, with each
-plot containing the input and output number of packets per second.
-
-By default, when Orca finds a plot set with a regular expression match, it
-will only find one match, and then go on to the next plot set.  After it
-reaches the last plot set, it will go back to the first plot set with
-a regular expression match and look for the next data that matches the
-regular expression.  The net result of this is that the generated HTML
-files using the above configuration will have links in this order:
+then separate plots will be created for olympia and sunridge, with
+each plot containing the input and output number of packets per
+second.
+
+By default, when Orca finds a plot set with a regular expression
+match, it will only find one match, and then go on to the next plot
+set.  After it reaches the last plot set, it will go back to the first
+plot set with a regular expression match and look for the next data
+that matches the regular expression.  The net result of this is that
+the generated HTML files using the above configuration will have links
+in this order:
 
   hme0 Input & Output Packets per Second
   hme0 Input & Output Kilobytes per Second
@@ -4121,15 +1669,16 @@
   hme1 Input & Output Kilobytes per Second
   hme1 Input & Output Errors per Second
 
-If you wanted to have the links listed in order of hme0 and hme1,
-then you would add the B<flush_regexps> option to tell Orca to find all
+If you wanted to have the links listed in order of hme0 and hme1, then
+you would add the B<flush_regexps> option to tell Orca to find all
 regular expression matches for a particular plot set and all plot sets
-before the plot set containing B<flush_regexps> before continuing on to
-the next plot set.  For example, if
+before the plot set containing B<flush_regexps> before continuing on
+to the next plot set.  For example, if
 
   flush_regexps 1
 
-were added to the plot set for InKB/s and OuKB/s, then the order would be
+were added to the plot set for InKB/s and OuKB/s, then the order would
+be
 
   hme0 Input & Output Packets per Second
   hme0 Input & Output Kilobytes per Second
@@ -4155,26 +1704,50 @@
 
 The following options are plot optional.  Like the B<data> option,
 multiple copies of these may be specified.  The first option of a
-particular type sets the option for the first B<data> option, the second
-option refers to the second B<data> option, etc.
+particular type sets the option for the first B<data> option, the
+second option refers to the second B<data> option, etc.
 
 =over 4
 
 =item B<data_type> I<type>
 
-When defining data types, Orca uses the same data types as provided
-by RRD.  These are (a direct quote from the RRDcreate manual page):
+When defining data types, Orca uses the same data types as provided by
+RRD.  These are (a direct quote from the RRDcreate manual page):
 
-I<type> can be one of the following: B<GAUGE> this is for things like
-temperatures or number of people in a room. B<COUNTER> is for continuous
-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 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.
-B<ABSOLUTE> is for counters which get reset upon reading.
+=over 4
+
+=item B<GAUGE> 
+
+is for things like temperatures or number of people in a room or value
+of a RedHat share.
+
+=item B<COUNTER>
+
+is for continuous 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.  The counter is stored as a per-second
+rate. When the counter overflows, RRDtool checks if the overflow
+happened at the 32bit or 64bit border and acts accordingly by adding
+an appropriate value to the result.
+
+=item B<DERIVE>
+
+will store the the derivative of the line going from the last to the
+current value of the data source. This can be useful for gauges, for
+example, to measure the rate of people entering or leaving a
+room. Internally, derive works exactly like COUNTER but without
+overflow checks. So if your counter does not reset at 32 or 64 bit you
+might want to use DERIVE and combine it with a MIN value of 0.
+
+=item B<ABSOLUTE> 
+
+is for counters which get reset upon reading. This is used for fast
+counters which tend to overflow. So instead of reading them normally
+you reset them after every read to make sure you have a maximal time
+available before the next overflow.
+
+=back
 
 If the B<data_type> is not specified for a B<data> option, it defaults
 to GAUGE.
@@ -4188,9 +1761,9 @@
 defined, any value outside the defined range will be regarded as
 I<*UNKNOWN*>.
 
-If you want to specify the second data sources minimum and maximum but do
-not want to limit the first data source, then set the I<number>'s to U.
-For example:
+If you want to specify the second data sources minimum and maximum but
+do not want to limit the first data source, then set the I<number>'s
+to U.  For example:
 
   plot {
   data		column1
@@ -4203,15 +1776,17 @@
 
 =item B<color> I<rrggbb>
 
-The optional B<color> option specifies the color to use for a particular
-plot.  The color should be of the form I<rrggbb> in hexadecimal.
+The optional B<color> option specifies the color to use for a
+particular plot.  The color should be of the form I<rrggbb> in
+hexadecimal.
 
 =item B<flush_regexps> 1
 
-Using the B<flush_regexps> option tells Orca to make sure that the plot
-set including this option and all previous plot sets have matched all of
-the columns with their regular expressions.  See the above description
-of using regular expressions in the B<data> option for an example.
+Using the B<flush_regexps> option tells Orca to make sure that the
+plot set including this option and all previous plot sets have matched
+all of the columns with their regular expressions.  See the above
+description of using regular expressions in the B<data> option for an
+example.
 
 =item B<required> 1
 
@@ -4236,13 +1811,13 @@
 =item B<base> I<number>
 
 If memory is being plotted (and not network traffic) this value should
-be set to 1024 so that one Kb is 1024 bytes.  For traffic measurements,
-1 Kb/s is 1000 b/s.  By default, a base of 1000 is used.
+be set to 1024 so that one Kb is 1024 bytes.  For traffic
+measurements, 1 Kb/s is 1000 b/s.  By default, a base of 1000 is used.
 
 =item B<plot_width> I<number>
 
-Using the B<plot_width> option specifies how many pixels wide the drawing
-area inside the PNG is.
+Using the B<plot_width> option specifies how many pixels wide the
+drawing area inside the PNG is.
 
 =item B<plot_height> I<number>
 
@@ -4251,15 +1826,15 @@
 
 =item B<plot_min> I<number>
 
-By setting the B<plot_min> option, the minimum value to be graphed is set.
-By default this will be auto-configured from the data you select with
-the graphing functions.
+By setting the B<plot_min> option, the minimum value to be graphed is
+set.  By default this will be auto-configured from the data you select
+with the graphing functions.
 
 =item B<plot_max> I<number>
 
-By setting the B<plot_max> option, the minimum value to be graphed is set.
-By default this will be auto-configured from the data you select with
-the graphing functions.
+By setting the B<plot_max> option, the minimum value to be graphed is
+set.  By default this will be auto-configured from the data you select
+with the graphing functions.
 
 =item B<rigid_min_max>
 
@@ -4269,16 +1844,16 @@
 
 =item B<logarithmic>
 
-Normally Orca will use a linear scale for the Y axis.  If a plot contains
-this option, then a logarithmic scale will be used.
+Normally Orca will use a linear scale for the Y axis.  If a plot
+contains this option, then a logarithmic scale will be used.
 
 =item B<title> <text>
 
-Setting the B<title> option sets the title of the plot.  If you place %g
-or %G in the title, it is replaced with the text matched by any ()'s in
-the group B<find_files> option.  %g gets replaced with the exact text
-matched by the ()'s and %G is replaced with the same text, except the
-first character is capitalized.
+Setting the B<title> option sets the title of the plot.  If you place
+%g or %G in the title, it is replaced with the text matched by any
+()'s in the group B<find_files> option.  %g gets replaced with the
+exact text matched by the ()'s and %G is replaced with the same text,
+except the first character is capitalized.
 
 =item B<y_legend> <text>
 
@@ -4296,18 +1871,19 @@
 
 =item B<line_type> I<type>
 
-The B<line_type> option specifies the type of line to plot a particular
-data set with.  The available options are: LINE1, LINE2, and LINE3 which
-generate increasingly wide lines, AREA, which does the same as LINE? but
-fills the area between 0 and the graph with the specified color, and
-STACK, which does the same as LINE?, but the graph gets stacked on top
-of the previous LINE?, AREA, or STACK graph.  Depending on the type of
-previous graph, the STACK will either be a LINE? or an AREA.
+The B<line_type> option specifies the type of line to plot a
+particular data set with.  The available options are: LINE1, LINE2,
+and LINE3 which generate increasingly wide lines, AREA, which does the
+same as LINE? but fills the area between 0 and the graph with the
+specified color, and STACK, which does the same as LINE?, but the
+graph gets stacked on top of the previous LINE?, AREA, or STACK graph.
+Depending on the type of previous graph, the STACK will either be a
+LINE? or an AREA.
 
 =item B<legend> I<text>
 
-The B<legend> option specifies for a single data source the comment that
-is placed below the PNG plot.
+The B<legend> option specifies for a single data source the comment
+that is placed below the PNG plot.
 
 =back
 
@@ -4317,12 +1893,13 @@
 all of the different data it uses.
 
 The I<Digest::MD5> module is used to cache the result of some
-expensive calculations that commonly could be performed more than once.
-In particular, this arrises when the same code is used to pull data from
-many different input data files into the same type of data structures.
-In this case, the code to be evaluated is run through MD5, where the
-resulting binary code is used as a key in a hash with the value being the
-anonymous subroutine array.  This saves in memory and in processing time.
+expensive calculations that commonly could be performed more than
+once.  In particular, this arises when the same code is used to pull
+data from many different input data files into the same type of data
+structures.  In this case, the code to be evaluated is run through
+MD5, where the resulting binary code is used as a key in a hash with
+the value being the anonymous subroutine array.  This saves in memory
+and in processing time.
 
 =head1 MAILING LISTS
 
@@ -4340,19 +1917,20 @@
 The orca-announce at onelist.com mailing list is a LOW volume moderated
 mailing list for announcing stable releases of Orca.
 
-B<orca-help at onelist.com>
+B<orca-users at onelist.com>
 
-  Subscribe http://www.onelist.com/subscribe/orca-help
-  Archive   http://www.onelist.com/archive/orca-help
+  Subscribe http://www.onelist.com/subscribe/orca-users
+  Archive   http://www.onelist.com/archive/orca-users
 
-The orca-help at onelist.com is a first stop mailing list for getting help in
-setting up and getting Orca running.  Problems relating to downloading,
-configuring, compiling the necessary Perl modules, and installing
-Orca belong here.  People interested anything more than this, such as
-developing data gathering modules or active Perl development, should be on
-one or both of the orca-discuss at onelist.com or orca-developers at onelist.com
-mailing lists.  Once you get Orca running to your satisfaction, you may
-want to remove yourself from this list.
+The orca-users at onelist.com is a first stop mailing list for getting
+help in setting up and getting Orca running.  Problems relating to
+downloading, configuring, compiling the necessary Perl modules, and
+installing Orca belong here.  People interested anything more than
+this, such as developing data gathering modules or active Perl
+development, should be on one or both of the orca-discuss at onelist.com
+or orca-developers at onelist.com mailing lists.  Once you get Orca
+running to your satisfaction, you may want to remove yourself from
+this list.
 
 B<orca-discuss at onelist.com>
 
@@ -4360,26 +1938,26 @@
   Archive   http://www.onelist.com/archive/orca-discuss
 
 The orca-discuss at onelist.com mailing list is for active users of Orca
-who are doing new interesting things with Orca and want to discuss Orca
-but are not interested in actively developing Orca source code.  These
-people are also not interested in helping people get Orca running on their
-systems.
+who are doing new interesting things with Orca and want to discuss
+Orca but are not interested in actively developing Orca source code.
+These people are also not interested in helping people get Orca
+running on their systems.
 
 B<orca-developers at onelist.com>
 
   Subscribe http://www.onelist.com/subscribe/orca-developers
   Archive   http://www.onelist.com/archive/orca-developers
 
-The orca-developers at onelist.com mailing list is for hackers of Orca who
-actually hack and improve Orca.
+The orca-developers at onelist.com mailing list is for hackers of Orca
+who actually hack and improve Orca.
 
 =head1 AUTHOR, COMMENTS, AND BUGS
 
 Please direct all Orca comments and bugs to one of the above mailing
 lists.
 
-If you wish to contact the author or Orca, Blair Zajac, directly, please
-email me to blair at akamai.com.
+If you wish to contact the author or Orca, Blair Zajac, directly,
+please email me to blair at akamai.com.
 
 =cut
 

Modified: trunk/orca/docs/Makefile.in
==============================================================================
--- trunk/orca/docs/Makefile.in	(original)
+++ trunk/orca/docs/Makefile.in	Sat Jul 13 21:07:54 2002
@@ -2,20 +2,20 @@
 mandir	= @mandir@/man1
 MKDIR	= @MKDIR@
 INSTALL	= @INSTALL@
-ORCA	= ../src/orca.pl.in
+ORCA	= ../src/orca.pl
 
 TARGETS	= orca.man orca.html orca.txt
 
 all:	Makefile $(TARGETS)
 
 orca.man: $(ORCA)
-	pod2man $< > $@
+	pod2man $(ORCA) > $@
 
 orca.html: $(ORCA)
-	pod2html $< > $@
+	pod2html $(ORCA) > $@
 
 orca.txt: $(ORCA)
-	pod2text $< > $@
+	pod2text $(ORCA) > $@
 
 install: all
 	$(MKDIR) $(mandir)

Modified: trunk/orca/CHANGES
==============================================================================
--- trunk/orca/CHANGES	(original)
+++ trunk/orca/CHANGES	Sat Jul 13 21:07:54 2002
@@ -1,4 +1,135 @@
-Wed Oct 20 18:19:15 PDT 1999
+Thu Mar  9 12:23:24 PST 2000
+
+	Remove from the INSTALL file the instructions to increase the
+	file descriptor limit to 256.  This should no longer be
+	necessary with the improvements to the code.
+
+Thu Mar  9 12:20:39 PST 2000
+
+	Reduce the number of open files for the open file descriptor
+	cache from roughly 200 to 100.  Change the code so that if a
+	open of a file or pipe fails, then close two open file
+	descriptors and try again.  It used to be that an attempt
+	would be made if only a pipe failed.
+
+Wed Mar  8 12:02:07 PST 2000
+
+	Due to some changes at onelist.com, the name of this mailing
+	must change.  The -help at the end of orca-help is being
+	reserved for the mailing list named "orca".  As such, I'm
+	renaming this list to orca-users at onelist.com.  All references
+	to the old name in the package were similarly changed.
+
+Sun Mar  5 20:27:38 PST 2000
+
+	Include and require Storable 0.6.9.
+
+Wed Mar  1 14:40:26 PST 2000
+
+	Require the latest versions of all the modules Orca uses.
+
+Wed Mar  1 13:33:00 PST 2000
+
+	Only build RRDtool if it is needed.
+
+Tue Feb 29 17:43:15 PST 2000
+
+	To prevent Orca from performing all the gunzip, uncompress,
+	and bunzip2 system calls to get the first line of the source
+	file, store the first line in the state file and use it when
+	constructing the Orca::SourceFile object.
+
+Tue Feb 29 12:16:22 PST 2000
+
+	Update orcallator.cfg.in to plot the NFS server calls per
+	second and also the v{2,3}{reads,writes}.
+
+Tue Feb 29 12:02:45 PST 2000
+
+	Update the POD documentation for data_type by copying the
+	exact text from the rrdcreate.pod file.
+
+Sat Feb 26 13:29:16 PST 2000
+
+	If Orca::OpenFileHash::open tries to open a pipe for
+	compressed input and it cannot be opened, then shrink the
+	maximum number of open file descriptors and close enough
+	descriptors to attempt the pipe again.
+
+Fri Feb 25 17:15:37 PST 2000
+
+	Upgrade to orcallator.se 1.23.  When orcallator was running on
+	a system with DiskSuite, the same physical disk was listed
+	multiple times when it appeared in the same metadevice.  The
+	solution to the problem is not to build the c0t0d0 name but
+	use the long disk name provided by the long_name string.
+	Patch contributed by Paul Haldane
+	<Paul.Haldane at newcastle.ac.uk>.
+
+	To facilitate Orca loading in a huge amount of data in one
+	pass, add a new group configuration file parameter that tells
+	Orca how to sort the filenames and when data loaded from them
+	can be flushed to disk.  The new parameters name is
+	"filename_compare" and takes a Perl subroutine that behaves
+	like a subroutine given to sort.  Data is flushed to disk when
+	the subroutine returns a number greater than 1.
+
+Fri Feb 25 16:49:44 PST 2000
+
+	Save the state more often so that if Orca quits in the middle,
+	it does not have to reload all the data from the files again,
+	even if the data has already been loaded into the RRD files.
+
+Fri Feb 25 16:35:29 PST 2000
+
+	Have configure determine the best ps commmand to run to get
+	information on the current running Orca process.
+
+	Finish splitting up the monolithic orca.pl.in into separate
+	modules.
+
+Fri Feb 25 12:44:43 PST 2000
+
+	start_orcallator.sh refers to percollator.  Change it to refer
+	to orcallator.
+
+	If two different groups had the same subgroup, then Orca would
+	list both group's subgroup file IDs for both subgroups.  Fix
+	this bug.
+
+	Rename Orca::FileIDs to Orca::SourceFileIDs.
+
+Fri Feb 18 13:00:19 PST 2000
+
+	Apply a patch to Orca::ImageFile so that the legends are
+	properly created with the newer RRDtool.
+
+Fri Feb 18 12:19:14 PST 2000
+
+	Include and require RRDtool 1.0.13.
+
+Thu Feb 17 13:13:39 PST 2000
+
+	Include orcallator.se 1.22, which includes the following
+	changes: Include code to record NFS v2 and v3 server
+	statistics.  The new statistics are: nfss_calls, the number of
+	NFS calls to the NFS server, nfss_bad, the number of bad NFS
+	calls per second, and v{2,3}{reads,writes}, which are
+	nfss_calls broken down into NFS version 2 and NFS version 3
+	calls.  The sum of v{2,3}{reads, writes} will be less than
+	nfss_calls as the other types of NFS calls, such as getattr
+	and lookup, are not included.  Contributed by Paul Haldane
+	<Paul.Haldane at newcastle.ac.uk>.  This code is enabled by the
+	standard -DWATCH_OS or individually by -DWATCH_NFS_SERVER.
+	The define -DWATCH_NFS has been supperseded by
+	-DWATCH_NFS_CLIENT, but to keep backwards compatibility,
+	-DWATCH_NFS_CLIENT will be defined if -DWATCH_NFS is defined.
+
+        Include orcallator.se 1.21, which includes the following
+        changes: Prevent core dumps on extremely long access log
+        lines.
+
+Wed Oct 20 17:39:19 PDT 1999
 
 	Release Orca 0.25.
 
@@ -9,15 +140,15 @@
 
 	Include Storable 0.607 but continue to only require 0.603.
 
-	Add a mention in the POD that sending a HUP to the Orca process
-	forces it to look for new files in the next loop.  This is faster
-	than restarting Orca.
-
-	Change the behavior of warnings when data requested to be plotted
-	in the configuration file does not exist in the source data files.
-	Any resulting errors from this, such as cannot compile errors,
-	are only sent when the verbose level is above 1 or when the plot
-	is required.
+	Add a mention in the POD that sending a HUP to the Orca
+	process forces it to look for new files in the next loop.
+	This is faster than restarting Orca.
+
+	Change the behavior of warnings when data requested to be
+	plotted in the configuration file does not exist in the source
+	data files.  Any resulting errors from this, such as cannot
+	compile errors, are only sent when the verbose level is above
+	1 or when the plot is required.
 
 	Did some renaming of classes and variables in limited places:
 	Orca::SourceDataFile -> Orca::SourceFile
@@ -225,8 +356,16 @@
 
 	Include and require Math::Interpolate 1.04.
 
+	No longer have Orca::RRDFile be a subclass of Orca::DataFile, since
+	Orca::DataFile now handles FIDs and the FID namespace should not be
+	polluted by the RRD filenames.
+
 Mon Aug 16 12:11:48 PDT 1999
 
+	Design a new module, Orca::FileIDs, for managing the long lists
+	of long filenames for memory and CPU speed improvements.  Now all
+	classes use File IDentifiers (FIDs) instead of filenames.
+
 	Add locking on a particular configuration file.  Make a directory
 	using the configuration filename.
 
@@ -324,6 +463,8 @@
 	Switch to use PNGs instead of GIFs.  They take up 1/3 less space
 	than GIFs and at least 10% less time to generate.
 
+	Rename all variables and comments containing GIF to image.
+
 	Revamp the INSTALL document to reflect the new * -> _times_
 	change and add some documentation of the file descriptor limit.
 
@@ -401,6 +542,10 @@
 	only a few processes, this does not make sense, so a separate
 	plot is created.  Noted by Paul Company <paul.company at plpt.com>.
 
+Tue Jun  8 15:16:43 PDT 1999
+
+	Begin the break up orca.pl into separate files for each module.
+
 Tue Jun  8 10:57:39 PDT 1999
 
 	Make the table of contents in INSTALL consistent with the contents

Modified: trunk/orca/NEWS
==============================================================================
--- trunk/orca/NEWS	(original)
+++ trunk/orca/NEWS	Sat Jul 13 21:07:54 2002
@@ -1,82 +1,193 @@
-New in Orca version 0.25.
+NEW IN ORCA 0.26
+================
+
+ 1) Due to some changes at onelist.com, the name of this mailing must
+    change.  The -help at the end of orca-help is being reserved for
+    the mailing list named "orca".  As such, I'm renaming this list to
+    orca-users at onelist.com.
+
+ 2) Major speedup in starting Orca when many different source files
+    exist and the first line of the file is used to tell Orca what
+    columns of data there are.  Now Orca caches this information in
+    the state file so that the source data files do no have to be
+    opened everytime Orca starts up.  This has a significant speed
+    improvement when the file is compressed, since a separate process
+    is normally spawned to read the file.
+
+ 3) Reduce the number of size of the open file descriptor cache to 100
+    open file descriptors since the change in 2) reduces the need for
+    as many open file descriptors.
+
+ 4) A new configuration file parameter named filename_compare was
+    added that let's Orca determine when it can flush data from loaded
+    source files.  This prevents Orca from loading in all of the data
+    and then flushing it to the disk when the amount of new data is
+    large.  See the Orca documentation for more information.
+
+ 5) Allow Orca to work with RRDtool versions newer than 1.0.7.
+
+ 6) Save Orca's state more often so that if something happens to the
+    Orca process, it does not have to reload all the data from the
+    source data files it previously read.
+
+ 7) Have Orca print the current memory usage and CPU time more often.
+    This attempts to use the proper ps command for the operating
+    system Orca was configured on.
+
+ 8) Take all of the modules in the monolithic orca script and move
+    them into their own files.  This improves readability and
+    maintainability.
+
+ 9) Require the latest versions of Data::Dumper (2.101), Digest::MD5
+    (2.09), Math::IntervalSearch (1.05), RRDs (1.0.13), and Storable
+    (0.6.9).
+
+10) Use arrays instead of hashes as the internal structure for many
+    objects.  This should speed access to object members and make
+    their memory footprint smaller.
+
+11) Use a new integer file identifier (FID) instead of the filename to
+    refer to in internal objects.  There is now a global array keyed
+    by the FID that gives the name and a hash keyed by filename that
+    returns the FID.  The FID is used where the filename previously
+    was used.  This reduces Orca's memory usage by 10%, since only one
+    copy of a long filename is needed.
+
+    These following changes are what's new in orcallator.se 1.23 and
+    the orcallator.cfg file since version 1.20 which was included with
+    Orca 0.25.  All of the changes below are taken advantage of in the
+    included orcallator.cfg and start_orcallator files.
+
+12) Include code to record and plot the NFS v2 and v3 server
+    statistics.  The new statistics are: nfss_calls, the number of NFS
+    calls to the NFS server, nfss_bad, the number of bad NFS calls per
+    second, and v{2,3}{reads,writes}, which are nfss_calls broken down
+    into NFS version 2 and NFS version 3 calls.  The sum of
+    v{2,3}{reads,writes} will be less than nfss_calls as the other
+    types of NFS calls, such as getattr and lookup, are not included.
+    Contributed by Paul Haldane <Paul.Haldane at newcastle.ac.uk>.  This
+    code is enabled by the standard -DWATCH_OS or individually by
+    -DWATCH_NFS_SERVER.  The define -DWATCH_NFS has been supperseded
+    by -DWATCH_NFS_CLIENT, but to keep backwards compatibility,
+    -DWATCH_NFS_CLIENT will be defined if -DWATCH_NFS is defined.
+
+13) When orcallator was running on a system with DiskSuite, the same
+    physical disk was listed multiple times when it appeared in the
+    same metadevice.  The solution to the problem is not to build the
+    c0t0d0 name but use the long disk name provided by the long_name
+    string. Patch contributed by Paul Haldane
+    <Paul.Haldane at newcastle.ac.uk>.
+
+14) Prevent core dumps on extremely long access log lines.
+
+NEW IN ORCA 0.25
+================
+
  1) I have moved companies from Yahoo!/GeoCities to Akamai.  My email
-    address has changed to blair at akamai.com and the old one will
-    no longer work.  Also, I have moved the my entire Orca archive
-    from www.geocities.com/~bzking/ to www.gps.caltech.edu/~blair/orca/
- 2) Fix an important bug where Orca would crash if column names mentioned
-    in the configuration file did not exist in the source data files.
+    address has changed to blair at akamai.com and the old one will no
+    longer work.  Also, I have moved the entire archive from
+    www.geocities.com/~bzking/ to www.gps.caltech.edu/~blair/orca/
+
+ 2) Fix an important bug where Orca would crash if column names
+    mentioned in the configuration file did not exist in the source
+    data files.
+
  3) Orca, when it received the HUP signal, will look for new source
-    data files the next time it runs through the main loop.  If you have
-    a constantly running Orca, this is a simpler and faster solution
-    than restarting Orca, which takes time to reread all the source files.
- 4) Add a new make target orcallator_run_at_boot which will install the
-    proper files into the proper /etc/*.d/ directories to start orcallator
-    at boot time and shut it down at halt time.
+    data files the next time it runs through the main loop.  If you
+    have a constantly running Orca, this is a simpler and faster
+    solution than restarting Orca, which takes time to reread all the
+    source files.
+
+ 4) Add a new make target orcallator_run_at_boot which will install
+    the proper files into the proper /etc/*.d/ directories to start
+    orcallator at boot time and shut it down at halt time.
+
  5) The previous default orcallator.cfg would not find compressed
     orcallator files.
+
  6) Remove the plot configuration option `optional' which made plots
     optional.  Now make plots optional by default and use the keyword
     `required' to make them required.  If a plot is required, then it
     will always display, even if there is no data loaded for it.
+
  7) Change the behavior of warnings when data requested to be plotted
     in the configuration file does not exist in the source data files.
-    Any resulting errors from this, such as cannot compile errors,
-    are only sent when the verbose level is above 1 or when the plot
-    is required.
- 8) Include Storable 0.6.7 but continue to only require Storable 0.6.3.
+    Any resulting errors from this, such as cannot compile errors, are
+    only sent when the verbose level is above 1 or when the plot is
+    required.
+
+ 8) Include Storable 0.6.7 but continue to only require Storable
+    0.6.3.
+
+NEW IN ORCA 0.24
+================
 
-New in Orca version 0.24.
  1) Installation notes.  Due to the way Orca generated image and HTML
     files are named, read the INSTALL file.  Otherwise, you will have
     some left over cruft that will waste disk space and you will have
     to reload all of your source data files.
+
  2) Orca now runs under older Perls: Perl 5.004_01 or later.
- 3) Switch to generate PNGs instead of GIFs.  They take up 1/3 less disk
-    space and are created at least 10% faster.  If you want Orca to
-    generate GIFs instead of PNGs, give it the -gifs flag.
- 4) Read in .gz files using gunzip, .Z files using uncompress, and .bz2
-    files with bunzip2.
+
+ 3) Switch to generate PNGs instead of GIFs.  They take up 1/3 less
+    disk space and are created at least 10% faster.  If you want Orca
+    to generate GIFs instead of PNGs, give it the -gifs flag.
+
+ 4) Read in .gz files using gunzip, .Z files using uncompress, and
+    .bz2 files with bunzip2.
+
  5) Add to the plot title the type of the plot (i.e. 'Yearly') in
     every image.
- 6) Add a href field for a plot.  This, if defined, appends a HREF to a
-    target name letting you point the user to a page to get more
+
+ 6) Add a href field for a plot.  This, if defined, appends a HREF to
+    a target name letting you point the user to a page to get more
     information.  The default orcallator.cfg has these added to point
     to the new documentation web page
-    http://www.geocities.com/~bzking/docs/orcallator.html for all
-    orcallator.se recorded data.
- 7) Add a new option named base that lets the user specify either a base
-    of 1000 or 1024 for autoscaling plots.  This is useful for memory
-    (base 1024) vs network (base 1000) measurements and is used in
-    generating correctly calculating the base to use in calculating
+    http://www.geocities.com/~bzking/docs/orcallator.html
+    for all orcallator.se recorded data.
+
+ 7) Add a new option named base that lets the user specify either a
+    base of 1000 or 1024 for autoscaling plots.  This is useful for
+    memory (base 1024) vs network (base 1000) measurements and is used
+    in generating correctly calculating the base to use in calculating
     the Y axis.
+
  8) The word logarithmic can now be used for a plot to create a
     logarithmic Y axis scale.
- 9) Orca no longer lists all the source files it finds to shorten verbose
-    output.  This output is now generated if the verbose level is greater
-    than one.
-10) Do not overwrite existing HTML files when creating new versions until
-    the new version is finished.  This allows people to better view
-    existing pages until the new page is completely finished.
-11) All generated HTML and image filenames are now created using
-    a different set of mappings.  Now
+
+ 9) Orca no longer lists all the source files it finds to shorten
+    verbose output.  This output is now generated if the verbose level
+    is greater than one.
+
+10) Do not overwrite existing HTML files when creating new versions
+    until the new version is finished.  This allows people to better
+    view existing pages until the new page is completely finished.
+
+11) All generated HTML and image filenames are now created using a
+   different set of mappings.  Now
       orcallator -> o
       orca       -> o
       _times_    -> _X_
       _percent_  -> _pct_
       _number_   -> _num_.
+
     All older installations of Orca will need to be renamed unless you
-    want to load in all your data again.  You can perform this renaming
-    on your files by running make upgrade, or if you have directories
-    that are not normally covered by the Orca install, run
-    src/upgrade_installation followed by the list of directories to search
-    in.  Pass the -n flag to upgrade_installation if you want to see
-    the renames that will be performed without actually performing them.
+    want to load in all your data again.  You can perform this
+    renaming on your files by running make upgrade, or if you have
+    directories that are not normally covered by the Orca install, run
+    src/upgrade_installation followed by the list of directories to
+    search in.  Pass the -n flag to upgrade_installation if you want
+    to see the renames that will be performed without actually
+    performing them.
+
 12) New HTML and image filenames are shorter, which can save 10% in
     disk space on a large installation according to du -k.  Also, now
-    plots containing arbitrary many data sources can be plotted without
-    exceeding the maximum file lengths.
-13) Add locking so that only one Orca can run on a single configuration
-    file at one time.
+    plots containing arbitrary many data sources can be plotted
+    without exceeding the maximum file lengths.
+
+13) Add locking so that only one Orca can run on a single
+    configuration file at one time.
+
 14) Include and require RRDtool 1.0.7.2 and Math::Interpolate 1.05.
     Include Data::Dumper 2.101, Digest::MD5 2.09, Storable 0.6.5, with
     Orca.
@@ -86,23 +197,27 @@
     below are taken advantage of in the included orcallator.cfg and
     start_orcallator files.
 
-15) Orcallator.se now has a web page describing the various measurements
-    it makes.  See http://www.geocities.com/~bzking/docs/orcallator.html.
-16) If the environmental variable WEB_SERVER is defined, use its value of
-    the as the name of the process to count for the number of web
+15) Orcallator.se now has a web page describing the various
+    measurements it makes.  See
+    http://www.geocities.com/~bzking/docs/orcallator.html.
+
+16) If the environmental variable WEB_SERVER is defined, use its value
+    of the as the name of the process to count for the number of web
     servers on the system.  If WEB_SERVER is not defined, then count
     number of httpd's.
-17) If the COMPRESSOR environmental variable is defined, then when a new
-    log file is opened for a new day, the just closed log file is
+
+17) If the COMPRESSOR environmental variable is defined, then when a
+    new log file is opened for a new day, the just closed log file is
     compressed using the COMPRESSOR command in the following manner:
-    system(sprintf("%s %s &", COMPRESSOR, log_file)
-    COMPRESSOR should be set to something like "gzip -9", or "compress",
-    or "bzip2 -9".  If the configure script finds both a compressor and
-    uncompressor tool, such as both gzip and gunzip, then start_orcallator
-    will inform orcallator.se to compress the log files at the end of a
+    system(sprintf("%s %s &", COMPRESSOR, log_file) COMPRESSOR should
+    be set to something like "gzip -9", or "compress", or "bzip2 -9".
+    If the configure script finds both a compressor and uncompressor
+    tool, such as both gzip and gunzip, then start_orcallator will
+    inform orcallator.se to compress the log files at the end of a
     day.
-18) New measurements.  The first column lists the define that must
-    be passed to the SE interpreter to obtain the measurement.  If you
+
+18) New measurements.  The first column lists the define that must be
+    passed to the SE interpreter to obtain the measurement.  If you
     use the WATCH_OS define, then all of these are now measured.
     WATCH_MUTEX  - ncpus - number of CPUs on the system
     WATCH_CPU    - #proc/s - 5 minute average process spawn rate if root
@@ -122,89 +237,124 @@
     WATCH_MOUNTS - mnta_* - available inodes for non-root users
     WATCH_MOUNTS - mntP_* - percentage of kilobytes used for non-root users
     WATCH_MOUNTS - mntp_* - percentage of inodes used for non-root users
+
 19) Add some smarts so that if the number of interfaces, physical
-    disks, or mounted partitions changes, then a new header is printed.
-    This will prevent column name and data mixups when the system
-    configuration changes.
-20) Prevent a division by zero in calculating the mean_disk_busy if the
-    number of disks on the system is 0.
-21) Fix a bug in the disk_mean calculation where it was being divided
-    by the wrong disk_count.  Now it should be much larger and in scale
-    with disk_peak.
-22) Increase the number of characters for each network interface from four
-    to five.
+    disks, or mounted partitions changes, then a new header is
+    printed.  This will prevent column name and data mixups when the
+    system configuration changes.
+
+20) Prevent a division by zero in calculating the mean_disk_busy if
+    the number of disks on the system is 0.  21) Fix a bug in the
+    disk_mean calculation where it was being divided by the wrong
+    disk_count.  Now it should be much larger and in scale with
+    disk_peak.
+
+22) Increase the number of characters for each network interface from
+    four to five.
+
 23) If WATCH_YAHOO is defined, then process the access log as a Yahoo!
     style access log.
-24) Restructure the code to handle different web server access log formats
-    easier.
 
-New in Orca version 0.23.
+24) Restructure the code to handle different web server access log
+    formats easier.
+
+NEW IN ORCA 0.23
+================
+
  1) Fix two important bugs in orcallator_running and start_orcallator
     which where using old PERCOLLATOR_DIR variables instead of the new
     ORCALLATOR_DIR.
 
-New in Orca version 0.22.
+NEW IN ORCA 0.22
+================
+
  1) Add a new command line option (-r) that tells Orca to only update
     the RRD data files and not to generate any HTML or GIF files.
-    This is useful if you are loading in a large amount of data in several
-    invocations of Orca and do not want to create the HTML and GIF files
-    in each run since it is time consuming.
- 2) Fix a bug where if the number of columns changed in from one source
-    file to the next source file in a files group, the column index used
-    to get a particular value is the index for the old file and not the
-    index for the new file.  This required some internal restructuring
-    the speeds Orca up slightly.
- 3) Add a new plot called quarterly that displays the last 100 days
-    of data.  This is a nice transition between the monthly and yearly
+    This is useful if you are loading in a large amount of data in
+    several invocations of Orca and do not want to create the HTML and
+    GIF files in each run since it is time consuming.
+
+ 2) Fix a bug where if the number of columns changed in from one
+    source file to the next source file in a files group, the column
+    index used to get a particular value is the index for the old file
+    and not the index for the new file.  This required some internal
+    restructuring the speeds Orca up slightly.
+
+ 3) Add a new plot called quarterly that displays the last 100 days of
+    data.  This is a nice transition between the monthly and yearly
     plots.
+
  4) A temporary fix: Skip and do not complain about input source data
     file lines containing the word timestamp in it.
+
  5) Removed some unused methods to make Orca smaller.
+
  6) Added some more documentation to orcallator.cfg.
+
  7) Make Orca slightly faster.
  
-New in Orca version 0.21.
+NEW IN ORCA 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.
+    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.
+    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.
+    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.
+
+ 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
+    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 21:07:54 2002
@@ -94,9 +94,9 @@
     This is a LOW volume moderated mailing list for announcing stable
     releases of Orca.
 
-orca-help at onelist.com
-    Subscribe    http://www.onelist.com/subscribe/orca-help
-    Archive      http://www.onelist.com/archive/orca-help
+orca-users at onelist.com
+    Subscribe    http://www.onelist.com/subscribe/orca-users
+    Archive      http://www.onelist.com/archive/orca-users
 
     This mailing list is a first stop mailing list for getting help
     in setting up and getting Orca running.  Problems relating to

Modified: trunk/orca/packages/Makefile.in
==============================================================================
--- trunk/orca/packages/Makefile.in	(original)
+++ trunk/orca/packages/Makefile.in	Sat Jul 13 21:07:54 2002
@@ -171,6 +171,7 @@
 	fi
 
 distclean: $(DISTCLEAN_TARGETS)
+	$(RM) Makefile
 
 distclean_compress_zlib:	clean_compress_zlib
 

Modified: trunk/orca/packages/Storable-0.6.9/t/dclone.t
==============================================================================
--- trunk/orca/packages/Storable-0.6.9/t/dclone.t	(original)
+++ trunk/orca/packages/Storable-0.6.9/t/dclone.t	Sat Jul 13 21:07:54 2002
@@ -1,6 +1,6 @@
 #!./perl
 
-# $Id: dclone.t,v 0.6 1998/06/04 16:08:25 ram Exp $
+# $Id: dclone.t,v 0.6.1.1 2000/03/02 22:21:05 ram Exp $
 #
 #  Copyright (c) 1995-1998, Raphael Manfredi
 #  
@@ -8,7 +8,10 @@
 #  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
+# Revision 0.6.1.1  2000/03/02 22:21:05  ram
+# patch9: added test case for "undef" bug in hashes
+#
+# Revision 0.6  1998/06/04  16:08:25  ram
 # Baseline for first beta release.
 #
 
@@ -16,7 +19,7 @@
 
 use Storable qw(dclone);
 
-print "1..6\n";
+print "1..9\n";
 
 $a = 'toto';
 $b = \$a;
@@ -55,3 +58,17 @@
 print "not " unless &dump($foo) eq &dump($r);
 print "ok 6\n";
 
+# Ensure refs to "undef" values are properly shared during cloning
+my $hash;
+push @{$$hash{''}}, \$$hash{a};
+print "not " unless $$hash{''}[0] == \$$hash{a};
+print "ok 7\n";
+
+my $cloned = dclone(dclone($hash));
+print "not " unless $$cloned{''}[0] == \$$cloned{a};
+print "ok 8\n";
+
+$$cloned{a} = "blah";
+print "not " unless $$cloned{''}[0] == \$$cloned{a};
+print "ok 9\n";
+

Modified: trunk/orca/packages/Storable-0.6.9/t/retrieve.t
==============================================================================
--- trunk/orca/packages/Storable-0.6.9/t/retrieve.t	(original)
+++ trunk/orca/packages/Storable-0.6.9/t/retrieve.t	Sat Jul 13 21:07:54 2002
@@ -1,6 +1,6 @@
 #!./perl
 
-# $Id: retrieve.t,v 0.6 1998/06/04 16:08:33 ram Exp $
+# $Id: retrieve.t,v 0.6.1.1 2000/02/10 18:47:49 ram Exp $
 #
 #  Copyright (c) 1995-1998, Raphael Manfredi
 #  
@@ -8,7 +8,10 @@
 #  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
+# Revision 0.6.1.1  2000/02/10 18:47:49  ram
+# patch8: added tests for the new last_op_in_netorder() predicate
+#
+# Revision 0.6  1998/06/04  16:08:33  ram
 # Baseline for first beta release.
 #
 
@@ -16,7 +19,7 @@
 
 use Storable qw(store retrieve nstore);
 
-print "1..9\n";
+print "1..14\n";
 
 $a = 'toto';
 $b = \$a;
@@ -28,30 +31,40 @@
 
 print "not " unless defined store(\@a, 't/store');
 print "ok 1\n";
-print "not " unless defined nstore(\@a, 't/nstore');
+print "not " if Storable::last_op_in_netorder();
 print "ok 2\n";
+print "not " unless defined nstore(\@a, 't/nstore');
+print "ok 3\n";
+print "not " unless Storable::last_op_in_netorder();
+print "ok 4\n";
+print "not " unless Storable::last_op_in_netorder();
+print "ok 5\n";
 
 $root = retrieve('t/store');
 print "not " unless defined $root;
-print "ok 3\n";
+print "ok 6\n";
+print "not " if Storable::last_op_in_netorder();
+print "ok 7\n";
 
 $nroot = retrieve('t/nstore');
 print "not " unless defined $nroot;
-print "ok 4\n";
+print "ok 8\n";
+print "not " unless Storable::last_op_in_netorder();
+print "ok 9\n";
 
 $d1 = &dump($root);
-print "ok 5\n";
+print "ok 10\n";
 $d2 = &dump($nroot);
-print "ok 6\n";
+print "ok 11\n";
 
 print "not " unless $d1 eq $d2; 
-print "ok 7\n";
+print "ok 12\n";
 
 # Make sure empty string is defined at retrieval time
 print "not " unless defined $root->[1];
-print "ok 8\n";
+print "ok 13\n";
 print "not " if length $root->[1];
-print "ok 9\n";
+print "ok 14\n";
 
 unlink 't/store', 't/nstore';
 

Modified: trunk/orca/packages/Storable-0.6.9/t/canonical.t
==============================================================================
--- trunk/orca/packages/Storable-0.6.9/t/canonical.t	(original)
+++ trunk/orca/packages/Storable-0.6.9/t/canonical.t	Sat Jul 13 21:07:54 2002
@@ -1,6 +1,6 @@
 #!./perl
 
-# $Id: canonical.t,v 0.6 1998/06/04 16:08:24 ram Exp $
+# $Id: canonical.t,v 0.6.1.1 2000/03/02 22:20:53 ram Exp $
 #
 #  Copyright (c) 1995-1998, Raphael Manfredi
 #  
@@ -8,7 +8,10 @@
 #  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
+# Revision 0.6.1.1  2000/03/02 22:20:53  ram
+# patch9: added test case for "undef" bug in hashes
+#
+# Revision 0.6  1998/06/04  16:08:24  ram
 # Baseline for first beta release.
 #
 
@@ -17,7 +20,7 @@
 use Storable qw(freeze thaw dclone);
 use vars qw($debugging $verbose);
 
-print "1..5\n";
+print "1..8\n";
 
 sub ok {
     my($testno, $ok) = @_;
@@ -126,3 +129,18 @@
 # may report a false negative.
 
 ok 5, ($x1 ne $x2) || ($x1 ne $x3);    
+
+
+# Ensure refs to "undef" values are properly shared
+# Same test as in t/dclone.t to ensure the "canonical" code is also correct
+
+my $hash;
+push @{$$hash{''}}, \$$hash{a};
+ok 6, $$hash{''}[0] == \$$hash{a};
+
+my $cloned = dclone(dclone($hash));
+ok 7, $$cloned{''}[0] == \$$cloned{a};
+
+$$cloned{a} = "blah";
+ok 8, $$cloned{''}[0] == \$$cloned{a};
+

Modified: trunk/orca/packages/Storable-0.6.9/Storable.xs
==============================================================================
--- trunk/orca/packages/Storable-0.6.9/Storable.xs	(original)
+++ trunk/orca/packages/Storable-0.6.9/Storable.xs	Sat Jul 13 21:07:55 2002
@@ -3,7 +3,7 @@
  */
 
 /*
- * $Id: Storable.xs,v 0.6.1.6 1999/10/19 19:23:34 ram Exp $
+ * $Id: Storable.xs,v 0.6.1.8 2000/03/02 22:20:35 ram Exp $
  *
  *  Copyright (c) 1995-1998, Raphael Manfredi
  *  
@@ -11,6 +11,13 @@
  *  as specified in the README file that comes with the distribution.
  *
  * $Log: Storable.xs,v $
+ * Revision 0.6.1.8  2000/03/02 22:20:35  ram
+ * patch9: include "patchlevel.h" for new perl 5.6
+ * patch9: fixed "undef" bug in hash keys, reported by Albert N. Micheev
+ *
+ * Revision 0.6.1.7  2000/02/10 18:47:22  ram
+ * patch8: added last_op_in_netorder() predicate
+ *
  * Revision 0.6.1.6  1999/10/19 19:23:34  ram
  * patch6: Fixed typo in macro that made threaded code not compilable
  * patch6: Changed detection of older perls (pre-5.005) by testing PATCHLEVEL
@@ -41,6 +48,7 @@
 
 #include "EXTERN.h"
 #include "perl.h"
+#include "patchlevel.h"		/* Perl's one, needed since 5.6 */
 #include "XSUB.h"
 
 /*#define DEBUGME /* Debug mode, turns assertions on as well */
@@ -590,7 +598,7 @@
 			TRACEME(("immortal undef"));
 			PUTMARK(SX_SV_UNDEF);
 		} else {
-			TRACEME(("undef"));
+			TRACEME(("undef at 0x%x", sv));
 			PUTMARK(SX_UNDEF);
 		}
 		return 0;
@@ -868,8 +876,21 @@
 			 */
 			
 			if (!SvOK(val)) {
-				TRACEME(("undef value"));
-				STORE_UNDEF();
+				/*
+				 * If the "undef" has a refcnt greater than one, other parts
+				 * of the structure might reference this, so we cannot call
+				 * STORE_UNDEF(): at retrieval time, we would break the
+				 * relationship.  Thanks to Albert Micheev for exhibiting
+				 * a structure where this bug manifested -- RAM, 02/03/2000.
+				 */
+				if (SvREFCNT(val) == 1) {
+					TRACEME(("undef value"));
+					STORE_UNDEF();
+				} else {
+					TRACEME(("undef value with refcnt=%d", SvREFCNT(val)));
+					if (ret = store(f, val))
+						goto out;
+				}
 			} else {
 				TRACEME(("(#%d) value 0x%lx", i, (unsigned long) val));
 				if (ret = store(f, val))
@@ -918,8 +939,17 @@
 			 */
 
 			if (!SvOK(val)) {
-				TRACEME(("undef value"));
-				STORE_UNDEF();
+				/*
+				 * See comment above in the "canonical" section.
+				 */
+				if (SvREFCNT(val) == 1) {
+					TRACEME(("undef value"));
+					STORE_UNDEF();
+				} else {
+					TRACEME(("undef value with refcnt=%d", SvREFCNT(val)));
+					if (ret = store(f, val))
+						goto out;
+				}
 			} else {
 				TRACEME(("(#%d) value 0x%lx", i, (unsigned long) val));
 				if (ret = store(f, val))
@@ -2596,6 +2626,21 @@
 }
 
 /*
+ * last_op_in_netorder
+ *
+ * Returns whether last operation was made using network order.
+ *
+ * This is typically out-of-band information that might prove useful
+ * to people wishing to convert native to network order data when used.
+ */
+int last_op_in_netorder()
+{
+	dPERINTERP;
+
+	return netorder;
+}
+
+/*
  * init_perinterp
  *
  * Called once per "thread" (interpreter) to initialize some global context.
@@ -2658,3 +2703,6 @@
 dclone(sv)
 SV *	sv
 
+int
+last_op_in_netorder()
+

Modified: trunk/orca/packages/Storable-0.6.9/Storable.pm
==============================================================================
--- trunk/orca/packages/Storable-0.6.9/Storable.pm	(original)
+++ trunk/orca/packages/Storable-0.6.9/Storable.pm	Sat Jul 13 21:07:55 2002
@@ -1,4 +1,4 @@
-;# $Id: Storable.pm,v 0.6.1.7 1999/10/20 17:07:31 ram Exp $
+;# $Id: Storable.pm,v 0.6.1.9 2000/03/02 22:19:47 ram Exp $
 ;#
 ;#  Copyright (c) 1995-1998, Raphael Manfredi
 ;#  
@@ -6,6 +6,12 @@
 ;#  as specified in the README file that comes with the distribution.
 ;#
 ;# $Log: Storable.pm,v $
+;# Revision 0.6.1.9  2000/03/02 22:19:47  ram
+;# patch9: updated version number
+;#
+;# Revision 0.6.1.8  2000/02/10 18:47:11  ram
+;# patch8: documented last_op_in_netorder()
+;#
 ;# Revision 0.6.1.7  1999/10/20 17:07:31  ram
 ;# patch7: forgot to update VERSION
 ;#
@@ -48,7 +54,7 @@
 use Carp;
 use vars qw($forgive_me $VERSION);
 
-$VERSION = '0.607';
+$VERSION = '0.609';
 *AUTOLOAD = \&AutoLoader::AUTOLOAD;		# Grrr...
 
 bootstrap Storable;
@@ -339,6 +345,12 @@
 Canonical order does not imply network order, those are two orthogonal
 settings.
 
+=head1 WIZARDS ONLY
+
+The C<Storable::last_op_in_netorder()> predicate will tell you whether
+network order was used in the last store or retrieve operation.  If you
+don't know how to use this, just forget about it.
+
 =head1 EXAMPLES
 
 Here are some code samples showing a possible usage of Storable:

Modified: trunk/orca/packages/Storable-0.6.9/ChangeLog
==============================================================================
--- trunk/orca/packages/Storable-0.6.9/ChangeLog	(original)
+++ trunk/orca/packages/Storable-0.6.9/ChangeLog	Sat Jul 13 21:07:55 2002
@@ -1,3 +1,18 @@
+Tue May 12 09:15:15 METDST 1998   Raphael Manfredi <Raphael_Manfredi at grenoble.hp.com>
+
+. Description:
+
+	Fixed shared "undef" bug in hashes, which did not remain shared
+	through store/retrieve.
+
+Thu Feb 10 19:48:16 MET 2000   Raphael Manfredi <Raphael_Manfredi at pobox.com>
+
+. Description:
+
+	added last_op_in_netorder() predicate
+	documented last_op_in_netorder()
+	added tests for the new last_op_in_netorder() predicate
+
 Wed Oct 20 19:07:36 MEST 1999   Raphael Manfredi <Raphael_Manfredi at pobox.com>
 
 . Description:

Modified: trunk/orca/packages/Storable-0.6.9/patchlevel.h
==============================================================================
--- trunk/orca/packages/Storable-0.6.9/patchlevel.h	(original)
+++ trunk/orca/packages/Storable-0.6.9/patchlevel.h	Sat Jul 13 21:07:56 2002
@@ -1 +1 @@
-#define PATCHLEVEL 7
+#define PATCHLEVEL 9

Modified: trunk/orca/packages/Storable-0.6.9/README
==============================================================================
--- trunk/orca/packages/Storable-0.6.9/README	(original)
+++ trunk/orca/packages/Storable-0.6.9/README	Sat Jul 13 21:07:56 2002
@@ -148,6 +148,7 @@
 	Gisle Aas <gisle at aas.no>
 	Jeff Gresham <gresham_jeffrey at jpmorgan.com>
 	Murray Nesbitt <murray at activestate.com>
+	Albert N. Micheev <Albert.N.Micheev at f80.n5049.z2.fidonet.org>
 
 for their contributions.
 

Modified: trunk/orca/packages/rrdtool-1.0.13/configure
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/configure	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/configure	Sat Jul 13 21:07:56 2002
@@ -11,7 +11,7 @@
 ac_help=
 ac_default_prefix=/usr/local
 # Any additions from configure.in:
-ac_default_prefix=/usr/local/rrdtool-1.0.7 
+ac_default_prefix=/usr/local/rrdtool-1.0.13 
 ac_help="$ac_help
   --enable-shared[=PKGS]  build shared libraries [default=no]"
 ac_help="$ac_help
@@ -794,7 +794,7 @@
 
 PACKAGE=rrdtool
 
-VERSION=1.0.7
+VERSION=1.0.13
 
 if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
   { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; }
@@ -1755,7 +1755,7 @@
 
 fi
 
-for ac_hdr in fcntl.h malloc.h unistd.h math.h sys/time.h sys/times.h sys/resource.h
+for ac_hdr in fcntl.h fp_class.h malloc.h unistd.h math.h sys/time.h sys/times.h sys/param.h sys/resource.h float.h
 do
 ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
 echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
@@ -1989,24 +1989,22 @@
 fi
 
 
-if test ${CC-gcc} = gcc; then
-	oCFLAGS=$CFLAGS
-	CFLAGS="$CFLAGS -Wall -pedantic"
-	echo $ac_n "checking if we can use GCC-specific compiler options""... $ac_c" 1>&6
-echo "configure:1997: checking if we can use GCC-specific compiler options" >&5
+oCFLAGS=$CFLAGS
+CFLAGS="$CFLAGS -Wall -pedantic"
+echo $ac_n "checking if we can use GCC-specific compiler options""... $ac_c" 1>&6
+echo "configure:1996: 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 2003 "configure"
+  cat > conftest.$ac_ext <<EOF
+#line 2001 "configure"
 #include "confdefs.h"
 
 int main() {
 return 0 
 ; return 0; }
 EOF
-if { (eval echo configure:2010: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:2008: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   rd_cv_gcc_opt=yes
 else
@@ -2016,22 +2014,60 @@
   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=$oCFLAGS
-	fi
+if test $rd_cv_gcc_opt = no; then
+	CFLAGS=$oCFLAGS
+fi
+
+
+oCFLAGS=$CFLAGS
+CFLAGS="$CFLAGS -fPIC"
+echo $ac_n "checking if we can use -fPIC as this may help building the perl module""... $ac_c" 1>&6
+echo "configure:2031: checking if we can use -fPIC as this may help building the perl module" >&5
+if eval "test \"`echo '$''{'rd_cv_pic'+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 2039 "configure"
+#include "confdefs.h"
+int main(void){return 0;}
+EOF
+if { (eval echo configure:2043: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  rd_cv_pic=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  rd_cv_pic=no
+fi
+rm -fr conftest*
+fi
+
+	       
+       
+fi
+
+echo "$ac_t""$rd_cv_pic" 1>&6
+if test $rd_cv_pic = no; then
+	CFLAGS=$oCFLAGS
 fi
 
+
 echo $ac_n "checking for strftime""... $ac_c" 1>&6
-echo "configure:2030: checking for strftime" >&5
+echo "configure:2066: 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 2035 "configure"
+#line 2071 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char strftime(); below.  */
@@ -2054,7 +2090,7 @@
 
 ; return 0; }
 EOF
-if { (eval echo configure:2058: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2094: \"$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
@@ -2076,7 +2112,7 @@
   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:2080: checking for strftime in -lintl" >&5
+echo "configure:2116: 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
@@ -2084,7 +2120,7 @@
   ac_save_LIBS="$LIBS"
 LIBS="-lintl  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 2088 "configure"
+#line 2124 "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
@@ -2095,7 +2131,7 @@
 strftime()
 ; return 0; }
 EOF
-if { (eval echo configure:2099: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2135: \"$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
@@ -2122,12 +2158,12 @@
 fi
 
 echo $ac_n "checking for vprintf""... $ac_c" 1>&6
-echo "configure:2126: checking for vprintf" >&5
+echo "configure:2162: 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 2131 "configure"
+#line 2167 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char vprintf(); below.  */
@@ -2150,7 +2186,7 @@
 
 ; return 0; }
 EOF
-if { (eval echo configure:2154: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2190: \"$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
@@ -2174,12 +2210,12 @@
 
 if test "$ac_cv_func_vprintf" != yes; then
 echo $ac_n "checking for _doprnt""... $ac_c" 1>&6
-echo "configure:2178: checking for _doprnt" >&5
+echo "configure:2214: 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 2183 "configure"
+#line 2219 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char _doprnt(); below.  */
@@ -2202,7 +2238,7 @@
 
 ; return 0; }
 EOF
-if { (eval echo configure:2206: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2242: \"$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
@@ -2227,15 +2263,15 @@
 fi
 
 
-for ac_func in snprintf fpclass isnan finite isinf memmove strchr mktime getrusage gettimeofday
+for ac_func in snprintf vsnprintf fpclass class fpclassify fp_class isnan finite isinf memmove strchr mktime getrusage gettimeofday
 do
 echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:2234: checking for $ac_func" >&5
+echo "configure:2270: 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 2239 "configure"
+#line 2275 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char $ac_func(); below.  */
@@ -2258,7 +2294,7 @@
 
 ; return 0; }
 EOF
-if { (eval echo configure:2262: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2298: \"$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
@@ -2285,7 +2321,7 @@
 
 
 echo $ac_n "checking if realloc can deal with NULL""... $ac_c" 1>&6
-echo "configure:2289: checking if realloc can deal with NULL" >&5
+echo "configure:2325: checking if realloc can deal with NULL" >&5
 if eval "test \"`echo '$''{'rd_cv_null_realloc'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2293,7 +2329,7 @@
   :
 else
   cat > conftest.$ac_ext <<EOF
-#line 2297 "configure"
+#line 2333 "configure"
 #include "confdefs.h"
 #include <stdlib.h>
 	      int main(void){
@@ -2303,7 +2339,7 @@
 	      return 0;
              }
 EOF
-if { (eval echo configure:2307: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2343: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   rd_cv_null_realloc=yes
 else
@@ -2333,7 +2369,7 @@
 unset CFLAGS
 
 echo $ac_n "checking if IEEE math works out of the box""... $ac_c" 1>&6
-echo "configure:2337: checking if IEEE math works out of the box" >&5
+echo "configure:2373: checking if IEEE math works out of the box" >&5
 if eval "test \"`echo '$''{'rd_cv_ieee_works'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2341,20 +2377,46 @@
   :
 else
   cat > conftest.$ac_ext <<EOF
-#line 2345 "configure"
+#line 2381 "configure"
 #include "confdefs.h"
 
 
-#if (! defined(HAVE_FINITE) && defined(HAVE_ISNAN) && defined(HAVE_ISINF))
-#  define HAVE_FINITE 1
-#  define finite(a) (! isnan(a) && ! isinf(a))
+#if HAVE_MATH_H
+#  include <math.h>                                                                                                                                        
 #endif
 
+#if HAVE_FLOAT_H
+#  include <float.h>  
+#endif
+
+/* for solaris */
 #if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASS))
 #  define HAVE_ISINF 1
 #  include <ieeefp.h>
 #  define isinf(a) (fpclass(a) == FP_NINF || fpclass(a) == FP_PINF)
 #endif
+/* for dec unix */
+#if (! defined(HAVE_ISINF) && defined(HAVE_FP_CLASS) && defined(HAVE_FP_CLASS_H))
+#  define HAVE_ISINF 1
+#  include <fp_class.h>
+#  define isinf(a) (fp_class(a) == FP_NEG_INF || fp_class(a) == FP_POS_INF)
+#endif
+/* for HP-UX 10.20 */
+#if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASSIFY))
+#  define HAVE_ISINF 1
+#  define isinf(a) (fpclassify(a) == FP_MINUS_INF || fpclassify(a) == FP_PLUS_INF)
+#endif
+/* for AIX */
+#if (! defined(HAVE_ISINF) && defined(HAVE_CLASS))
+#  define HAVE_ISINF 1
+#  define isinf(a) (class(a) == FP_MINUS_INF || class(a) == FP_PLUS_INF)
+#endif
+
+#if (! defined(HAVE_FINITE) && defined(HAVE_ISNAN) && defined(HAVE_ISINF))
+#  define HAVE_FINITE 1
+#  define finite(a) (! isnan(a) && ! isinf(a))
+#endif
+
 
 #include <stdio.h>
 int main(void){
@@ -2376,7 +2438,7 @@
      return 0;
 }
 EOF
-if { (eval echo configure:2380: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2442: \"$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
@@ -2391,12 +2453,11 @@
 fi
 
 echo "$ac_t""$rd_cv_ieee_works" 1>&6
-
 if test "$rd_cv_ieee_works" != yes ; then
 
 CFLAGS=-ieee
 echo $ac_n "checking if IEEE math works with the -ieee switch""... $ac_c" 1>&6
-echo "configure:2400: checking if IEEE math works with the -ieee switch" >&5
+echo "configure:2461: checking if IEEE math works with the -ieee switch" >&5
 if eval "test \"`echo '$''{'rd_cv_ieee_switch'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2404,20 +2465,46 @@
   :
 else
   cat > conftest.$ac_ext <<EOF
-#line 2408 "configure"
+#line 2469 "configure"
 #include "confdefs.h"
 
 
-#if (! defined(HAVE_FINITE) && defined(HAVE_ISNAN) && defined(HAVE_ISINF))
-#  define HAVE_FINITE 1
-#  define finite(a) (! isnan(a) && ! isinf(a))
+#if HAVE_MATH_H
+#  include <math.h>                                                                                                                                        
+#endif
+
+#if HAVE_FLOAT_H
+#  include <float.h>  
 #endif
 
+/* for solaris */
 #if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASS))
 #  define HAVE_ISINF 1
 #  include <ieeefp.h>
 #  define isinf(a) (fpclass(a) == FP_NINF || fpclass(a) == FP_PINF)
 #endif
+/* for dec unix */
+#if (! defined(HAVE_ISINF) && defined(HAVE_FP_CLASS) && defined(HAVE_FP_CLASS_H))
+#  define HAVE_ISINF 1
+#  include <fp_class.h>
+#  define isinf(a) (fp_class(a) == FP_NEG_INF || fp_class(a) == FP_POS_INF)
+#endif
+/* for HP-UX 10.20 */
+#if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASSIFY))
+#  define HAVE_ISINF 1
+#  define isinf(a) (fpclassify(a) == FP_MINUS_INF || fpclassify(a) == FP_PLUS_INF)
+#endif
+/* for AIX */
+#if (! defined(HAVE_ISINF) && defined(HAVE_CLASS))
+#  define HAVE_ISINF 1
+#  define isinf(a) (class(a) == FP_MINUS_INF || class(a) == FP_PLUS_INF)
+#endif
+
+#if (! defined(HAVE_FINITE) && defined(HAVE_ISNAN) && defined(HAVE_ISINF))
+#  define HAVE_FINITE 1
+#  define finite(a) (! isnan(a) && ! isinf(a))
+#endif
+
 
 #include <stdio.h>
 int main(void){
@@ -2439,7 +2526,7 @@
      return 0;
 }
 EOF
-if { (eval echo configure:2443: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2530: \"$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
@@ -2454,33 +2541,234 @@
 fi
 
 echo "$ac_t""$rd_cv_ieee_switch" 1>&6
+if test "$rd_cv_ieee_switch" != yes ; then
 
- if test "$rd_cv_ieee_switch" != yes ; then
+CFLAGS=-qfloat=nofold
+echo $ac_n "checking if IEEE math works with the -qfloat=nofold switch""... $ac_c" 1>&6
+echo "configure:2549: checking if IEEE math works with the -qfloat=nofold switch" >&5
+if eval "test \"`echo '$''{'rd_cv_ieee_nofold'+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 2557 "configure"
+#include "confdefs.h"
 
-CFLAGS=-mieee
-echo $ac_n "checking if IEEE math works with the -mieee switch""... $ac_c" 1>&6
-echo "configure:2463: checking if IEEE math works with the -mieee switch" >&5
-if eval "test \"`echo '$''{'rd_cv_ieee_mswitch'+set}'`\" = set"; then
+
+#if HAVE_MATH_H
+#  include <math.h>                                                                                                                                        
+#endif
+
+#if HAVE_FLOAT_H
+#  include <float.h>  
+#endif
+
+/* for solaris */
+#if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASS))
+#  define HAVE_ISINF 1
+#  include <ieeefp.h>
+#  define isinf(a) (fpclass(a) == FP_NINF || fpclass(a) == FP_PINF)
+#endif
+/* for dec unix */
+#if (! defined(HAVE_ISINF) && defined(HAVE_FP_CLASS) && defined(HAVE_FP_CLASS_H))
+#  define HAVE_ISINF 1
+#  include <fp_class.h>
+#  define isinf(a) (fp_class(a) == FP_NEG_INF || fp_class(a) == FP_POS_INF)
+#endif
+/* for HP-UX 10.20 */
+#if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASSIFY))
+#  define HAVE_ISINF 1
+#  define isinf(a) (fpclassify(a) == FP_MINUS_INF || fpclassify(a) == FP_PLUS_INF)
+#endif
+/* for AIX */
+#if (! defined(HAVE_ISINF) && defined(HAVE_CLASS))
+#  define HAVE_ISINF 1
+#  define isinf(a) (class(a) == FP_MINUS_INF || class(a) == FP_PLUS_INF)
+#endif
+
+#if (! defined(HAVE_FINITE) && defined(HAVE_ISNAN) && defined(HAVE_ISINF))
+#  define HAVE_FINITE 1
+#  define finite(a) (! isnan(a) && ! isinf(a))
+#endif
+
+
+#include <stdio.h>
+int main(void){
+    double nan,inf,c,d;
+     ;
+     /* some math to see if we get a segfault; */
+     nan=0.0/0.0;
+     inf=1.0/0.0;
+     c = 1.0;
+     c = c / 0.0; /* try getting fpe */
+     c = inf + nan;
+     c = inf / nan;
+     if (! isnan(nan)) {printf ("isnan(NaN) ... "); return 1;}
+     if (nan == nan) {printf ("nan != nan ..."); return 1;}
+     if (! isinf(inf)) {printf ("isinf(oo) ... "); return 1;}
+     if (! isinf(-inf)) {printf ("isinf(-oo) ... "); return 1;}
+     if (! inf > 0) {printf ("inf > 0 ... "); return 1;}
+     if (! -inf < 0) {printf ("inf < 0 ... "); return 1;}
+     return 0;
+}
+EOF
+if { (eval echo configure:2618: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  rd_cv_ieee_nofold=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  rd_cv_ieee_nofold=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$rd_cv_ieee_nofold" 1>&6
+if test "$rd_cv_ieee_nofold" != yes ; then
+
+CFLAGS="-w -qflttrap=enable:zerodivide"
+echo $ac_n "checking if IEEE math works with the -w -qflttrap=enable:zerodivide""... $ac_c" 1>&6
+echo "configure:2637: checking if IEEE math works with the -w -qflttrap=enable:zerodivide" >&5
+if eval "test \"`echo '$''{'rd_cv_ieee_flttrap'+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 2471 "configure"
+#line 2645 "configure"
 #include "confdefs.h"
 
 
+#if HAVE_MATH_H
+#  include <math.h>                                                                                                                                        
+#endif
+
+#if HAVE_FLOAT_H
+#  include <float.h>  
+#endif
+
+/* for solaris */
+#if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASS))
+#  define HAVE_ISINF 1
+#  include <ieeefp.h>
+#  define isinf(a) (fpclass(a) == FP_NINF || fpclass(a) == FP_PINF)
+#endif
+/* for dec unix */
+#if (! defined(HAVE_ISINF) && defined(HAVE_FP_CLASS) && defined(HAVE_FP_CLASS_H))
+#  define HAVE_ISINF 1
+#  include <fp_class.h>
+#  define isinf(a) (fp_class(a) == FP_NEG_INF || fp_class(a) == FP_POS_INF)
+#endif
+/* for HP-UX 10.20 */
+#if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASSIFY))
+#  define HAVE_ISINF 1
+#  define isinf(a) (fpclassify(a) == FP_MINUS_INF || fpclassify(a) == FP_PLUS_INF)
+#endif
+/* for AIX */
+#if (! defined(HAVE_ISINF) && defined(HAVE_CLASS))
+#  define HAVE_ISINF 1
+#  define isinf(a) (class(a) == FP_MINUS_INF || class(a) == FP_PLUS_INF)
+#endif
+
 #if (! defined(HAVE_FINITE) && defined(HAVE_ISNAN) && defined(HAVE_ISINF))
 #  define HAVE_FINITE 1
 #  define finite(a) (! isnan(a) && ! isinf(a))
 #endif
 
+
+#include <stdio.h>
+int main(void){
+    double nan,inf,c,d;
+     ;
+     /* some math to see if we get a segfault; */
+     nan=0.0/0.0;
+     inf=1.0/0.0;
+     c = 1.0;
+     c = c / 0.0; /* try getting fpe */
+     c = inf + nan;
+     c = inf / nan;
+     if (! isnan(nan)) {printf ("isnan(NaN) ... "); return 1;}
+     if (nan == nan) {printf ("nan != nan ..."); return 1;}
+     if (! isinf(inf)) {printf ("isinf(oo) ... "); return 1;}
+     if (! isinf(-inf)) {printf ("isinf(-oo) ... "); return 1;}
+     if (! inf > 0) {printf ("inf > 0 ... "); return 1;}
+     if (! -inf < 0) {printf ("inf < 0 ... "); return 1;}
+     return 0;
+}
+EOF
+if { (eval echo configure:2706: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  rd_cv_ieee_flttrap=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  rd_cv_ieee_flttrap=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$rd_cv_ieee_flttrap" 1>&6
+if test "$rd_cv_ieee_flttrap" != yes ; then
+
+CFLAGS=-mieee
+echo $ac_n "checking if IEEE math works with the -mieee switch""... $ac_c" 1>&6
+echo "configure:2725: checking if IEEE math works with the -mieee switch" >&5
+if eval "test \"`echo '$''{'rd_cv_ieee_mswitch'+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 2733 "configure"
+#include "confdefs.h"
+
+
+#if HAVE_MATH_H
+#  include <math.h>                                                                                                                                        
+#endif
+
+#if HAVE_FLOAT_H
+#  include <float.h>  
+#endif
+
+/* for solaris */
 #if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASS))
 #  define HAVE_ISINF 1
 #  include <ieeefp.h>
 #  define isinf(a) (fpclass(a) == FP_NINF || fpclass(a) == FP_PINF)
 #endif
+/* for dec unix */
+#if (! defined(HAVE_ISINF) && defined(HAVE_FP_CLASS) && defined(HAVE_FP_CLASS_H))
+#  define HAVE_ISINF 1
+#  include <fp_class.h>
+#  define isinf(a) (fp_class(a) == FP_NEG_INF || fp_class(a) == FP_POS_INF)
+#endif
+/* for HP-UX 10.20 */
+#if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASSIFY))
+#  define HAVE_ISINF 1
+#  define isinf(a) (fpclassify(a) == FP_MINUS_INF || fpclassify(a) == FP_PLUS_INF)
+#endif
+/* for AIX */
+#if (! defined(HAVE_ISINF) && defined(HAVE_CLASS))
+#  define HAVE_ISINF 1
+#  define isinf(a) (class(a) == FP_MINUS_INF || class(a) == FP_PLUS_INF)
+#endif
+
+#if (! defined(HAVE_FINITE) && defined(HAVE_ISNAN) && defined(HAVE_ISINF))
+#  define HAVE_FINITE 1
+#  define finite(a) (! isnan(a) && ! isinf(a))
+#endif
+
 
 #include <stdio.h>
 int main(void){
@@ -2502,7 +2790,7 @@
      return 0;
 }
 EOF
-if { (eval echo configure:2506: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2794: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   rd_cv_ieee_mswitch=yes
 else
@@ -2517,12 +2805,11 @@
 fi
 
 echo "$ac_t""$rd_cv_ieee_mswitch" 1>&6
-
-  if test "$rd_cv_ieee_mswitch" != yes ; then
+if test "$rd_cv_ieee_mswitch" != yes ; then
 
 CFLAGS="-q float=rndsngl"
 echo $ac_n "checking if IEEE math works with the -q float=rndsngl switch""... $ac_c" 1>&6
-echo "configure:2526: checking if IEEE math works with the -q float=rndsngl switch" >&5
+echo "configure:2813: checking if IEEE math works with the -q float=rndsngl switch" >&5
 if eval "test \"`echo '$''{'rd_cv_ieee_qswitch'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2530,20 +2817,46 @@
   :
 else
   cat > conftest.$ac_ext <<EOF
-#line 2534 "configure"
+#line 2821 "configure"
 #include "confdefs.h"
 
 
-#if (! defined(HAVE_FINITE) && defined(HAVE_ISNAN) && defined(HAVE_ISINF))
-#  define HAVE_FINITE 1
-#  define finite(a) (! isnan(a) && ! isinf(a))
+#if HAVE_MATH_H
+#  include <math.h>                                                                                                                                        
 #endif
 
+#if HAVE_FLOAT_H
+#  include <float.h>  
+#endif
+
+/* for solaris */
 #if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASS))
 #  define HAVE_ISINF 1
 #  include <ieeefp.h>
 #  define isinf(a) (fpclass(a) == FP_NINF || fpclass(a) == FP_PINF)
 #endif
+/* for dec unix */
+#if (! defined(HAVE_ISINF) && defined(HAVE_FP_CLASS) && defined(HAVE_FP_CLASS_H))
+#  define HAVE_ISINF 1
+#  include <fp_class.h>
+#  define isinf(a) (fp_class(a) == FP_NEG_INF || fp_class(a) == FP_POS_INF)
+#endif
+/* for HP-UX 10.20 */
+#if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASSIFY))
+#  define HAVE_ISINF 1
+#  define isinf(a) (fpclassify(a) == FP_MINUS_INF || fpclassify(a) == FP_PLUS_INF)
+#endif
+/* for AIX */
+#if (! defined(HAVE_ISINF) && defined(HAVE_CLASS))
+#  define HAVE_ISINF 1
+#  define isinf(a) (class(a) == FP_MINUS_INF || class(a) == FP_PLUS_INF)
+#endif
+
+#if (! defined(HAVE_FINITE) && defined(HAVE_ISNAN) && defined(HAVE_ISINF))
+#  define HAVE_FINITE 1
+#  define finite(a) (! isnan(a) && ! isinf(a))
+#endif
+
 
 #include <stdio.h>
 int main(void){
@@ -2565,7 +2878,7 @@
      return 0;
 }
 EOF
-if { (eval echo configure:2569: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2882: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   rd_cv_ieee_qswitch=yes
 else
@@ -2580,13 +2893,11 @@
 fi
 
 echo "$ac_t""$rd_cv_ieee_qswitch" 1>&6
-
-  if test "$rd_cv_ieee_qswitch" != yes ; then
+if test "$rd_cv_ieee_qswitch" != yes ; then
 
 unset CFLAGS
-
 echo $ac_n "checking if IEEE math works with fpsetmask(0)""... $ac_c" 1>&6
-echo "configure:2590: checking if IEEE math works with fpsetmask(0)" >&5
+echo "configure:2901: checking if IEEE math works with fpsetmask(0)" >&5
 if eval "test \"`echo '$''{'rd_cv_ieee_mask'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2594,20 +2905,46 @@
   :
 else
   cat > conftest.$ac_ext <<EOF
-#line 2598 "configure"
+#line 2909 "configure"
 #include "confdefs.h"
 #include <floatingpoint.h>
 
-#if (! defined(HAVE_FINITE) && defined(HAVE_ISNAN) && defined(HAVE_ISINF))
-#  define HAVE_FINITE 1
-#  define finite(a) (! isnan(a) && ! isinf(a))
+#if HAVE_MATH_H
+#  include <math.h>                                                                                                                                        
+#endif
+
+#if HAVE_FLOAT_H
+#  include <float.h>  
 #endif
 
+/* for solaris */
 #if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASS))
 #  define HAVE_ISINF 1
 #  include <ieeefp.h>
 #  define isinf(a) (fpclass(a) == FP_NINF || fpclass(a) == FP_PINF)
 #endif
+/* for dec unix */
+#if (! defined(HAVE_ISINF) && defined(HAVE_FP_CLASS) && defined(HAVE_FP_CLASS_H))
+#  define HAVE_ISINF 1
+#  include <fp_class.h>
+#  define isinf(a) (fp_class(a) == FP_NEG_INF || fp_class(a) == FP_POS_INF)
+#endif
+/* for HP-UX 10.20 */
+#if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASSIFY))
+#  define HAVE_ISINF 1
+#  define isinf(a) (fpclassify(a) == FP_MINUS_INF || fpclassify(a) == FP_PLUS_INF)
+#endif
+/* for AIX */
+#if (! defined(HAVE_ISINF) && defined(HAVE_CLASS))
+#  define HAVE_ISINF 1
+#  define isinf(a) (class(a) == FP_MINUS_INF || class(a) == FP_PLUS_INF)
+#endif
+
+#if (! defined(HAVE_FINITE) && defined(HAVE_ISNAN) && defined(HAVE_ISINF))
+#  define HAVE_FINITE 1
+#  define finite(a) (! isnan(a) && ! isinf(a))
+#endif
+
 
 #include <stdio.h>
 int main(void){
@@ -2629,7 +2966,7 @@
      return 0;
 }
 EOF
-if { (eval echo configure:2633: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2970: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   rd_cv_ieee_mask=yes
 else
@@ -2644,11 +2981,10 @@
 fi
 
 echo "$ac_t""$rd_cv_ieee_mask" 1>&6
-
-   if test "$rd_cv_ieee_mask" != yes ; then
+if test "$rd_cv_ieee_mask" != yes ; then
 
 echo $ac_n "checking if IEEE math works with signal(SIGFPE,SIG_IGN)""... $ac_c" 1>&6
-echo "configure:2652: checking if IEEE math works with signal(SIGFPE,SIG_IGN)" >&5
+echo "configure:2988: checking if IEEE math works with signal(SIGFPE,SIG_IGN)" >&5
 if eval "test \"`echo '$''{'rd_cv_ieee_sigfpe'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2656,20 +2992,46 @@
   :
 else
   cat > conftest.$ac_ext <<EOF
-#line 2660 "configure"
+#line 2996 "configure"
 #include "confdefs.h"
 #include <signal.h>
 
-#if (! defined(HAVE_FINITE) && defined(HAVE_ISNAN) && defined(HAVE_ISINF))
-#  define HAVE_FINITE 1
-#  define finite(a) (! isnan(a) && ! isinf(a))
+#if HAVE_MATH_H
+#  include <math.h>                                                                                                                                        
 #endif
 
+#if HAVE_FLOAT_H
+#  include <float.h>  
+#endif
+
+/* for solaris */
 #if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASS))
 #  define HAVE_ISINF 1
 #  include <ieeefp.h>
 #  define isinf(a) (fpclass(a) == FP_NINF || fpclass(a) == FP_PINF)
 #endif
+/* for dec unix */
+#if (! defined(HAVE_ISINF) && defined(HAVE_FP_CLASS) && defined(HAVE_FP_CLASS_H))
+#  define HAVE_ISINF 1
+#  include <fp_class.h>
+#  define isinf(a) (fp_class(a) == FP_NEG_INF || fp_class(a) == FP_POS_INF)
+#endif
+/* for HP-UX 10.20 */
+#if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASSIFY))
+#  define HAVE_ISINF 1
+#  define isinf(a) (fpclassify(a) == FP_MINUS_INF || fpclassify(a) == FP_PLUS_INF)
+#endif
+/* for AIX */
+#if (! defined(HAVE_ISINF) && defined(HAVE_CLASS))
+#  define HAVE_ISINF 1
+#  define isinf(a) (class(a) == FP_MINUS_INF || class(a) == FP_PLUS_INF)
+#endif
+
+#if (! defined(HAVE_FINITE) && defined(HAVE_ISNAN) && defined(HAVE_ISINF))
+#  define HAVE_FINITE 1
+#  define finite(a) (! isnan(a) && ! isinf(a))
+#endif
+
 
 #include <stdio.h>
 int main(void){
@@ -2691,7 +3053,7 @@
      return 0;
 }
 EOF
-if { (eval echo configure:2695: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:3057: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   rd_cv_ieee_sigfpe=yes
 else
@@ -2706,8 +3068,7 @@
 fi
 
 echo "$ac_t""$rd_cv_ieee_sigfpe" 1>&6
-
-    if test "$rd_cv_ieee_sigfpe" != yes ; then
+if test "$rd_cv_ieee_sigfpe" != yes ; then
 
 
 echo "--------------------------------------------------------------"
@@ -2717,6 +3078,8 @@
 echo "Check config.log to see what went wrong ..."
 echo ""
 exit 1
+       fi
+      fi
      fi
     fi
    fi
@@ -2738,12 +3101,21 @@
 #define MUST_DISABLE_FPMASK 1
 EOF
 
+   CFLAGS="$CFLAGS -DMUST_DISABLE_FPMASK"
 fi
 
 if test x$rd_cv_ieee_switch = xyes; then
    CFLAGS="$CFLAGS -ieee"
 fi
 
+if test x$rd_cv_ieee_nofold = xyes; then
+   CFLAGS="$CFLAGS -qfloat=nofold"
+fi
+
+if test x$rd_cv_ieee_flttrap = xyes; then
+   CFLAGS="$CFLAGS -w -qflttrap=enable:zerodivide"
+fi
+
 if test x$rd_cv_ieee_mswitch = xyes; then
    CFLAGS="$CFLAGS -mieee"
 fi
@@ -2868,7 +3240,17 @@
           contrib/trytime/Makefile			\
           contrib/log2rrd/Makefile			\
           contrib/log2rrd/log2rrd.pl			\
+          contrib/killspike/Makefile			\
+          contrib/killspike/killspike.pl		\
+          contrib/rrdlastds/Makefile			\
+          contrib/rrdlastds/rrdlastds.pl		\
+          contrib/rrdfetchnames/Makefile		\
+          contrib/rrdfetchnames/rrdfetchnames.pl	\
+          contrib/add_ds/Makefile			\
+          contrib/add_ds/add_ds.pl			\
+	  contrib/add_ds/batch.pl			\
           contrib/rrd-file-icon/Makefile		\
+          contrib/rrdproc/Makefile			\
           doc/Makefile					\
           gd1.3/Makefile				\
           libpng-1.0.3/Makefile				\
@@ -2999,7 +3381,17 @@
           contrib/trytime/Makefile			\
           contrib/log2rrd/Makefile			\
           contrib/log2rrd/log2rrd.pl			\
+          contrib/killspike/Makefile			\
+          contrib/killspike/killspike.pl		\
+          contrib/rrdlastds/Makefile			\
+          contrib/rrdlastds/rrdlastds.pl		\
+          contrib/rrdfetchnames/Makefile		\
+          contrib/rrdfetchnames/rrdfetchnames.pl	\
+          contrib/add_ds/Makefile			\
+          contrib/add_ds/add_ds.pl			\
+	  contrib/add_ds/batch.pl			\
           contrib/rrd-file-icon/Makefile		\
+          contrib/rrdproc/Makefile			\
           doc/Makefile					\
           gd1.3/Makefile				\
           libpng-1.0.3/Makefile				\
@@ -3188,10 +3580,10 @@
 
 
 echo $ac_n "checking in""... $ac_c" 1>&6
-echo "configure:3192: checking in" >&5
+echo "configure:3584: 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
+echo $ac_n "ordering CD from http://ee-staff.ethz-ch/~oetiker/wish $ac_c" 1>&6
 sleep 1
 echo $ac_n ".$ac_c" 1>&6
 sleep 1
@@ -3210,7 +3602,7 @@
 echo "install everything to $prefix. If you want to install the perl"
 echo "modules in site-perl, try 'make site-perl-install'."
 echo 
-echo "       ... that wishlist mentioned above does realy exist. So if"
+echo "       ... that wishlist mentioned above does really exist. So if"
 echo "you feel like showing your appreciation for rrdtool this is the"
 echo "place to go. :-)"
 echo 

Modified: trunk/orca/packages/rrdtool-1.0.13/Makefile.in
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/Makefile.in	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/Makefile.in	Sat Jul 13 21:07:56 2002
@@ -10,8 +10,6 @@
 # even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 # PARTICULAR PURPOSE.
 
-# build the following subdirectories
-
 
 SHELL = @SHELL@
 
@@ -75,6 +73,8 @@
 RANLIB = @RANLIB@
 ZLIB_LIB_DIR = @ZLIB_LIB_DIR@
 
+RSYNC = rsync --rsh=ssh
+# build the following subdirectories
 SUBDIRS = cgilib-0.4 config gd1.3 zlib-1.1.3 libpng-1.0.3 src doc examples contrib
 
 # the following files are not mentioned in any other Makefile
@@ -104,7 +104,7 @@
 
 DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
 
-TAR = tar
+TAR = gtar
 GZIP_ENV = --best
 all: all-redirect
 .SUFFIXES:
@@ -382,13 +382,13 @@
 
 # rules for building the perl module
 perl_piped: perl-piped/Makefile
-	cd perl-piped && $(MAKE)  OPTIMIZE="$(CFLAGS)"
+	cd perl-piped && $(MAKE)  OPTIMIZE="$(CFLAGS)" CC="$(CC)"
 
 perl-piped/Makefile: perl-piped/Makefile.PL
 	cd perl-piped && $(PERL) Makefile.PL
 
 perl_shared: perl-shared/Makefile
-	cd perl-shared && $(MAKE) OPTIMIZE="$(CFLAGS)"
+	cd perl-shared && $(MAKE) OPTIMIZE="$(CFLAGS)" CC="$(CC)"
 
 perl-shared/Makefile: perl-shared/Makefile.PL
 	cd perl-shared && $(PERL) Makefile.PL
@@ -407,27 +407,28 @@
 
 to-docs: to-versync
 	(cd doc && $(MAKE) clean && $(MAKE))
+
 #to-autoconf
 to-versync: 
 	perl -i -p -e '"$(VERSION)" =~ /(\d+)\.(\d+)\.(\d+)/; $$v=sprintf("%1d.%02d0%02d1" ,$${1},$${2},$${3}); s|VERSION\s*=\s*[\d.]+|VERSION = $$v|' perl-*/RRD?.pm
-	perl -i -p -e 's|RRDtool\s+\d+\.\d+\.\d+|RRDtool $(VER)|' src/*.[ch]
+	perl -i -p -e 's|RRDtool\s+\d+\.\d+\.\d+ |RRDtool $(VERSION) |' src/*.[ch]
 
 to-dist: to-docs dist
 	mv $(PACKAGE)-$(VERSION).tar.gz archive
 
 to-scp: to-dist
-	scp CHANGES oetiker at tardis.ee.ethz.ch:/home/oetiker/public_html/webtools/rrdtool/pub/
-	scp archive/$(PACKAGE)-$(VERSION).tar.gz oetiker at tardis.ee.ethz.ch:/home/oetiker/public_html/webtools/rrdtool/pub/$(ARCHIVE)
-	scp CHANGES tobi at ipn.caida.org:/ipn/web/Tools/RRDtool/pub/
-	scp archive/$(PACKAGE)-$(VERSION).tar.gz tobi at ipn.caida.org:/ipn/web/Tools/RRDtool/pub/
+	$(RSYNC) CHANGES  archive/$(PACKAGE)-$(VERSION).tar.gz oetiker at tardis.ee.ethz.ch:/home/oetiker/public_html/webtools/rrdtool/pub/
+	$(RSYNC) CHANGES archive/$(PACKAGE)-$(VERSION).tar.gz tobi at ipn.caida.org:/ipn/web/Tools/RRDtool/pub/
+
+site-perl-inst: site-perl-install
 
-site-perl-inst:
+site-perl-install: perl-piped/Makefile perl-shared/Makefile
 	cd perl-piped && $(MAKE) install
 	cd perl-shared && $(MAKE) install
 
 clean-local:
-	cd perl-piped && $(MAKE) clean
-	cd perl-shared && $(MAKE) clean
+	cd perl-piped && test -f Makefile && $(MAKE) clean || true
+	cd perl-shared && test -f Makefile && $(MAKE) clean || true
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.

Modified: trunk/orca/packages/rrdtool-1.0.13/configure.in
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/configure.in	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/configure.in	Sat Jul 13 21:07:56 2002
@@ -16,10 +16,10 @@
 AC_CANONICAL_SYSTEM
 
 dnl tell automake the this script is for rrdtool
-AM_INIT_AUTOMAKE(rrdtool, 1.0.7)
+AM_INIT_AUTOMAKE(rrdtool, 1.0.13)
 
 dnl where we install our stuff ...
-AC_PREFIX_DEFAULT( /usr/local/rrdtool-1.0.7 )
+AC_PREFIX_DEFAULT( /usr/local/rrdtool-1.0.13 )
 
 dnl tell automake which file to use as config header
 AM_CONFIG_HEADER(config/config.h)
@@ -63,7 +63,7 @@
 
 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)
+AC_CHECK_HEADERS(fcntl.h fp_class.h malloc.h unistd.h math.h sys/time.h sys/times.h sys/param.h sys/resource.h float.h)
 
 dnl Checks for typedefs, structures, and compiler characteristics.
 AC_C_CONST
@@ -73,28 +73,41 @@
 dnl Checks for libraries.
 AC_CHECK_LIB(m, acos)
 
-dnl If CC is not set we assume gcc
-if test ${CC-gcc} = gcc; then
-	oCFLAGS=$CFLAGS
-	CFLAGS="$CFLAGS -Wall -pedantic"
-	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=$oCFLAGS
-	fi
+dnl Does the compiler like -Wall and -pedantic ?
+oCFLAGS=$CFLAGS
+CFLAGS="$CFLAGS -Wall -pedantic"
+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=$oCFLAGS
+fi
+
+dnl Can the compiler take -fPIC
+
+oCFLAGS=$CFLAGS
+CFLAGS="$CFLAGS -fPIC"
+AC_CACHE_CHECK(if we can use -fPIC as this may help building the perl module, rd_cv_pic,
+               [AC_TRY_RUN([int main(void){return 0;}],
+             	    rd_cv_pic=yes,
+		    rd_cv_pic=no,:)
+	       ]
+       )
+if test $rd_cv_pic = no; then
+	CFLAGS=$oCFLAGS
 fi
 
+
 dnl Checks for library functions.
 AC_FUNC_STRFTIME
 AC_FUNC_VPRINTF
 
 dnl for each function found we get a definition in config.h 
 dnl of the form HAVE_FUNCTION
-AC_CHECK_FUNCS(snprintf fpclass isnan finite isinf memmove strchr mktime getrusage gettimeofday)
+AC_CHECK_FUNCS(snprintf vsnprintf fpclass class fpclassify fp_class isnan finite isinf memmove strchr mktime getrusage gettimeofday)
 
 dnl what does realloc do if it gets called with a NULL pointer
 
@@ -118,16 +131,42 @@
 AC_CACHE_CHECK([if IEEE math works $1], [rd_cv_ieee_$2],
 [AC_TRY_RUN([$3
 
-#if (! defined(HAVE_FINITE) && defined(HAVE_ISNAN) && defined(HAVE_ISINF))
-#  define HAVE_FINITE 1
-#  define finite(a) (! isnan(a) && ! isinf(a))
+#if HAVE_MATH_H
+#  include <math.h>                                                                                                                                        
 #endif
 
+#if HAVE_FLOAT_H
+#  include <float.h>  
+#endif
+
+/* for solaris */
 #if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASS))
 #  define HAVE_ISINF 1
 #  include <ieeefp.h>
 #  define isinf(a) (fpclass(a) == FP_NINF || fpclass(a) == FP_PINF)
 #endif
+/* for dec unix */
+#if (! defined(HAVE_ISINF) && defined(HAVE_FP_CLASS) && defined(HAVE_FP_CLASS_H))
+#  define HAVE_ISINF 1
+#  include <fp_class.h>
+#  define isinf(a) (fp_class(a) == FP_NEG_INF || fp_class(a) == FP_POS_INF)
+#endif
+/* for HP-UX 10.20 */
+#if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASSIFY))
+#  define HAVE_ISINF 1
+#  define isinf(a) (fpclassify(a) == FP_MINUS_INF || fpclassify(a) == FP_PLUS_INF)
+#endif
+/* for AIX */
+#if (! defined(HAVE_ISINF) && defined(HAVE_CLASS))
+#  define HAVE_ISINF 1
+#  define isinf(a) (class(a) == FP_MINUS_INF || class(a) == FP_PLUS_INF)
+#endif
+
+#if (! defined(HAVE_FINITE) && defined(HAVE_ISNAN) && defined(HAVE_ISINF))
+#  define HAVE_FINITE 1
+#  define finite(a) (! isnan(a) && ! isinf(a))
+#endif
+
 
 #include <stdio.h>
 int main(void){
@@ -154,33 +193,34 @@
 unset CFLAGS
 
 AC_IEEE([out of the box],works)
-
 if test "$rd_cv_ieee_works" != yes ; then
 
 CFLAGS=-ieee
 AC_IEEE([with the -ieee switch],switch)
+if test "$rd_cv_ieee_switch" != yes ; then
 
- if test "$rd_cv_ieee_switch" != yes ; then
+CFLAGS=-qfloat=nofold
+AC_IEEE([with the -qfloat=nofold switch],nofold)
+if test "$rd_cv_ieee_nofold" != yes ; then
+
+CFLAGS="-w -qflttrap=enable:zerodivide"
+AC_IEEE([with the -w -qflttrap=enable:zerodivide],flttrap)
+if test "$rd_cv_ieee_flttrap" != yes ; then
 
 CFLAGS=-mieee
 AC_IEEE([with the -mieee switch],mswitch)
-
-  if test "$rd_cv_ieee_mswitch" != yes ; then
+if test "$rd_cv_ieee_mswitch" != yes ; then
 
 CFLAGS="-q float=rndsngl"
 AC_IEEE([with the -q float=rndsngl switch],qswitch)
-
-  if test "$rd_cv_ieee_qswitch" != yes ; then
+if test "$rd_cv_ieee_qswitch" != yes ; then
 
 unset CFLAGS
-
 AC_IEEE([with fpsetmask(0)],mask,[#include <floatingpoint.h>],[fpsetmask(0)])
-
-   if test "$rd_cv_ieee_mask" != yes ; then
+if test "$rd_cv_ieee_mask" != yes ; then
 
 AC_IEEE([with signal(SIGFPE,SIG_IGN)],sigfpe,[#include <signal.h>],[signal(SIGFPE,SIG_IGN)])
-
-    if test "$rd_cv_ieee_sigfpe" != yes ; then
+if test "$rd_cv_ieee_sigfpe" != yes ; then
 
 
 echo "--------------------------------------------------------------"
@@ -190,6 +230,8 @@
 echo "Check config.log to see what went wrong ..."
 echo ""
 exit 1
+       fi
+      fi
      fi
     fi
    fi
@@ -205,12 +247,21 @@
 
 if test x$rd_cv_ieee_mask = xyes; then
    AC_DEFINE(MUST_DISABLE_FPMASK)
+   CFLAGS="$CFLAGS -DMUST_DISABLE_FPMASK"
 fi
 
 if test x$rd_cv_ieee_switch = xyes; then
    CFLAGS="$CFLAGS -ieee"
 fi
 
+if test x$rd_cv_ieee_nofold = xyes; then
+   CFLAGS="$CFLAGS -qfloat=nofold"
+fi
+
+if test x$rd_cv_ieee_flttrap = xyes; then
+   CFLAGS="$CFLAGS -w -qflttrap=enable:zerodivide"
+fi
+
 if test x$rd_cv_ieee_mswitch = xyes; then
    CFLAGS="$CFLAGS -mieee"
 fi
@@ -234,7 +285,17 @@
           contrib/trytime/Makefile			\
           contrib/log2rrd/Makefile			\
           contrib/log2rrd/log2rrd.pl			\
+          contrib/killspike/Makefile			\
+          contrib/killspike/killspike.pl		\
+          contrib/rrdlastds/Makefile			\
+          contrib/rrdlastds/rrdlastds.pl		\
+          contrib/rrdfetchnames/Makefile		\
+          contrib/rrdfetchnames/rrdfetchnames.pl	\
+          contrib/add_ds/Makefile			\
+          contrib/add_ds/add_ds.pl			\
+	  contrib/add_ds/batch.pl			\
           contrib/rrd-file-icon/Makefile		\
+          contrib/rrdproc/Makefile			\
           doc/Makefile					\
           gd1.3/Makefile				\
           libpng-1.0.3/Makefile				\
@@ -246,7 +307,7 @@
 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
+echo $ac_n "ordering CD from http://ee-staff.ethz-ch/~oetiker/wish $ac_c" 1>&6
 sleep 1
 echo $ac_n ".$ac_c" 1>&6
 sleep 1
@@ -265,7 +326,7 @@
 echo "install everything to $prefix. If you want to install the perl"
 echo "modules in site-perl, try 'make site-perl-install'."
 echo 
-echo "       ... that wishlist mentioned above does realy exist. So if"
+echo "       ... that wishlist mentioned above does really exist. So if"
 echo "you feel like showing your appreciation for rrdtool this is the"
 echo "place to go. :-)"
 echo 

Modified: trunk/orca/packages/rrdtool-1.0.13/src/gdpng.c
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/src/gdpng.c	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/src/gdpng.c	Sat Jul 13 21:07:57 2002
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool  Copyright Tobias Oetiker, 1997, 1998, 1999
+ * RRDtool 1.0.13  Copyright Tobias Oetiker, 1997, 1998, 1999
  *****************************************************************************
  * gdpng.c  add PNG output routine to gd library
  *****************************************************************************/

Modified: trunk/orca/packages/rrdtool-1.0.13/src/rrd_format.c
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/src/rrd_format.c	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/src/rrd_format.c	Sat Jul 13 21:07:57 2002
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool  Copyright Tobias Oetiker, 1999
+ * RRDtool 1.0.13  Copyright Tobias Oetiker, 1999
  *****************************************************************************
  * rrd_format.c  RRD Database Format helper functions
  *****************************************************************************

Modified: trunk/orca/packages/rrdtool-1.0.13/src/gifsize.c
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/src/gifsize.c	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/src/gifsize.c	Sat Jul 13 21:07:57 2002
@@ -1,5 +1,5 @@
 /****************************************************************************
- * RRDtool  Copyright Tobias Oetiker, 1997,1998, 1999
+ * RRDtool 1.0.13  Copyright Tobias Oetiker, 1997,1998, 1999
  ****************************************************************************
  * gifsize.c  provides the function gifsize which determines the size of a gif
  ****************************************************************************/

Modified: trunk/orca/packages/rrdtool-1.0.13/src/rrd_fetch.c
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/src/rrd_fetch.c	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/src/rrd_fetch.c	Sat Jul 13 21:07:57 2002
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool  Copyright Tobias Oetiker, 1997, 1998, 1999
+ * RRDtool 1.0.13  Copyright Tobias Oetiker, 1997, 1998, 1999
  *****************************************************************************
  * rrd_fetch.c  read date from an rrd to use for further processing
  *****************************************************************************

Modified: trunk/orca/packages/rrdtool-1.0.13/src/rrd_error.c
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/src/rrd_error.c	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/src/rrd_error.c	Sat Jul 13 21:07:57 2002
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool  Copyright Tobias Oetiker, 1997, 1998, 1999
+ * RRDtool 1.0.13  Copyright Tobias Oetiker, 1997, 1998, 1999
  *****************************************************************************
  * rrd_error.c   Common Header File
  *****************************************************************************
@@ -16,14 +16,17 @@
 void
 rrd_set_error(char *fmt, ...)
 {
-    static char buffer[4096];
+    int maxlen = 4096;
     va_list argp;
     rrd_clear_error();
+    rrd_error = malloc(sizeof(char)*maxlen);
     va_start(argp, fmt);
-    vsprintf(buffer, fmt, argp);
+#ifdef HAVE_VSNPRINTF
+    vsnprintf(rrd_error, maxlen-1, fmt, argp);
+#else
+    vsprintf(rrd_error, fmt, argp);
+#endif
     va_end(argp);
-    rrd_error = malloc(sizeof(char)*(strlen(buffer)+1));
-    strcpy(rrd_error, buffer);
 }
 
 int

Modified: trunk/orca/packages/rrdtool-1.0.13/src/Makefile.in
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/src/Makefile.in	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/src/Makefile.in	Sat Jul 13 21:07:57 2002
@@ -164,7 +164,7 @@
 
 DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
 
-TAR = tar
+TAR = gtar
 GZIP_ENV = --best
 SOURCES = $(librrd_la_SOURCES) $(librrd_private_la_SOURCES) $(rrdcgi_SOURCES) $(rrdtool_SOURCES)
 OBJECTS = $(librrd_la_OBJECTS) $(librrd_private_la_OBJECTS) $(rrdcgi_OBJECTS) $(rrdtool_OBJECTS)
@@ -337,7 +337,7 @@
 	done
 gdpng.lo gdpng.o : gdpng.c ../libpng-1.0.3/png.h ../zlib-1.1.3/zlib.h \
 	../zlib-1.1.3/zconf.h ../libpng-1.0.3/pngconf.h ../gd1.3/gd.h
-getopt.lo getopt.o : getopt.c ../config/config.h
+getopt.lo getopt.o : getopt.c ../config/config.h getopt.h
 getopt1.lo getopt1.o : getopt1.c ../config/config.h getopt.h
 gifsize.lo gifsize.o : gifsize.c
 parsetime.lo parsetime.o : parsetime.c rrd_tool.h ../config/config.h \

Modified: trunk/orca/packages/rrdtool-1.0.13/src/rrd_format.h
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/src/rrd_format.h	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/src/rrd_format.h	Sat Jul 13 21:07:57 2002
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool  Copyright Tobias Oetiker, 1997, 1998, 1999
+ * RRDtool 1.0.13  Copyright Tobias Oetiker, 1997, 1998, 1999
  *****************************************************************************
  * rrd_format.h  RRD Database Format header
  *****************************************************************************/
@@ -20,7 +20,7 @@
 #define RRD_VERSION   "0001"
 #define FLOAT_COOKIE  8.642135E130
 
-#if defined(WIN32) || defined(_HPUX_SOURCE)
+#if defined(WIN32)
 #define DNAN          ((double)fmod(0.0,0.0))    
 #define DINF	      ((double)log(0.0))
 #else

Modified: trunk/orca/packages/rrdtool-1.0.13/src/rrd_open.c
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/src/rrd_open.c	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/src/rrd_open.c	Sat Jul 13 21:07:57 2002
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool  Copyright Tobias Oetiker, 1997, 1998, 1999
+ * RRDtool 1.0.13  Copyright Tobias Oetiker, 1997, 1998, 1999
  *****************************************************************************
  * rrd_open.c  Open an RRD File
  *****************************************************************************
@@ -105,7 +105,7 @@
     long writecnt=0,totalcnt = MEMBLK;
     FILE *input=NULL;
     char c ;
-    if ((strcmp("-",file_name) == 0)) { *input = *stdin; }
+    if ((strcmp("-",file_name) == 0)) { input = stdin; }
     else {
       if ((input = fopen(file_name,"rb")) == NULL ){
 	rrd_set_error("readfile can't open '%s'",file_name);
@@ -130,7 +130,7 @@
       }
     } while (! feof(input));
     (*buffer)[writecnt] = '\0';
-    fclose(input);
+    if (strcmp("-",file_name) != 0) {fclose(input);};
     return writecnt;
 }
 

Modified: trunk/orca/packages/rrdtool-1.0.13/src/rrd_graph.c
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/src/rrd_graph.c	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/src/rrd_graph.c	Sat Jul 13 21:07:58 2002
@@ -1,5 +1,5 @@
 /****************************************************************************
- * RRDtool  Copyright Tobias Oetiker, 1997,1998, 1999
+ * RRDtool 1.0.13  Copyright Tobias Oetiker, 1997,1998, 1999
  ****************************************************************************
  * rrd__graph.c  make creates ne rrds
  ****************************************************************************/
@@ -30,7 +30,7 @@
 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_INF,OP_NEGINF,
+enum op_en {OP_NUMBER=0,OP_VARIABLE,OP_INF,OP_PREV,OP_NEGINF,
 	    OP_UNKN,OP_NOW,OP_TIME,OP_ADD,OP_MOD,
             OP_SUB,OP_MUL,
 	    OP_DIV,OP_SIN, OP_DUP, OP_EXC, OP_POP,
@@ -180,7 +180,7 @@
 
     /* configuration of graph */
 
-    char           graphfile[1024]; /* filename for graphic */
+    char           graphfile[MAXPATH]; /* 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 */
@@ -219,7 +219,7 @@
 
 } image_desc_t;
 
-
+int bad_format(char *);
 
 
 /* translate time values into x coordinates */   
@@ -559,25 +559,30 @@
         
     for (src_row = skiprows; src_row < row_cnt; src_row+=reduce_factor) {
 	for (col=0;col<(*ds_cnt);col++){
-	    double newval=0;
+	    double newval=DNAN;
 	    unsigned long validval=0;
 	    for (i=0;i<reduce_factor && src_row+i<row_cnt;i++) {		
 		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:
+		if (isnan(newval)) {
 		    newval = (*data)[ptr];
-		    break;
+		} else {
+		   
+  		  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{
@@ -735,8 +740,8 @@
 	    return NULL;
 	}
 
-	else if(sscanf(expr,"%lf%n",&rpnp[steps].val,&pos) == 1){
-	    rpnp[steps].op = OP_NUMBER;
+	else if((sscanf(expr,"%lf%n",&rpnp[steps].val,&pos) == 1) && (expr[pos] == ',')){
+ 	    rpnp[steps].op = OP_NUMBER;
 	    expr+=pos;
 	} 
 	
@@ -768,6 +773,7 @@
 	match_op(OP_UNKN,UNKN)
 	match_op(OP_UN,UN)
 	match_op(OP_NEGINF,NEGINF)
+	match_op(OP_PREV,PREV)
 	match_op(OP_INF,INF)
 	match_op(OP_NOW,NOW)
 	match_op(OP_TIME,TIME)
@@ -917,6 +923,13 @@
 		    }
 		    stack[++stptr] =  *im->gdes[gdi].rpnp[rpi].data;
 		    break;
+		case OP_PREV:
+		    if (dataidx == 0) {
+                       stack[++stptr] = DNAN;
+                    } else {
+                       stack[++stptr] = im->gdes[gdi].data[dataidx];
+                    }
+		    break;
 		case OP_UNKN:
 		    stack[++stptr] = DNAN; 
 		    break;
@@ -1165,7 +1178,7 @@
 
 		value =
 		    im->gdes[vidx].data[
-					((unsigned long)floor(
+					((unsigned long)floor((double)
 							     (gr_time - im->gdes[vidx].start ) 
 							     / im->gdes[vidx].step)+1)			
 
@@ -1178,16 +1191,15 @@
 		if (! isnan(value)) {
 		  paintval += value;
 		  im->gdes[ii].p_data[i] = paintval;
+		  if (finite(paintval)){
+  		   if (isnan(minval) || paintval <  minval)
+		     minval = paintval;
+		   if (isnan(maxval) || paintval >  maxval)
+		     maxval = paintval;
+		  }
 		} else {
 		  im->gdes[ii].p_data[i] = DNAN;
 		}
-
-		if (finite(paintval)){
-		  if (isnan(minval) || paintval <  minval)
-		    minval = paintval;
-		  if (isnan(maxval) || paintval >  maxval)
-		    maxval = paintval;
-		}
 		break;
 	    case GF_PRINT:
 	    case GF_GPRINT:
@@ -1444,6 +1456,10 @@
 	    }
 	    if (im->gdes[i].gf == GF_PRINT){
 		(*prdata)[prlines-2] = malloc((FMT_LEG_LEN+2)*sizeof(char));
+		if (bad_format(im->gdes[i].format)) {
+			rrd_set_error("bad format for [G]PRINT in '%s'", im->gdes[i].format);
+			return -1;
+		}
 #ifdef HAVE_SNPRINTF
 		snprintf((*prdata)[prlines-2],FMT_LEG_LEN,im->gdes[i].format,printval,si_symb);
 #else
@@ -1453,6 +1469,10 @@
 	    } else {
 		/* GF_GPRINT */
 
+		if (bad_format(im->gdes[i].format)) {
+			rrd_set_error("bad format for [G]PRINT in '%s'", im->gdes[i].format);
+			return -1;
+		}
 #ifdef HAVE_SNPRINTF
 		snprintf(im->gdes[i].legend,FMT_LEG_LEN-2,im->gdes[i].format,printval,si_symb);
 #else
@@ -1481,7 +1501,7 @@
 
 
 /* place legends with color spots */
-void
+int
 leg_place(image_desc_t *im)
 {
     
@@ -1496,6 +1516,12 @@
     int   glue = 0;
     int   i,ii, mark = 0;
     char  prt_fctn; /*special printfunctions */
+    int  *legspace;
+
+    if ((legspace = malloc(im->gdes_c*sizeof(int)))==NULL){
+       rrd_set_error("malloc for legspace");
+       return -1;
+    }
 
     for(i=0;i<im->gdes_c;i++){
 	fill_last = fill;
@@ -1505,22 +1531,38 @@
 	/* 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;
+	    im->gdes[i].legend[leg_cc] = '\0';
 	} else {
 	    prt_fctn = '\0';
 	}
-
+        /* remove exess space */
+        while (prt_fctn=='g' && 
+	       leg_cc > 0 && 
+	       im->gdes[i].legend[leg_cc-1]==' '){
+	   leg_cc--;
+	   im->gdes[i].legend[leg_cc]='\0';
+	}
 	if (leg_cc != 0 ){	    
-	    if (fill > 0) 
-		fill += interleg;
+	   legspace[i]=(prt_fctn=='g' ? 0 : interleg);
+	   
+	   if (fill > 0){ 
+ 	       /* no interleg space if string ends in \g */
+	       fill += legspace[i];
+	    }
 	    if (im->gdes[i].gf != GF_GPRINT && 
-		im->gdes[i].gf != GF_COMMENT) 
+		im->gdes[i].gf != GF_COMMENT) { 
 		fill += box; 	   
+	    }
 	    fill += leg_cc * SmallFont->w;
 	    leg_c++;
+	} else {
+	   legspace[i]=0;
+	}
+        /* who said there was a special tag ... ?*/
+	if (prt_fctn=='g') {    
+	   prt_fctn = '\0';
 	}
-	    
 	if (prt_fctn == '\0') {
 	    if (i == im->gdes_c -1 ) prt_fctn ='l';
 	    
@@ -1558,7 +1600,7 @@
 		im->gdes[ii].legloc.y = leg_y;
 		leg_x =  leg_x 
 		    + strlen(im->gdes[ii].legend)*SmallFont->w 
-		    + interleg 
+		    + legspace[ii]
 		    + glue;
 		if (im->gdes[ii].gf != GF_GPRINT && 
 		    im->gdes[ii].gf != GF_COMMENT) 
@@ -1572,6 +1614,8 @@
 	}	   
     }
     im->ygif = leg_y+6;
+    free(legspace);
+    return 0;
 }
 
 
@@ -1697,7 +1741,7 @@
                               (polyPoints[0].x - (strlen(graph_label) * 
                                                   SmallFont->w)-7), 
                               polyPoints[0].y - SmallFont->h/2+1,
-                              graph_label, graph_col[GRC_FONT].i);
+                              (unsigned char *)graph_label, graph_col[GRC_FONT].i);
 		
 		gdImageSetStyle(gif, styleMajor, 2);
 
@@ -1809,7 +1853,7 @@
 			  (polyPoints[0].x - (strlen(graph_label) * 
 					      SmallFont->w)-7), 
 			  polyPoints[0].y - SmallFont->h/2+1,
-			  graph_label, graph_col[GRC_FONT].i);	
+			  (unsigned char *)graph_label, graph_col[GRC_FONT].i);	
 	} 
     }
 	return 1;
@@ -1919,7 +1963,7 @@
 	    && gr_pos + width <= im->xorigin+im->xsize) 
 	    gdImageString(gif, SmallFont,
 			  gr_pos,  polyPoints[0].y+4,
-			  graph_label, graph_col[GRC_FONT].i);
+			  (unsigned char *)graph_label, graph_col[GRC_FONT].i);
     }
 
 }
@@ -2001,7 +2045,7 @@
 		     im->xgif/2 
 		     - (strlen(nodata)*LargeFont->w)/2,
 		     (2*im->yorigin-im->ysize) / 2,
-		     nodata, graph_col[GRC_FONT].i);
+		     (unsigned char *)nodata, graph_col[GRC_FONT].i);
     }
 
 
@@ -2010,7 +2054,7 @@
 		    7,
 		    (im->yorigin - im->ysize/2
 		     +(strlen(im->ylegend)*SmallFont->w)/2 ),
-		    im->ylegend, graph_col[GRC_FONT].i);
+		    (unsigned char *)im->ylegend, graph_col[GRC_FONT].i);
     
 
     /* graph title */
@@ -2018,7 +2062,7 @@
 		    im->xgif/2 
 		    - (strlen(im->title)*LargeFont->w)/2,
 		  8,
-		    im->title, graph_col[GRC_FONT].i);
+		    (unsigned char *)im->title, graph_col[GRC_FONT].i);
     
     /* graph labels */
 
@@ -2042,7 +2086,7 @@
 	    gdImageString(gif, SmallFont,
 			  polyPoints[0].x+boxH+6, 
 			  polyPoints[0].y-1,
-			  im->gdes[i].legend,
+			  (unsigned char *)im->gdes[i].legend,
 			  graph_col[GRC_FONT].i);
 	} else {
 	    polyPoints[0].x = im->gdes[i].legloc.x;
@@ -2051,7 +2095,7 @@
 	    gdImageString(gif, SmallFont,
 			  polyPoints[0].x, 
 			  polyPoints[0].y,
-			  im->gdes[i].legend,
+			  (unsigned char *)im->gdes[i].legend,
 			  graph_col[GRC_FONT].i);
 	}
     }
@@ -2130,11 +2174,9 @@
       return 0; /* the file does not exist */
     switch (im->imgformat) {
     case IF_GIF:
-	GifSize(fd,&(im->xgif),&(im->ygif));
-	break;
+	return GifSize(fd,&(im->xgif),&(im->ygif));
     case IF_PNG:
-	PngSize(fd,&(im->xgif),&(im->ygif));
-	break;
+	return PngSize(fd,&(im->xgif),&(im->ygif));
     }
     fclose(fd);
     return 1;
@@ -2206,7 +2248,8 @@
     
     /* determine where to place the legends onto the graphics.
        and set im->ygif to match space requirements for text */
-    leg_place(im);
+    if(leg_place(im)==-1)
+     return -1;
 
     gif=gdImageCreate(im->xgif,im->ygif);
 
@@ -2690,19 +2733,26 @@
 	    break;
 
 	case '?':
-	    rrd_set_error("unknown option '%s'",argv[optind-1]);
-	    return -1;
+            if (optopt != 0)
+                rrd_set_error("unknown option '%c'", optopt);
+            else
+                rrd_set_error("unknown option '%s'",argv[optind-1]);
+            return -1;
 	}
     }
     
+    if (optind >= argc) {
+       rrd_set_error("missing filename");
+       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],sizeof(im.graphfile)-1);
-    im.graphfile[sizeof(im.graphfile)-1]='\0';
+    strncpy(im.graphfile,argv[optind],MAXPATH-1);
+    im.graphfile[MAXPATH-1]='\0';
 
     if (proc_start_end(&start_tv,&end_tv,&start_tmp,&end_tmp) == -1){
 	return -1;
@@ -2903,7 +2953,7 @@
 		if(sscanf(&argv[i][argstart
 				  +strstart
 				  +scan_for_col(&argv[i][argstart+strstart],
-						254,im.gdes[im.gdes_c-1].rrd)],
+						MAXPATH,im.gdes[im.gdes_c-1].rrd)],
 			  ":" DS_NAM_FMT ":" CF_NAM_FMT,
 			  im.gdes[im.gdes_c-1].ds_nam,
 			  symname) != 2){
@@ -2974,4 +3024,30 @@
     return 0;
 }
 
+int bad_format(char *fmt) {
+	char *ptr;
+
+	ptr = fmt;
+	while (*ptr != '\0') {
+		if (*ptr == '%') {ptr++;
+			if (*ptr == '\0') return 1;
+			while ((*ptr >= '0' && *ptr <= '9') || *ptr == '.') { 
+				ptr++;
+			}
+			if (*ptr == '\0') return 1;
+			if (*ptr == 'l') {
+				ptr++;
+				if (*ptr == '\0') return 1;
+				if (*ptr == 'e' || *ptr == 'f') { 
+					ptr++; 
+					} else { return 1; }
+			}
+			else if (*ptr == 's' || *ptr == 'S' || *ptr == '%') { ++ptr; }
+			else { return 1; }
+		} else {
+			++ptr;
+		}
+	}
+	return 0;
+}
 

Modified: trunk/orca/packages/rrdtool-1.0.13/src/rrd_resize.c
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/src/rrd_resize.c	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/src/rrd_resize.c	Sat Jul 13 21:07:58 2002
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool  Copyright Tobias Oetiker, 1997, 1998, 1999
+ * RRDtool 1.0.13  Copyright Tobias Oetiker, 1997, 1998, 1999
  *****************************************************************************
  * rrd_resize.c Alters size of an RRA
  *****************************************************************************

Modified: trunk/orca/packages/rrdtool-1.0.13/src/rrd_cgi.c
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/src/rrd_cgi.c	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/src/rrd_cgi.c	Sat Jul 13 21:07:58 2002
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool  Copyright Tobias Oetiker, 1997, 1998, 1999
+ * RRDtool 1.0.13  Copyright Tobias Oetiker, 1997, 1998, 1999
  *****************************************************************************
  * rrd_cgi.c  RRD Web Page Generator
  *****************************************************************************/
@@ -38,16 +38,26 @@
 /* return PRINT functions from last rrd_graph call */
 char* drawprint(long, char **);
 
+/* pretty-print the <last></last> value for some.rrd via strftime() */
+char* printtimelast(long, char **);
+
+/* pretty-print current time */
+char* printtimenow(long,char **);
+
 /* set an evironment variable */
 char* rrdsetenv(long, char **);
 
 /* include the named file at this point */
 char* includefile(long, char **);
 
+/* for how long is the output of the cgi valid ? */
+char* rrdgoodfor(long, char **);
+
 /** http protocol needs special format, and GMT time **/
 char *http_time(time_t *);
 
 
+static long goodfor=0;
 static char **calcpr=NULL;
 static void calfree (void){
   if (calcpr) {
@@ -65,38 +75,38 @@
   strcpy(nstr,str);
   return(nstr);
 }
+
 int main(int argc, char *argv[]) {
   long length;
   char *buffer;
   char *server_url = NULL;
   long i;
-  long goodfor=0;
   long filter=0;
-  long refresh=0;
+#ifdef MUST_DISABLE_SIGFPE
+  signal(SIGFPE,SIG_IGN);
+#endif
+#ifdef MUST_DISABLE_FPMASK
+  fpsetmask(0);
+#endif
+  /* what do we get for cmdline arguments?
+  for (i=0;i<argc;i++)
+  printf("%d-'%s'\n",i,argv[i]); */
   while (1){
       static struct option long_options[] =
       {
-	  {"goodfor",        required_argument, 0, 'g'},
 	  {"filter",          no_argument, 0, 'f'},
-	  {"refresh",        no_argument, 0, 'r'},
 	  {0,0,0,0}
       };
       int option_index = 0;
       int opt;
-      opt = getopt_long(argc, argv, "g:fr", 
+      opt = getopt_long(argc, argv, "f", 
 			long_options, &option_index);
       if (opt == EOF)
 	  break;
       switch(opt) {
-      case 'g': 
-	  goodfor=atol(optarg);
-	  break;
       case 'f':
 	  filter=1;
 	  break;
-	  case 'r':
-	  refresh=1;
-	  break;
       case '?':
             printf("unknown commandline option '%s'\n",argv[optind-1]);
             return -1;
@@ -108,18 +118,20 @@
       cgiArg = cgiInit ();
       server_url = getenv("SERVER_URL");
   }
+
   if (optind != argc-1) { 
-      fprintf (stderr, "Command line error. Expected Input file name! %d\n",optind);
-      exit(1);
+     fprintf(stderr, "ERROR: expected a filename\n");
+     exit(1);
+  } else {
+     length  = readfile(argv[optind], &buffer, 1);
   }
-
-  length  = readfile(argv[optind], &buffer, 1);
-
+   
   if(rrd_test_error()){
       fprintf(stderr, "ERROR: %s\n",rrd_get_error());
       exit(1);
   }
 
+
   if(filter==0) {
   /* pass 1 makes only sense in cgi mode */
       for (i=0;buffer[i] != '\0'; i++){    
@@ -131,12 +143,15 @@
 
   /* pass 2 */
   for (i=0;buffer[i] != '\0'; i++){    
+      i +=parse(&buffer,i,"<RRD::GOODFOR ",rrdgoodfor);
+      i += parse(&buffer,i,"<RRD::SETENV ",rrdsetenv);
       i += parse(&buffer,i,"<RRD::INCLUDE ",includefile);
+      i += parse(&buffer,i,"<RRD::TIME::LAST ",printtimelast);
+      i += parse(&buffer,i,"<RRD::TIME::NOW ",printtimenow);
   }
 
   /* pass 3 */
   for (i=0;buffer[i] != '\0'; i++){    
-    i += parse(&buffer,i,"<RRD::SETENV ",rrdsetenv);
     i += parse(&buffer,i,"<RRD::GRAPH ",drawgraph);
     i += parse(&buffer,i,"<RRD::PRINT ",drawprint);
   }
@@ -144,14 +159,14 @@
   if (filter==0){
       printf ("Content-Type: text/html\n"
 	      "Content-Length: %d\n", strlen(buffer));
-      if (goodfor > 0){
+      if (labs(goodfor) > 0){
 		  time_t now;
 		  now = time(NULL);
 		  printf ("Last-Modified: %s\n",http_time(&now));
-		  now += goodfor;
+		  now += labs(goodfor);
 		  printf ("Expires: %s\n",http_time(&now));
-		  if (refresh) {
-			printf("Refresh: %ld\n", goodfor);
+	          if (goodfor < 0) {
+ 	            printf("Refresh: %ld\n", labs(goodfor));
 		  }
       }
       printf ("\n");
@@ -181,6 +196,20 @@
   return stralloc("");
 }
 
+char* rrdgoodfor(long argc, char **args){
+  if (argc == 1) {
+      goodfor = atol(args[0]);
+  } else {
+    return stralloc("[ERROR: goodfor expected 1 argument]");
+  }
+   
+  if (goodfor == 0){
+     return stralloc("[ERROR: goodfor value must not be 0]");
+  }
+   
+  return stralloc("");
+}
+
 char* includefile(long argc, char **args){
   char *buffer;
   if (argc >= 1) {
@@ -332,15 +361,60 @@
 }
 
 char* drawprint(long argc, char **args){
-  if (argc>=1 && calcpr != NULL){
+  if (argc==1 && calcpr){
     long i=0;
     while (calcpr[i] != NULL) i++; /*determine number lines in calcpr*/
     if (atol(args[0])<i-1)
-      return calcpr[atol(args[0])+1];    
+      return stralloc(calcpr[atol(args[0])+1]);    
   }
   return stralloc("[ERROR: RRD::PRINT argument error]");
 }
 
+char* printtimelast(long argc, char **args) {
+  time_t last;
+  struct tm tm_last;
+  char *buf;
+  if ( argc == 2 ) {
+    buf = malloc(255);
+    if (buf == NULL){	
+	return stralloc("[ERROR: allocating strftime buffer]");
+    };
+    last = rrd_last(argc+1, args-1); 
+    if (rrd_test_error()) {
+      char *err = malloc((strlen(rrd_get_error())+20)*sizeof(char));
+      sprintf(err, "[ERROR: %s]",rrd_get_error());
+      rrd_clear_error();
+      return err;
+    }
+    tm_last = *localtime(&last);
+    strftime(buf,254,args[1],&tm_last);
+    return buf;
+  }
+  if ( argc < 2 ) {
+    return stralloc("[ERROR: too few arguments for RRD::TIME::LAST]");
+  }
+  return stralloc("[ERROR: not enough arguments for RRD::TIME::LAST]");
+}
+
+char* printtimenow(long argc, char **args) {
+  time_t now = time(NULL);
+  struct tm tm_now;
+  char *buf;
+  if ( argc == 1 ) {
+    buf = malloc(255);
+    if (buf == NULL){	
+	return stralloc("[ERROR: allocating strftime buffer]");
+    };
+    tm_now = *localtime(&now);
+    strftime(buf,254,args[0],&tm_now);
+    return buf;
+  }
+  if ( argc < 1 ) {
+    return stralloc("[ERROR: too few arguments for RRD::TIME::NOW]");
+  }
+  return stralloc("[ERROR: not enough arguments for RRD::TIME::NOW]");
+}
+
 /* scan aLine until an unescaped '>' arives */
 char* scanargs(char *aLine, long *argc, char ***args)
 {
@@ -470,7 +544,7 @@
   memmove ((*buf)+i+valln,end,strlen(end)+1);
   if (val != NULL ) memmove ((*buf)+i,val, valln);
   free(val);
-  return valln;
+  return valln > 0 ? valln-1: valln;
 }
 
 char *

Modified: trunk/orca/packages/rrdtool-1.0.13/src/rrd_create.c
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/src/rrd_create.c	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/src/rrd_create.c	Sat Jul 13 21:07:58 2002
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool  Copyright Tobias Oetiker, 1997, 1998, 1999
+ * RRDtool 1.0.13  Copyright Tobias Oetiker, 1997, 1998, 1999
  *****************************************************************************
  * rrd_create.c  creates new rrds
  *****************************************************************************/
@@ -62,7 +62,7 @@
 	switch(opt) {
 	case 'b':
             if ((parsetime_error = parsetime(optarg, &last_up_tv))) {
-                rrd_set_error("last update time: %s", parsetime_error );
+                rrd_set_error("start time: %s", parsetime_error );
 		rrd_free(&rrd);
                 return(-1);
 	    }
@@ -94,7 +94,10 @@
 	    break;
 
 	case '?':
-	    rrd_set_error("unknown option '%s'",argv[optind-1]);
+            if (optopt != 0)
+                rrd_set_error("unknown option '%c'", optopt);
+            else
+                rrd_set_error("unknown option '%s'",argv[optind-1]);
             rrd_free(&rrd);
 	    return(-1);
 	}
@@ -103,6 +106,7 @@
 
     for(i=optind+1;i<argc;i++){
 	char minstr[20], maxstr[20];	
+	int ii;
 	if (strncmp(argv[i],"DS:",3)==0){
 	    size_t old_size = sizeof(ds_def_t)*(rrd.stat_head->ds_cnt);
 	    if((rrd.ds_def = rrd_realloc(rrd.ds_def,
@@ -118,6 +122,15 @@
 		       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){
+		/* check for duplicate datasource names */
+		for(ii=0;ii<rrd.stat_head->ds_cnt;ii++){
+			if(strcmp(rrd.ds_def[rrd.stat_head->ds_cnt].ds_nam,
+			  	  rrd.ds_def[ii].ds_nam) == 0){
+				rrd_set_error("Duplicate DS name: %s",rrd.ds_def[ii].ds_nam);
+		                rrd_free(&rrd);
+                                return(-1);
+			}				                                
+		}
 		if(dst_conv(rrd.ds_def[rrd.stat_head->ds_cnt].dst) == -1){
 		    rrd_free(&rrd);
 		    return (-1);

Modified: trunk/orca/packages/rrdtool-1.0.13/src/rrd_last.c
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/src/rrd_last.c	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/src/rrd_last.c	Sat Jul 13 21:07:59 2002
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool  Copyright Tobias Oetiker, 1997, 1998, 1999
+ * RRDtool 1.0.13  Copyright Tobias Oetiker, 1997, 1998, 1999
  *****************************************************************************
  * rrd_last.c
  *****************************************************************************

Modified: trunk/orca/packages/rrdtool-1.0.13/src/ntconfig.h
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/src/ntconfig.h	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/src/ntconfig.h	Sat Jul 13 21:07:59 2002
@@ -8,3 +8,4 @@
 /* Define if you have the <math.h> header file.  */
 #define HAVE_MATH_H 1
 
+#define rrd_realloc(a,b) realloc((a), (b))

Modified: trunk/orca/packages/rrdtool-1.0.13/src/rrd_dump.c
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/src/rrd_dump.c	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/src/rrd_dump.c	Sat Jul 13 21:07:59 2002
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool  Copyright Tobias Oetiker, 1997, 1998, 1999
+ * RRDtool 1.0.13  Copyright Tobias Oetiker, 1997, 1998, 1999
  *****************************************************************************
  * rrd_dump  Display a RRD
  *****************************************************************************

Modified: trunk/orca/packages/rrdtool-1.0.13/src/pngsize.c
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/src/pngsize.c	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/src/pngsize.c	Sat Jul 13 21:07:59 2002
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool  Copyright Tobias Oetiker, 1997, 1998, 1999
+ * RRDtool 1.0.13  Copyright Tobias Oetiker, 1997, 1998, 1999
  *****************************************************************************
  * pngsize.c  determine the size of a PNG image
  *****************************************************************************/

Modified: trunk/orca/packages/rrdtool-1.0.13/src/rrd_diff.c
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/src/rrd_diff.c	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/src/rrd_diff.c	Sat Jul 13 21:07:59 2002
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool  Copyright Tobias Oetiker, 1999
+ * RRDtool 1.0.13  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

Modified: trunk/orca/packages/rrdtool-1.0.13/src/rrd_tune.c
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/src/rrd_tune.c	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/src/rrd_tune.c	Sat Jul 13 21:07:59 2002
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool  Copyright Tobias Oetiker, 1997, 1998, 1999
+ * RRDtool 1.0.13  Copyright Tobias Oetiker, 1997, 1998, 1999
  *****************************************************************************
  * change header parameters of an rrd
  *****************************************************************************
@@ -132,7 +132,10 @@
 	    rrd.ds_def[ds].ds_nam[DS_NAM_SIZE-1]='\0';
 	    break;
 	case '?':
-            rrd_set_error("unknown option '%s'",argv[optind-1]);
+            if (optopt != 0)
+                rrd_set_error("unknown option '%c'", optopt);
+            else
+                rrd_set_error("unknown option '%s'",argv[optind-1]);
 	    rrd_free(&rrd);	    
             return -1;
         }

Modified: trunk/orca/packages/rrdtool-1.0.13/src/rrd_tool.c
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/src/rrd_tool.c	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/src/rrd_tool.c	Sat Jul 13 21:07:59 2002
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool  Copyright Tobias Oetiker, 1997, 1998, 1999
+ * RRDtool 1.0.13  Copyright Tobias Oetiker, 1997, 1998, 1999
  *****************************************************************************
  * rrd_tool.c  Startup wrapper
  *****************************************************************************
@@ -21,7 +21,7 @@
 void PrintUsage(void)
 {
     printf("\n"
-	   "RRDtool   Copyright (C) 1999 by Tobias Oetiker <tobi at oetiker.ch>\n\n"
+	   "RRDtool 1.0.13  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"
 
@@ -202,12 +202,12 @@
 	    datai=data;
 	    printf("           ");
 	    for (i = 0; i<ds_cnt;i++)
-	        printf("%10s",ds_namv[i]);
+	        printf("%14s",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(" %13.2f", *(datai++));
 	        printf("\n");
 	    }
 	    for (i=0;i<ds_cnt;i++)

Modified: trunk/orca/packages/rrdtool-1.0.13/src/parsetime.c
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/src/parsetime.c	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/src/parsetime.c	Sat Jul 13 21:08:00 2002
@@ -296,8 +296,11 @@
 static char *
 ve ( char *fmt, va_list ap )
 {
-/* vsnprintf( errmsg, MAX_ERR_MSG_LEN, fmt, ap ); */
+#ifdef HAVE_VSNPRINTF
+  vsnprintf( errmsg, MAX_ERR_MSG_LEN, fmt, ap );
+#else
   vsprintf( errmsg, fmt, ap );
+#endif
   EnsureMemFree();
   return( errmsg );
 }

Modified: trunk/orca/packages/rrdtool-1.0.13/src/rrd_tool.h
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/src/rrd_tool.h	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/src/rrd_tool.h	Sat Jul 13 21:08:00 2002
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool  Copyright Tobias Oetiker, 1997,1998, 1999
+ * RRDtool 1.0.13  Copyright Tobias Oetiker, 1997,1998, 1999
  *****************************************************************************
  * rrd_tool.h   Common Header File
  *****************************************************************************
@@ -37,6 +37,14 @@
 #include <time.h>
 #include <ctype.h>
 
+#if HAVE_SYS_PARAM_H
+#  include <sys/param.h>
+#endif
+
+#ifndef MAXPATH
+#  define MAXPATH 1024
+#endif
+
 #if HAVE_MATH_H
 # include <math.h>
 #endif

Modified: trunk/orca/packages/rrdtool-1.0.13/src/rrd_update.c
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/src/rrd_update.c	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/src/rrd_update.c	Sat Jul 13 21:08:00 2002
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool  Copyright Tobias Oetiker, 1997, 1998, 1999
+ * RRDtool 1.0.13  Copyright Tobias Oetiker, 1997, 1998, 1999
  *****************************************************************************
  * rrd_update.c  RRD Update Function
  *****************************************************************************
@@ -109,7 +109,18 @@
 	return -1;
     }
     rra_current = rra_start = rra_begin = ftell(rrd_file);
+    /* This is defined in the ANSI C standard, section 7.9.5.3:
 
+        When a file is opened with udpate mode ('+' as the second
+        or third character in the ... list of mode argument
+        variables), both input and ouptut may be performed on the
+        associated stream.  However, ...  input may not be directly
+        followed by output without an intervening call to a file
+        positioning function, unless the input oepration encounters
+        end-of-file. */
+    fseek(rrd_file, 0, SEEK_CUR);
+
+    
     /* get exclusive lock to whole file.
      * lock gets removed when we close the file.
      */
@@ -138,7 +149,7 @@
 
     if ((tmpl_idx = malloc(sizeof(unsigned long)
 			   *(rrd.stat_head->ds_cnt+1)))==NULL){
-	rrd_set_error("allocating template_idx ...");
+	rrd_set_error("allocating tmpl_idx ...");
 	free(pdp_temp);
 	free(updvals);
 	rrd_free(&rrd);
@@ -146,35 +157,41 @@
 	return(-1);
     }
     /* initialize template redirector */
-
-    /* the first entry [0] points to zero as the first entry in an
-       update argument is always the time. The remaining entries point
-       the the index number of their respective datasource. */
+    /* default config
+       tmpl_idx[0] -> 0; (time)
+       tmpl_idx[1] -> 1; (DS 0)
+       tmpl_idx[2] -> 2; (DS 1)
+       tmpl_idx[3] -> 3; (DS 2)
+       ... */
     for (i=0;i<=rrd.stat_head->ds_cnt;i++) tmpl_idx[i]=i;
     tmpl_cnt=rrd.stat_head->ds_cnt+1;
     if (template) {
 	char *dsname;
 	int tmpl_len;
 	dsname = template;
-	template++;
 	tmpl_cnt = 1; /* the first entry is the time */
 	tmpl_len = strlen(template);
-	for(i=0;i<=tmpl_len;i++) {
+	for(i=0;i<=tmpl_len ;i++) {
 	    if (template[i] == ':' || template[i] == '\0') {
 		template[i] = '\0';
+		if (tmpl_cnt>rrd.stat_head->ds_cnt){
+  		    rrd_set_error("Template contains more DS definitions than RRD");
+		    free(updvals); free(pdp_temp);
+		    free(tmpl_idx); rrd_free(&rrd);
+		    fclose(rrd_file); return(-1);
+		}
 		if ((tmpl_idx[tmpl_cnt++] = ds_match(&rrd,dsname)) == -1){
+  		    rrd_set_error("unknown DS name '%s'",dsname);
 		    free(updvals); free(pdp_temp);
 		    free(tmpl_idx); rrd_free(&rrd);
 		    fclose(rrd_file); return(-1);
+		} else {
+		  /* the first element is always the time */
+		  tmpl_idx[tmpl_cnt-1]++; 
+		  /* go to the next entry on the template */
+		  dsname = &template[i+1];
 		}
-		/* the first element is always the time */
-		tmpl_idx[tmpl_cnt-1]++; 
-
-		/* go to the next entry on the template */
-	        dsname = &template[i+1];
-
 	    }	    
-
 	}
     }
     if ((pdp_new = malloc(sizeof(rrd_value_t)
@@ -190,7 +207,7 @@
 
     /* loop through the arguments. */
     for(arg_i=optind+1; arg_i<argc;arg_i++) {
-	char *stepper;;
+	char *stepper;
 	/* 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";
@@ -208,7 +225,7 @@
 	    stepper++;
 	}
 
-	if (ii+1 != tmpl_cnt) {
+	if (ii != tmpl_cnt-1) {
 	    rrd_set_error("expected %lu data source readings (got %lu) from %s:...",
 			  tmpl_cnt-1, ii, argv[arg_i]);
 	    break;
@@ -279,7 +296,8 @@
 	    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 */
+	       double rate = DNAN;
+	       /* 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 */
@@ -289,25 +307,29 @@
 		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 */;
-			}
+		       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 */;
+		       }
+		       rate = pdp_new[i] / interval;
 		    }
-			else
-			    pdp_new[i]= DNAN;		
-		    break;
+		   else {
+		     pdp_new[i]= DNAN;		
+		   }
+		   break;
 		case DST_ABSOLUTE:
-		    pdp_new[i]= atof(updvals[i+1]);		
+		    pdp_new[i]= atof(updvals[i+1]);
+		    rate = pdp_new[i] / interval;		  
 		    break;
 		case DST_GAUGE:
 		    pdp_new[i] = atof(updvals[i+1]) * interval;
+		    rate = pdp_new[i] / interval;		   
 		    break;
 		default:
 		    rrd_set_error("rrd contains and DS type : '%s'",
@@ -315,8 +337,19 @@
 		    break;
 		}
 		/* break out of this for loop if the error string is set */
-		if (rrd_test_error())
+		if (rrd_test_error()){
 		    break;
+		}
+	       /* make sure pdp_temp is neither too large or too small
+		* if any of these occur it becomes unknown ...
+		* sorry folks ... */
+	       if ( ! isnan(rate) && 
+	            (( ! isnan(rrd.ds_def[i].par[DS_max_val].u_val) &&
+	                 rate > rrd.ds_def[i].par[DS_max_val].u_val ) ||     
+	            ( ! isnan(rrd.ds_def[i].par[DS_min_val].u_val) &&
+	                rate < rrd.ds_def[i].par[DS_min_val].u_val ))){
+		  pdp_new[i] = DNAN;
+	       }	       
 	    } else {
 		/* no news is news all the same */
 		pdp_new[i] = DNAN;
@@ -401,16 +434,7 @@
 		    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"

Modified: trunk/orca/packages/rrdtool-1.0.13/src/rrd_restore.c
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/src/rrd_restore.c	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/src/rrd_restore.c	Sat Jul 13 21:08:00 2002
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool  Copyright Tobias Oetiker, 1997, 1998, 1999
+ * RRDtool 1.0.13  Copyright Tobias Oetiker, 1997, 1998, 1999, 2000
  *****************************************************************************
  * rrd_restore.c  creates new rrd from data dumped by rrd_dump.c
  *****************************************************************************/

Modified: trunk/orca/packages/rrdtool-1.0.13/cgilib-0.4/Makefile.in
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/cgilib-0.4/Makefile.in	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/cgilib-0.4/Makefile.in	Sat Jul 13 21:08:00 2002
@@ -111,7 +111,7 @@
 
 DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
 
-TAR = tar
+TAR = gtar
 GZIP_ENV = --best
 SOURCES = $(librrd_cgi_la_SOURCES)
 OBJECTS = $(librrd_cgi_la_OBJECTS)

Modified: trunk/orca/packages/rrdtool-1.0.13/CONTRIBUTORS
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/CONTRIBUTORS	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/CONTRIBUTORS	Sat Jul 13 21:08:00 2002
@@ -1,5 +1,5 @@
 I would like to thank to following people for helping to
-bring mrtg 3.0 into existence.
+bring RRDTool into existence.
 
 Planning and Inspiration
 
@@ -11,22 +11,33 @@
 
 	Andreas Kroomaa <andre at ml.ee>
 	Andrew Turner <turner at mint.net> (LAST consolidator)
+	Bill Fenner <fenner at research.att.com>
 	Blair Zajac <bzajac at geostaff.com>
 	Dan Dunn <dandunn at computer.org>
 	Hermann Hueni <hueni at glue.ch> (SunOS porting)
 	Jeff R. Allen <jeff.allen at acm.org> (autoconfigure, portability)  
 	Jost.Krieger <Jost.Krieger at ruhr-uni-bochum.de>
+	Larry Leszczynski <larryl at furph.com>
 	Otmar Lendl <O.Lendl at Austria.EU.net> (lots of bugfixes)
+	Paul Joslin <Paul.Joslin at sdrc.com>
 	Philippe.Simonet <Philippe.Simonet at swisscom.com> (NT porting)
 	Russ Wright <rwwright at home.com>
 	Simon Leinen <simon at switch.ch>
-	Wrolf Courtney <wrolf at concentric.net> (HP-UX)
+	Wrolf Courtney <wrolf at wrolf.net> (HP-UX)
         Alan Lichty <alan_lichty at eli.net>
         Alex van den Bogaerdt <alex at ergens.op.het.net> (rrd_resize.c and more)
         Jeremy Fischer <jeremy at pobox.com> (Makefile changes & RPM builds)
         Oleg Cherevko <olwi at icyb.kiev.ua>
         Steen Linden <Steen.Linden at ebone.net>
         Tom Crawley <Tom.Crawley at hi.riotinto.com.au> (GCC&HP configuration)
+	Steve Rader <rader at teak.wiscnet.net> (rrd_cgi debugging and LAST)
+        Steve Harris <steveh at wesley.com.au> AIX portability
+	Stefan Mueller <s.mueller at computer.org> HPUX 11
+	Ulrich Schilling <schilling at netz.uni-essen.de> AIX
+	Joel Becker <jlbec at raleigh.ibm.com> AIX
+	REIBENSCHUH Alfred <alfred.reibenschuh at it-austria.com> AIX
+        Selena M Brewington <smbrewin at ichips.intel.com> add_ds
+	Larry Leszczynski <larryl at furph.com>
 
 Documentation
 
@@ -35,8 +46,15 @@
         Amos Shapira <amos at gezernet.co.il>
         Kai Siering <kai.siering at mediaways.net>
         Russ Wright <rwwright at home.com>
-        Wrolf Courtney <wrolf at concentric.net>      
+	Steve Rader <rader at teak.wiscnet.net>  
+        Wrolf Courtney <wrolf at wrolf.net>      
 	Tobias Weingartner <weingart at cs.ualberta.ca>
+	hendrik visage <hvisage at is.co.za>
+	Steve Rader <rader at teak.wiscnet.net>
+
+Packaging
+        Henri GOMEZ -- Redhat RPMs
+        Philippe Simonet -- NT Binaries
 
 Internet Resources
         LAN Services AG (www.lan.ch) for the http://rrdtool.eu.org domain reflector

Modified: trunk/orca/packages/rrdtool-1.0.13/README
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/README	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/README	Sat Jul 13 21:08:01 2002
@@ -54,8 +54,8 @@
 RRDtool. All documents are available as html and as ASCII text.  
 
 If you are looking for a more slow paced introduction, make sure to read
-Alex van den Bogaerdts rrdintro which is also available from the doc
-directory.
+Alex van den Bogaerdt's rrdtutorial which is also available from the doc
+directory. Also read his cdeftutorial and Steve Rader's rpntutorial.
  
 If you want to know about the format of the log files check
 src/rrd_format.h there are a lot of comments in there ...
@@ -64,7 +64,7 @@
 -----------------------
 
 If you want to show your appreciation for RRDtool you could make me happy
-by going to www.cdnow.com/gift/oetiker at ee.ethz.ch and getting me a CD from
+by going to ee-staff.ethz.ch/~oetiker/wish and ordering a CD from
 my CD wish list ... 
 
 

Modified: trunk/orca/packages/rrdtool-1.0.13/zlib-1.1.3/Makefile.in
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/zlib-1.1.3/Makefile.in	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/zlib-1.1.3/Makefile.in	Sat Jul 13 21:08:01 2002
@@ -114,7 +114,7 @@
 
 DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
 
-TAR = tar
+TAR = gtar
 GZIP_ENV = --best
 SOURCES = $(librrd_z_la_SOURCES)
 OBJECTS = $(librrd_z_la_OBJECTS)

Modified: trunk/orca/packages/rrdtool-1.0.13/zlib-1.1.3/zconf.h
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/zlib-1.1.3/zconf.h	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/zlib-1.1.3/zconf.h	Sat Jul 13 21:08:01 2002
@@ -71,6 +71,9 @@
 #  define UNALIGNED_OK
 #endif
 
+/* RRDtool will not compile without them anyway */
+#define STDC
+
 #if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32))  && !defined(STDC)
 #  define STDC
 #endif

Modified: trunk/orca/packages/rrdtool-1.0.13/contrib/Makefile.in
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/contrib/Makefile.in	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/contrib/Makefile.in	Sat Jul 13 21:08:02 2002
@@ -75,7 +75,7 @@
 RANLIB = @RANLIB@
 ZLIB_LIB_DIR = @ZLIB_LIB_DIR@
 
-SUBDIRS = log2rrd rrd-file-icon trytime
+SUBDIRS = log2rrd rrd-file-icon trytime rrdproc rrdlastds add_ds killspike rrdfetchnames
 
 contribdir = $(prefix)/contrib
 contrib_DATA = README
@@ -92,7 +92,7 @@
 
 DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
 
-TAR = tar
+TAR = gtar
 GZIP_ENV = --best
 all: all-redirect
 .SUFFIXES:

Added: trunk/orca/packages/rrdtool-1.0.13/contrib/rrdlastds/rrdlastds.pl.in
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/contrib/rrdlastds/rrdlastds.pl.in	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/contrib/rrdlastds/rrdlastds.pl.in	Sat Jul 13 21:08:02 2002
@@ -0,0 +1,192 @@
+#! @PERL@
+#
+# rrdlastds - report the latest DS values from the RRA with
+# the shortest time resolution
+#
+# steve rader
+# <rader at wiscnet.net>
+# Jan 8th, 2000
+#
+# $Id: rrdlastds.in,v 1.15 2000/01/27 21:35:16 rader Exp $
+#
+
+#makes things work when run without install
+use lib qw( ../../perl-shared/blib/lib ../../perl-shared/blib/arch );
+# this is for after install
+use lib qw( @prefix@/lib/perl ../lib/perl );
+
+use RRDs;
+
+%scale_symbols = qw( -18 a -15 f -12 p -9 n -6 u -3 m 
+  3 k 6 M 9 G 12 T 15 P 18 E );
+
+#----------------------------------------
+
+while ( $ARGV[0] =~ /^-/ ) {
+  switch: {
+    if ( $ARGV[0] eq '--autoscale' || $ARGV[0] =~ /^-a/ ) {
+      $scale = 1;
+      last switch;
+    }
+    if ( $ARGV[0] eq '--conversion' || $ARGV[0] =~ /^-c/ ) {
+      shift @ARGV;
+      $conversion = $ARGV[0];
+      if ( $conversion !~ /^\d+$|^\d+\.\d+$|^\.\d+$/ ) {
+        print "rrdlastds: bad conversion factor \"$conversion\"\n";
+        exit 1;
+      }
+      last switch;
+    }
+    if ( $ARGV[0] eq '--label' || $ARGV[0] =~ /^-l/ ) {
+      shift @ARGV;
+      $label = $ARGV[0];
+      last switch;
+    }
+    if ( $ARGV[0] eq '--start' || $ARGV[0] =~ /^-s/ ) {
+      shift @ARGV;
+      $start = $ARGV[0]; 
+      if ( $start =~ /^\d+$/ ) {
+        $end = $start+1;
+      } else {
+        $end = "${start}+1sec";
+      }
+      last switch;
+    }
+    if ( $ARGV[0] eq '--verbose' || $ARGV[0] =~ /^-v/ ) {
+      $verbose = 1;
+      last switch;
+    }
+    if ( $ARGV[0] eq '--debug' || $ARGV[0] =~ /^-d/ ) {
+      $debug = 1;
+      last switch;
+    }
+    print "rrdlastds: unknown option \"$ARGV[0]\"\n";
+    exit 1;
+  }
+  shift @ARGV;
+}
+
+if ( $#ARGV != 0 ) {
+  print <<_EOT_;
+usage: rrdlastds [-v] [-a] [-c num] [-l label] [-s stamp] some.rrd
+  -v        print the start and end times (also --verbose)
+  -a        autoscale DS values (also --autoscale)
+  -c num    convert DS values by "num" (also --conversion)
+  -l label  label DS values with "label" (also --label)
+  -s time   report about DS values at the time "time" (also --start)
+
+  The -s option supports the traditional "seconds since the Unix epoch"
+  and the AT-STYLE time specification (see man rrdfetch)
+_EOT_
+  exit 1;
+}
+
+if ( ! -f "$ARGV[0]" ) {
+  print "rrdlastds: can't find \"$ARGV[0]\"\n";
+  exit 1;
+} 
+
+#----------------------------------------
+
+if ( $start ) {
+  @fetch = ("$ARGV[0]", "-s", "$start", "-e", "$end", "AVERAGE");
+} else {
+  @fetch = ("$ARGV[0]", "-s", "-1sec", "AVERAGE");
+}
+if ( $debug ) {
+  print "rrdfetch ", join(' ', at fetch), "\n";
+}
+
+($start,$step,$names,$data) = RRDs::fetch @fetch;
+
+if ( $error = RRDs::error ) {
+  print "rrdlastds: rrdtool fetch failed: \"$error\"\n";
+  exit 1;
+}
+
+#----------------------------------------
+
+if ( $debug ) {
+  $d_start = $start;
+  print "Start:       ", scalar localtime($d_start), " ($d_start)\n";
+  print "Step size:   $step seconds\n";
+  print "DS names:    ", join (", ", @$names)."\n";
+  print "Data points: ", $#$data + 1, "\n";
+  print "Data:\n";
+  foreach $line (@$data) {
+    print "  ", scalar localtime($d_start), " ($d_start) ";
+    $d_start += $step;
+    foreach $val (@$line) {
+      printf "%12.1f ", $val;
+    }
+    print "\n";
+  }
+  print "\n";
+}
+   
+#----------------------------------------
+
+if ( $verbose ) {
+  print scalar localtime($start), ' through ', 
+    scalar localtime($start+$step), "\naverage";
+} else {
+  print scalar localtime($start);
+}
+
+$line = $$data[0];
+for $i (0 .. $#$names) {
+  if ( $conversion ) {
+    $$line[$i] = $$line[$i] * $conversion;
+  }
+  if ( $scale ) {
+    ($val, $units) = autoscale($$line[$i]);
+  } else {
+    $val = $$line[$i];
+  }
+  printf "  %.2f$units$label %s", $val, $$names[$i];
+}
+print "\n";
+
+exit 0;
+
+#==================================================================
+
+sub autoscale {
+  local($value) = @_;
+  local($floor, $mag, $index, $symbol, $new_value);
+
+  if ( $value =~ /^\s*[0]+\s*$/ || 
+       $value =~ /^\s*[0]+.[0]+\s*$/ || 
+       $value =~ /^\s*NaN\s*$/ ) {
+    return $value, ' ';
+  }
+
+  $floor = &floor($value);
+  $mag = int($floor/3);
+  $index = $mag * 3;
+  $symbol = $scale_symbols{$index};
+  $new_value = $value / (10 ** $index);
+  return $new_value, " $symbol";
+}
+
+#------------------------------------------------------------------
+
+sub floor {
+  local($value) = @_;
+  local($i) = 0;
+
+  if ( $value > 1.0 ) {
+    # scale downward...
+    while ( $value > 10.0 ) {
+      $i++;
+      $value /= 10.0;
+    }
+  } else {
+    while ( $value < 10.0 ) {
+      $i--;
+      $value *= 10.0;
+    }
+  }
+  return $i;
+}
+

Added: trunk/orca/packages/rrdtool-1.0.13/contrib/rrdlastds/Makefile.in
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/contrib/rrdlastds/Makefile.in	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/contrib/rrdlastds/Makefile.in	Sat Jul 13 21:08:02 2002
@@ -0,0 +1,234 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ../..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_alias = @build_alias@
+build_triplet = @build@
+host_alias = @host_alias@
+host_triplet = @host@
+target_alias = @target_alias@
+target_triplet = @target@
+CC = @CC@
+CFLAGS = @CFLAGS@
+CGI_LIB_DIR = @CGI_LIB_DIR@
+COMP_PERL = @COMP_PERL@
+CPP = @CPP@
+GD_LIB_DIR = @GD_LIB_DIR@
+LIBTOOL = @LIBTOOL@
+PERL = @PERL@
+PNG_LIB_DIR = @PNG_LIB_DIR@
+RANLIB = @RANLIB@
+ZLIB_LIB_DIR = @ZLIB_LIB_DIR@
+
+EXTRA_DIST = rrdlastds.pl.in
+
+contribdir = $(prefix)/contrib/rrdlastds
+contrib_DATA = README
+contrib_SCRIPTS = rrdlastds.pl
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = ../../config/config.h
+CONFIG_CLEAN_FILES =  rrdlastds.pl
+SCRIPTS =  $(contrib_SCRIPTS)
+
+DATA =  $(contrib_DATA)
+
+DIST_COMMON =  README Makefile.am Makefile.in rrdlastds.pl.in
+
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+all: all-redirect
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+	cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps contrib/rrdlastds/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+rrdlastds.pl: $(top_builddir)/config.status rrdlastds.pl.in
+	cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+install-contribSCRIPTS: $(contrib_SCRIPTS)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(contribdir)
+	@list='$(contrib_SCRIPTS)'; for p in $$list; do \
+	  if test -f $$p; then \
+	    echo " $(INSTALL_SCRIPT) $$p $(DESTDIR)$(contribdir)/`echo $$p|sed '$(transform)'`"; \
+	    $(INSTALL_SCRIPT) $$p $(DESTDIR)$(contribdir)/`echo $$p|sed '$(transform)'`; \
+	  else if test -f $(srcdir)/$$p; then \
+	    echo " $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(contribdir)/`echo $$p|sed '$(transform)'`"; \
+	    $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(contribdir)/`echo $$p|sed '$(transform)'`; \
+	  else :; fi; fi; \
+	done
+
+uninstall-contribSCRIPTS:
+	@$(NORMAL_UNINSTALL)
+	list='$(contrib_SCRIPTS)'; for p in $$list; do \
+	  rm -f $(DESTDIR)$(contribdir)/`echo $$p|sed '$(transform)'`; \
+	done
+
+install-contribDATA: $(contrib_DATA)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(contribdir)
+	@list='$(contrib_DATA)'; for p in $$list; do \
+	  if test -f $(srcdir)/$$p; then \
+	    echo " $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(contribdir)/$$p"; \
+	    $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(contribdir)/$$p; \
+	  else if test -f $$p; then \
+	    echo " $(INSTALL_DATA) $$p $(DESTDIR)$(contribdir)/$$p"; \
+	    $(INSTALL_DATA) $$p $(DESTDIR)$(contribdir)/$$p; \
+	  fi; fi; \
+	done
+
+uninstall-contribDATA:
+	@$(NORMAL_UNINSTALL)
+	list='$(contrib_DATA)'; for p in $$list; do \
+	  rm -f $(DESTDIR)$(contribdir)/$$p; \
+	done
+tags: TAGS
+TAGS:
+
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = contrib/rrdlastds
+
+distdir: $(DISTFILES)
+	@for file in $(DISTFILES); do \
+	  d=$(srcdir); \
+	  if test -d $$d/$$file; then \
+	    cp -pr $$/$$file $(distdir)/$$file; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+	    || cp -p $$d/$$file $(distdir)/$$file || :; \
+	  fi; \
+	done
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am: install-contribSCRIPTS install-contribDATA
+install-data: install-data-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-contribSCRIPTS uninstall-contribDATA
+uninstall: uninstall-am
+all-am: Makefile $(SCRIPTS) $(DATA)
+all-redirect: all-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+	$(mkinstalldirs)  $(DESTDIR)$(contribdir) $(DESTDIR)$(contribdir)
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+	-rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-generic clean-am
+	-rm -f libtool
+
+distclean: distclean-am
+
+maintainer-clean-am:  maintainer-clean-generic distclean-am
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: uninstall-contribSCRIPTS install-contribSCRIPTS \
+uninstall-contribDATA install-contribDATA tags distdir info-am info \
+dvi-am dvi check check-am installcheck-am installcheck install-exec-am \
+install-exec install-data-am install-data install-am install \
+uninstall-am uninstall all-redirect all-am all installdirs \
+mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: trunk/orca/packages/rrdtool-1.0.13/contrib/rrdlastds/Makefile.am
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/contrib/rrdlastds/Makefile.am	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/contrib/rrdlastds/Makefile.am	Sat Jul 13 21:08:02 2002
@@ -0,0 +1,7 @@
+## Process this file with automake to produce Makefile.in
+
+EXTRA_DIST = rrdlastds.pl.in
+
+contribdir = $(prefix)/contrib/rrdlastds
+contrib_DATA = README
+contrib_SCRIPTS = rrdlastds.pl

Added: trunk/orca/packages/rrdtool-1.0.13/contrib/rrdlastds/README
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/contrib/rrdlastds/README	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/contrib/rrdlastds/README	Sat Jul 13 21:08:02 2002
@@ -0,0 +1,29 @@
+From: steve rader <rader at teak.wiscnet.net>
+Date: Mon, 10 Jan 2000 10:40:56 -0600
+Subject: ANNOUNCEMENT: "rrdlastds" (was Re: rrd script assistance)
+
+ % ./rrdlastds 
+ usage: rrdlastds [-v] [-a] [-c num] [-l label] [-s stamp] some.rrd
+   -v        print the start and end times (also --verbose)
+   -a        autoscale DS values (also --autoscale)
+   -c num    convert DS values by "num" (also --conversion)
+   -l label  label DS values with "label" (also --label)
+   -s stamp  report about DS values at the time "stamp" (also --start)
+
+The nominal usage is:
+
+ % ./rrdlastds some.rrd
+ Mon Jan 10 10:30:00 2000  146823.19 input  17225.20 output
+
+To get a verbose, autoscaled report about this time yesterday,
+converted to bits and nicely labeled, do:
+
+ % ./rrdlastds -v -a -c 8 -l b/s -s -1day some.rrd
+ Sun Jan  9 10:30:00 2000 through Sun Jan  9 10:35:00 2000
+ average  105.27 kb/s input  17.10 kb/s output
+
+later
+steve
+- - -
+systems guy
+wiscnet.net

Added: trunk/orca/packages/rrdtool-1.0.13/contrib/rrdfetchnames/Makefile.in
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/contrib/rrdfetchnames/Makefile.in	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/contrib/rrdfetchnames/Makefile.in	Sat Jul 13 21:08:02 2002
@@ -0,0 +1,234 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ../..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_alias = @build_alias@
+build_triplet = @build@
+host_alias = @host_alias@
+host_triplet = @host@
+target_alias = @target_alias@
+target_triplet = @target@
+CC = @CC@
+CFLAGS = @CFLAGS@
+CGI_LIB_DIR = @CGI_LIB_DIR@
+COMP_PERL = @COMP_PERL@
+CPP = @CPP@
+GD_LIB_DIR = @GD_LIB_DIR@
+LIBTOOL = @LIBTOOL@
+PERL = @PERL@
+PNG_LIB_DIR = @PNG_LIB_DIR@
+RANLIB = @RANLIB@
+ZLIB_LIB_DIR = @ZLIB_LIB_DIR@
+
+EXTRA_DIST = rrdfetchnames.pl.in
+
+contribdir = $(prefix)/contrib/rrdfetchnames
+contrib_DATA = README
+contrib_SCRIPTS = rrdfetchnames.pl
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = ../../config/config.h
+CONFIG_CLEAN_FILES =  rrdfetchnames.pl
+SCRIPTS =  $(contrib_SCRIPTS)
+
+DATA =  $(contrib_DATA)
+
+DIST_COMMON =  README Makefile.am Makefile.in rrdfetchnames.pl.in
+
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+all: all-redirect
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+	cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps contrib/rrdfetchnames/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+rrdfetchnames.pl: $(top_builddir)/config.status rrdfetchnames.pl.in
+	cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+install-contribSCRIPTS: $(contrib_SCRIPTS)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(contribdir)
+	@list='$(contrib_SCRIPTS)'; for p in $$list; do \
+	  if test -f $$p; then \
+	    echo " $(INSTALL_SCRIPT) $$p $(DESTDIR)$(contribdir)/`echo $$p|sed '$(transform)'`"; \
+	    $(INSTALL_SCRIPT) $$p $(DESTDIR)$(contribdir)/`echo $$p|sed '$(transform)'`; \
+	  else if test -f $(srcdir)/$$p; then \
+	    echo " $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(contribdir)/`echo $$p|sed '$(transform)'`"; \
+	    $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(contribdir)/`echo $$p|sed '$(transform)'`; \
+	  else :; fi; fi; \
+	done
+
+uninstall-contribSCRIPTS:
+	@$(NORMAL_UNINSTALL)
+	list='$(contrib_SCRIPTS)'; for p in $$list; do \
+	  rm -f $(DESTDIR)$(contribdir)/`echo $$p|sed '$(transform)'`; \
+	done
+
+install-contribDATA: $(contrib_DATA)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(contribdir)
+	@list='$(contrib_DATA)'; for p in $$list; do \
+	  if test -f $(srcdir)/$$p; then \
+	    echo " $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(contribdir)/$$p"; \
+	    $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(contribdir)/$$p; \
+	  else if test -f $$p; then \
+	    echo " $(INSTALL_DATA) $$p $(DESTDIR)$(contribdir)/$$p"; \
+	    $(INSTALL_DATA) $$p $(DESTDIR)$(contribdir)/$$p; \
+	  fi; fi; \
+	done
+
+uninstall-contribDATA:
+	@$(NORMAL_UNINSTALL)
+	list='$(contrib_DATA)'; for p in $$list; do \
+	  rm -f $(DESTDIR)$(contribdir)/$$p; \
+	done
+tags: TAGS
+TAGS:
+
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = contrib/rrdfetchnames
+
+distdir: $(DISTFILES)
+	@for file in $(DISTFILES); do \
+	  d=$(srcdir); \
+	  if test -d $$d/$$file; then \
+	    cp -pr $$/$$file $(distdir)/$$file; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+	    || cp -p $$d/$$file $(distdir)/$$file || :; \
+	  fi; \
+	done
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am: install-contribSCRIPTS install-contribDATA
+install-data: install-data-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-contribSCRIPTS uninstall-contribDATA
+uninstall: uninstall-am
+all-am: Makefile $(SCRIPTS) $(DATA)
+all-redirect: all-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+	$(mkinstalldirs)  $(DESTDIR)$(contribdir) $(DESTDIR)$(contribdir)
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+	-rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-generic clean-am
+	-rm -f libtool
+
+distclean: distclean-am
+
+maintainer-clean-am:  maintainer-clean-generic distclean-am
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: uninstall-contribSCRIPTS install-contribSCRIPTS \
+uninstall-contribDATA install-contribDATA tags distdir info-am info \
+dvi-am dvi check check-am installcheck-am installcheck install-exec-am \
+install-exec install-data-am install-data install-am install \
+uninstall-am uninstall all-redirect all-am all installdirs \
+mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: trunk/orca/packages/rrdtool-1.0.13/contrib/rrdfetchnames/rrdfetchnames.pl.in
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/contrib/rrdfetchnames/rrdfetchnames.pl.in	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/contrib/rrdfetchnames/rrdfetchnames.pl.in	Sat Jul 13 21:08:03 2002
@@ -0,0 +1,30 @@
+#!/usr/bin/perl
+
+use strict;
+
+#makes things work when run without install
+use lib qw( ../../perl-shared/blib/lib ../../perl-shared/blib/arch );
+
+#makes programm work AFTER install
+use lib qw( @prefix@/lib/perl ../lib/perl );
+
+use vars qw(@ISA $loaded);
+
+use RRDs;
+
+my $NAME = $ARGV[ 0];
+my $SEPARATOR = " ";
+my $CF = "AVERAGE";
+
+my ($start,$step,$names,$data) = RRDs::fetch "$NAME", "$CF", "--start", "now","--end","start+1";
+
+if ( my $ERR = RRDs::error){
+	die "ERROR while fetching data from $NAME $ERR\n";
+}
+
+print join( $SEPARATOR, @$names), "\n";
+
+sub usage{
+	print "usage: rrdfetchnames filename";
+};
+

Added: trunk/orca/packages/rrdtool-1.0.13/contrib/rrdfetchnames/Makefile.am
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/contrib/rrdfetchnames/Makefile.am	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/contrib/rrdfetchnames/Makefile.am	Sat Jul 13 21:08:03 2002
@@ -0,0 +1,7 @@
+## Process this file with automake to produce Makefile.in
+
+EXTRA_DIST = rrdfetchnames.pl.in
+
+contribdir = $(prefix)/contrib/rrdfetchnames
+contrib_DATA = README
+contrib_SCRIPTS = rrdfetchnames.pl

Added: trunk/orca/packages/rrdtool-1.0.13/contrib/rrdfetchnames/README
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/contrib/rrdfetchnames/README	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/contrib/rrdfetchnames/README	Sat Jul 13 21:08:03 2002
@@ -0,0 +1,13 @@
+Is there a program currently to list the available data sources, in a given rrd
+file?
+
+From: Rainer Nagel <rainer at roka.net>
+
+yes ...
+
+here ...
+
+rrdfetchnames.pl my.rrd
+
+have fun
+

Added: trunk/orca/packages/rrdtool-1.0.13/contrib/killspike/Makefile.in
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/contrib/killspike/Makefile.in	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/contrib/killspike/Makefile.in	Sat Jul 13 21:08:03 2002
@@ -0,0 +1,234 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ../..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_alias = @build_alias@
+build_triplet = @build@
+host_alias = @host_alias@
+host_triplet = @host@
+target_alias = @target_alias@
+target_triplet = @target@
+CC = @CC@
+CFLAGS = @CFLAGS@
+CGI_LIB_DIR = @CGI_LIB_DIR@
+COMP_PERL = @COMP_PERL@
+CPP = @CPP@
+GD_LIB_DIR = @GD_LIB_DIR@
+LIBTOOL = @LIBTOOL@
+PERL = @PERL@
+PNG_LIB_DIR = @PNG_LIB_DIR@
+RANLIB = @RANLIB@
+ZLIB_LIB_DIR = @ZLIB_LIB_DIR@
+
+EXTRA_DIST = killspike.pl.in
+
+contribdir = $(prefix)/contrib/killspike
+contrib_DATA = README
+contrib_SCRIPTS = killspike.pl
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = ../../config/config.h
+CONFIG_CLEAN_FILES =  killspike.pl
+SCRIPTS =  $(contrib_SCRIPTS)
+
+DATA =  $(contrib_DATA)
+
+DIST_COMMON =  README Makefile.am Makefile.in killspike.pl.in
+
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+all: all-redirect
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+	cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps contrib/killspike/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+killspike.pl: $(top_builddir)/config.status killspike.pl.in
+	cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+install-contribSCRIPTS: $(contrib_SCRIPTS)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(contribdir)
+	@list='$(contrib_SCRIPTS)'; for p in $$list; do \
+	  if test -f $$p; then \
+	    echo " $(INSTALL_SCRIPT) $$p $(DESTDIR)$(contribdir)/`echo $$p|sed '$(transform)'`"; \
+	    $(INSTALL_SCRIPT) $$p $(DESTDIR)$(contribdir)/`echo $$p|sed '$(transform)'`; \
+	  else if test -f $(srcdir)/$$p; then \
+	    echo " $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(contribdir)/`echo $$p|sed '$(transform)'`"; \
+	    $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(contribdir)/`echo $$p|sed '$(transform)'`; \
+	  else :; fi; fi; \
+	done
+
+uninstall-contribSCRIPTS:
+	@$(NORMAL_UNINSTALL)
+	list='$(contrib_SCRIPTS)'; for p in $$list; do \
+	  rm -f $(DESTDIR)$(contribdir)/`echo $$p|sed '$(transform)'`; \
+	done
+
+install-contribDATA: $(contrib_DATA)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(contribdir)
+	@list='$(contrib_DATA)'; for p in $$list; do \
+	  if test -f $(srcdir)/$$p; then \
+	    echo " $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(contribdir)/$$p"; \
+	    $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(contribdir)/$$p; \
+	  else if test -f $$p; then \
+	    echo " $(INSTALL_DATA) $$p $(DESTDIR)$(contribdir)/$$p"; \
+	    $(INSTALL_DATA) $$p $(DESTDIR)$(contribdir)/$$p; \
+	  fi; fi; \
+	done
+
+uninstall-contribDATA:
+	@$(NORMAL_UNINSTALL)
+	list='$(contrib_DATA)'; for p in $$list; do \
+	  rm -f $(DESTDIR)$(contribdir)/$$p; \
+	done
+tags: TAGS
+TAGS:
+
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = contrib/killspike
+
+distdir: $(DISTFILES)
+	@for file in $(DISTFILES); do \
+	  d=$(srcdir); \
+	  if test -d $$d/$$file; then \
+	    cp -pr $$/$$file $(distdir)/$$file; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+	    || cp -p $$d/$$file $(distdir)/$$file || :; \
+	  fi; \
+	done
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am: install-contribSCRIPTS install-contribDATA
+install-data: install-data-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-contribSCRIPTS uninstall-contribDATA
+uninstall: uninstall-am
+all-am: Makefile $(SCRIPTS) $(DATA)
+all-redirect: all-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+	$(mkinstalldirs)  $(DESTDIR)$(contribdir) $(DESTDIR)$(contribdir)
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+	-rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-generic clean-am
+	-rm -f libtool
+
+distclean: distclean-am
+
+maintainer-clean-am:  maintainer-clean-generic distclean-am
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: uninstall-contribSCRIPTS install-contribSCRIPTS \
+uninstall-contribDATA install-contribDATA tags distdir info-am info \
+dvi-am dvi check check-am installcheck-am installcheck install-exec-am \
+install-exec install-data-am install-data install-am install \
+uninstall-am uninstall all-redirect all-am all installdirs \
+mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: trunk/orca/packages/rrdtool-1.0.13/contrib/killspike/killspike.pl.in
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/contrib/killspike/killspike.pl.in	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/contrib/killspike/killspike.pl.in	Sat Jul 13 21:08:03 2002
@@ -0,0 +1,132 @@
+#! @PERL@ -w
+
+# $Id: killspike.pl,v 1.2 2000/01/14 01:56:59 bertd Exp $
+# $Source: /cvs-mis/local/support/killspike/killspike.pl,v $
+
+# This script will read an XML file produced by
+#	rrdtool dump foo.rrd >in.xml
+# and look at the $maxspike highest samples per datasource. It then finds
+# the records with the most hits and ditches the data. The resulting file
+# can be read back into the RRD database with the command
+#	rrdtool restore out.xml foo.rrd
+#
+# The whole idea is to find and eradicate "spikes" caused by erroneous
+# readings affecting entire records.
+#
+# This tool is not for the faint of heart, will require tweaking per case
+# (even though that should just be picking values for cutoff and to a lesser
+# extent, maxspike). It will cause data loss, for obvious reasons.
+#
+# THIS SOFTWARE IS DISTRIBUTED IN THE HOPE THAT IT IS USEFUL, AND COMES WITH
+# NO WARRANTY. USE AT YOUR OWN RISK!
+#
+#			Bert Driehuis <driehuis at playbeing.org>
+
+use strict;
+
+my $maxspike = 25;	# How many top samples to consider per datasource
+my $cutoff = 20;	# How many records to ditch
+my $debug = 1;
+my $file = "in.xml";
+my $outfile = "out.xml";
+
+my $nds = 0;
+my @dsl = ();
+my @dsi = ();
+my @topindx = ();
+my @botindx = ();
+my $i;
+my $j;
+
+# Count the number of data sources
+open(IN, $file) || die;
+while(<IN>) {
+	$nds++ if /<name>\s*ds/;
+}
+close IN;
+
+print "Found $nds datasources\n" if $debug;
+
+# Set up the list of lists for the datasource data
+for ($i = 0; $i < $nds; $i++) {
+	my @dsdata = ();
+	push @dsl, \@dsdata;
+	my @dsindex = ();
+	push @dsi, \@dsindex;
+	my @top = ();
+	push @topindx, \@top;
+	my @bot = ();
+	push @botindx, \@bot;
+}
+
+# Slurp all datasource fields into the @dsl Lol
+my $recno = -1;
+open(IN, $file) || die;
+while(<IN>) {
+	next if !/<row>/;
+	$recno++;
+	my @data = split(/ /);
+	die "Malformed input" if $data[5] ne "<row><v>";
+	die "Malformed record" if $data[5 + ($nds * 2)] ne "</v></row>\n";
+	for ($i = 0; $i < $nds; $i++) {
+		my $sample = $data[($i * 2) + 6];
+		#print "$sample\n";
+		push @{$dsl[$i]}, $sample;
+	}
+}
+close IN;
+
+# Set up a LoL with indexes, and ditch the values that represent NaN's
+for ($i = 0; $i < $nds; $i++) {
+	@{$dsi[$i]} = grep { ${$dsl[$i]}[$_] ne "NaN" } (0..$recno);
+	print "Ds$i has $#{$dsi[$i]} valid samples\n" if $debug;
+}
+
+sub sortit {
+	${$dsl[$i]}[$a] <=> ${$dsl[$i]}[$b];
+}
+my %indexes;
+for ($i = 0; $i < $nds; $i++) {
+	@{$dsi[$i]} = sort sortit @{$dsi[$i]};
+	@{$botindx[$i]} = @{$dsi[$i]};
+	@{$topindx[$i]} = splice(@{$botindx[$i]}, -$maxspike);
+	print "ds$i top $maxspike: ".join(' ', @{$topindx[$i]})."\n";
+	for($j = 0; $j < $maxspike; $j++) {
+		$indexes{${$topindx[$i]}[$j]} = 0 if
+				!defined($indexes{${$topindx[$i]}[$j]});
+		$indexes{${$topindx[$i]}[$j]}++;
+		printf "%1.1e ", ${$dsl[$i]}[${$topindx[$i]}[$j]];
+	}
+	print "\n";
+}
+
+# Report on the hit rate of the records to be dumped, and a few for
+# reference.
+$j = 0;
+my %ditch;
+foreach $i (sort {$indexes{$b} <=> $indexes{$a}} keys %indexes) {
+	print "Record index $i: $indexes{$i} hits\n";
+	$ditch{$i} = 1 if $j < $cutoff;
+	print "----------\n" if $j + 1 == $cutoff;
+	last if $j++ > $maxspike;
+}
+
+# Okay, so we start ditching the records. You can always re-run the script
+# if the results don't suit you after adjusting $cutoff or $maxspike.
+$recno = -1;
+open(IN, $file) || die;
+open(OUT, ">$outfile") || die;
+while(<IN>) {
+	print OUT if !/<row>/;
+	next if !/<row>/;
+	$recno++;
+	print OUT if !defined($ditch{$recno});
+	next if !defined($ditch{$recno});
+	my @data = split(/ /);
+	for ($i = 0; $i < $nds; $i++) {
+		$data[($i * 2) + 6] = "NaN";
+	}
+	print OUT join(' ', @data);
+}
+close IN;
+close OUT;

Added: trunk/orca/packages/rrdtool-1.0.13/contrib/killspike/Makefile.am
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/contrib/killspike/Makefile.am	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/contrib/killspike/Makefile.am	Sat Jul 13 21:08:03 2002
@@ -0,0 +1,7 @@
+## Process this file with automake to produce Makefile.in
+
+EXTRA_DIST = killspike.pl.in
+
+contribdir = $(prefix)/contrib/killspike
+contrib_DATA = README
+contrib_SCRIPTS =  killspike.pl

Added: trunk/orca/packages/rrdtool-1.0.13/contrib/killspike/README
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/contrib/killspike/README	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/contrib/killspike/README	Sat Jul 13 21:08:03 2002
@@ -0,0 +1,19 @@
+From: Bert Driehuis <driehuis at playbeing.org>
+Date: Fri, 14 Jan 2000 03:41:07 +0100 (CET)
+
+This script will read an XML file produced by
+
+       rrdtool dump foo.rrd >in.xml
+
+and look at the $maxspike highest samples per datasource. It then finds the
+records with the most hits and ditches the data. The resulting file can be
+read back into the RRD database with the command
+
+       rrdtool restore out.xml foo.rrd
+
+The whole idea is to find and eradicate "spikes" caused by erroneous
+readings affecting entire records.
+
+This tool is not for the faint of heart, will require tweaking per case
+(even though that should just be picking values for cutoff and to a lesser
+extent, maxspike). It will cause data loss, for obvious reasons.

Modified: trunk/orca/packages/rrdtool-1.0.13/contrib/Makefile.am
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/contrib/Makefile.am	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/contrib/Makefile.am	Sat Jul 13 21:08:04 2002
@@ -1,6 +1,6 @@
 ## Process this file with automake to produce Makefile.in
 
-SUBDIRS= log2rrd rrd-file-icon trytime
+SUBDIRS = log2rrd rrd-file-icon trytime rrdproc rrdlastds add_ds killspike rrdfetchnames
 
 contribdir = $(prefix)/contrib
 contrib_DATA = README

Modified: trunk/orca/packages/rrdtool-1.0.13/contrib/rrd-file-icon/Makefile.in
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/contrib/rrd-file-icon/Makefile.in	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/contrib/rrd-file-icon/Makefile.in	Sat Jul 13 21:08:04 2002
@@ -91,7 +91,7 @@
 
 DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
 
-TAR = tar
+TAR = gtar
 GZIP_ENV = --best
 all: all-redirect
 .SUFFIXES:

Added: trunk/orca/packages/rrdtool-1.0.13/contrib/rrdproc/Makefile.in
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/contrib/rrdproc/Makefile.in	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/contrib/rrdproc/Makefile.in	Sat Jul 13 21:08:04 2002
@@ -0,0 +1,212 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ../..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_alias = @build_alias@
+build_triplet = @build@
+host_alias = @host_alias@
+host_triplet = @host@
+target_alias = @target_alias@
+target_triplet = @target@
+CC = @CC@
+CFLAGS = @CFLAGS@
+CGI_LIB_DIR = @CGI_LIB_DIR@
+COMP_PERL = @COMP_PERL@
+CPP = @CPP@
+GD_LIB_DIR = @GD_LIB_DIR@
+LIBTOOL = @LIBTOOL@
+PERL = @PERL@
+PNG_LIB_DIR = @PNG_LIB_DIR@
+RANLIB = @RANLIB@
+ZLIB_LIB_DIR = @ZLIB_LIB_DIR@
+
+EXTRA_DIST = rrdproc.c
+contribdir = $(prefix)/contrib/rrdproc
+contrib_DATA = README rrdproc.c
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = ../../config/config.h
+CONFIG_CLEAN_FILES = 
+DATA =  $(contrib_DATA)
+
+DIST_COMMON =  README Makefile.am Makefile.in
+
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+all: all-redirect
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+	cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps contrib/rrdproc/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+install-contribDATA: $(contrib_DATA)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(contribdir)
+	@list='$(contrib_DATA)'; for p in $$list; do \
+	  if test -f $(srcdir)/$$p; then \
+	    echo " $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(contribdir)/$$p"; \
+	    $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(contribdir)/$$p; \
+	  else if test -f $$p; then \
+	    echo " $(INSTALL_DATA) $$p $(DESTDIR)$(contribdir)/$$p"; \
+	    $(INSTALL_DATA) $$p $(DESTDIR)$(contribdir)/$$p; \
+	  fi; fi; \
+	done
+
+uninstall-contribDATA:
+	@$(NORMAL_UNINSTALL)
+	list='$(contrib_DATA)'; for p in $$list; do \
+	  rm -f $(DESTDIR)$(contribdir)/$$p; \
+	done
+tags: TAGS
+TAGS:
+
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = contrib/rrdproc
+
+distdir: $(DISTFILES)
+	@for file in $(DISTFILES); do \
+	  d=$(srcdir); \
+	  if test -d $$d/$$file; then \
+	    cp -pr $$/$$file $(distdir)/$$file; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+	    || cp -p $$d/$$file $(distdir)/$$file || :; \
+	  fi; \
+	done
+
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am: install-contribDATA
+install-data: install-data-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-contribDATA
+uninstall: uninstall-am
+all-am: Makefile $(DATA)
+all-redirect: all-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+	$(mkinstalldirs)  $(DESTDIR)$(contribdir)
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+	-rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-generic clean-am
+	-rm -f libtool
+
+distclean: distclean-am
+
+maintainer-clean-am:  maintainer-clean-generic distclean-am
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: uninstall-contribDATA install-contribDATA tags distdir info-am \
+info dvi-am dvi check check-am installcheck-am installcheck \
+install-exec-am install-exec install-data-am install-data install-am \
+install uninstall-am uninstall all-redirect all-am all installdirs \
+mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+#bin_PROGRAMS    = rrdproc
+#rrdproc_SOURCES  = rrdproc.c
+#rrdproc_LDADD    = ../../src/librrd.la
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: trunk/orca/packages/rrdtool-1.0.13/contrib/rrdproc/Makefile.am
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/contrib/rrdproc/Makefile.am	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/contrib/rrdproc/Makefile.am	Sat Jul 13 21:08:04 2002
@@ -0,0 +1,7 @@
+## Process this file with automake to produce Makefile.in
+EXTRA_DIST = rrdproc.c
+contribdir = $(prefix)/contrib/rrdproc
+contrib_DATA = README rrdproc.c
+#bin_PROGRAMS    = rrdproc
+#rrdproc_SOURCES  = rrdproc.c
+#rrdproc_LDADD    = ../../src/librrd.la

Added: trunk/orca/packages/rrdtool-1.0.13/contrib/rrdproc/rrdproc.c
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/contrib/rrdproc/rrdproc.c	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/contrib/rrdproc/rrdproc.c	Sat Jul 13 21:08:04 2002
@@ -0,0 +1,249 @@
+/*
+** rrdproc.c Copyright 1999 Damien Miller <djm at mindrot.org>
+**
+**
+** This program is a very lightweight collecter for rrdtool. It reads
+** and parses /proc/net/dev and sends a rrdtool remote control update
+** command to stdout.
+**
+** rrdproc will sleep a user-defined amount of time between reads from
+** /proc/net/dev. This time should match the sample rate you created your
+** RRD files with.
+**
+** Example:
+**
+** rrdproc --interface=ppp0 \
+**         --wait 30 \
+**         --filename=/home/djm/traffic-ppp0.rrd | rrdtool -
+**
+** This will update the RRD file /home/djm/traffic-eth0.rrd with bytes
+** received and sent on eth0 every 30 seconds.
+**
+** rrdproc --interface=eth0 \
+**         --wait 300 \
+**         --frame \
+**         --filename=/home/djm/traffic-eth0.rrd | rrdtool -
+**
+** Will update /home/djm/traffic-eth0.rrd with counts of framing errors and
+** collisions every 5 minutes
+**
+** rrdproc is licensed under the GNU GPL version 2. Please refer to
+** http://www.fsf.org/copyleft/gpl.html for details.
+**
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <time.h>
+
+#define PROC_DEV					"/proc/net/dev"
+
+#define DEFAULT_SLEEP_TIME		3
+#define DEFAULT_INTERFACE		"eth0"
+#define DEFAULT_FILENAME		"traffic"
+
+#define COLUMN_BYTES				0
+#define COLUMN_PACKETS			1
+#define COLUMN_ERRORS			2
+#define COLUMN_DROPPED			3
+#define COLUMN_FIFO				4
+#define COLUMN_FRAME				5
+
+void get_stats(FILE *devstats, const char *interface, int start_column);
+const char *skip_columns(const char *p, int num_columns);
+void help(void);
+void version(void);
+
+static struct option long_options[] =
+{
+	{ "wait", 1, NULL, 'w'},
+	{ "interface", 1, NULL, 'i'},
+	{ "filename", 1, NULL, 'f'},
+	{ "help", 0, NULL, 'h'},
+	{ "version", 0, NULL, 'v'},
+	{ "bytes", 0, NULL, 'B'},
+	{ "packets", 0, NULL, 'P'},
+	{ "errors", 0, NULL, 'E'},
+	{ "dropped", 0, NULL, 'D'},
+	{ "fifo", 0, NULL, 'F'},
+	{ "frame", 0, NULL, 'R'},
+};
+
+int main(int argc, char **argv)
+{
+	int sleep_time = DEFAULT_SLEEP_TIME;
+	char *interface = DEFAULT_INTERFACE;
+	char *filename = DEFAULT_FILENAME;
+	int start_column = COLUMN_BYTES;
+	int c;
+	FILE *devstats;
+	
+	extern char *optarg;
+	
+	openlog("if-update", LOG_PERROR|LOG_PID, LOG_DAEMON);
+	
+	while(1)
+	{
+		c = getopt_long(argc, argv, "w:i:f:hvBPEDFRCM", long_options, NULL);
+		if (c == -1)
+			break;
+		
+		switch(c)
+		{
+			case 'w':
+				sleep_time = atoi(optarg);
+				break;
+			case 'i':
+				interface = strdup(optarg);
+				break;
+			case 'f':
+				filename = strdup(optarg);
+				break;
+			case 'h':
+				help();
+				exit(0);
+			case 'v':
+				version();
+				exit(0);
+			case 'B':
+				start_column = COLUMN_BYTES;
+				break;
+			case 'P':
+				start_column = COLUMN_PACKETS;
+				break;
+			case 'E':
+				start_column = COLUMN_ERRORS;
+				break;
+			case 'D':
+				start_column = COLUMN_DROPPED;
+				break;
+			case 'F':
+				start_column = COLUMN_FIFO;
+				break;
+			case 'R':
+				start_column = COLUMN_FRAME;
+				break;
+			default:
+				fprintf(stderr, "Invalid commandline options.\n");
+				help();
+				exit(1);
+		}		
+	}
+	
+	setlinebuf(stdout);
+	
+	while(1)
+	{
+		devstats = fopen(PROC_DEV, "r");
+		if (devstats == NULL)
+		{
+			syslog(LOG_ERR, "Couldn't open proc file \"%s\" for reading: %m", PROC_DEV);
+			exit(1);
+		}
+		printf("update %s N:", filename);
+		get_stats(devstats, interface, start_column);
+		sleep(sleep_time);
+		fclose(devstats);
+	}
+	exit(0);
+}
+
+void get_stats(FILE *devstats, const char *interface, int start_column)
+{
+	char buffer[2048];
+	const char *p;
+	int if_len;
+	unsigned long long in;
+	unsigned long long out;
+	
+	if_len = strlen(interface);
+	
+	while(fgets(buffer, sizeof(buffer), devstats) != NULL)
+	{
+		p = buffer;
+		
+		/* skip space at start of line */
+		while(*p && (*p == ' '))
+			p++;
+
+		if (strncmp(p, interface, if_len) == 0)
+		{
+			/* Skip to the statistic we wnt to report */
+			p = skip_columns(p + if_len + 1, start_column);
+
+			in = strtoull(p, NULL, 10);
+
+			/* Skip from received column to transmit column */
+			p = skip_columns(p, 8);
+
+			out = strtoull(p, NULL, 10);
+
+			printf("%Lu:%Lu\n", in, out);
+
+			return;
+		}		
+	}
+
+	/* Non-fatal error if interface not found */
+	syslog(LOG_WARNING, "Couldn't find statistics for interface \"%s\"", interface);
+	printf("U:U\n");
+	return;
+}
+
+void help(void)
+{
+	fprintf(stderr, "\
+rrdproc - Update rrd file using statistics in /proc\n\
+\n\
+rrdproc will periodically read /proc/net/dev and update an RRD database\n\
+with the numbers that it finds there.\n\
+\n\
+Options:\n\
+    --wait, -w      [time]      Time to wait between statistics updates\n\
+    --interface, -i [name]      Name of network interface to report on\n\
+    --filename, -f  [filename]  Path of RRD file to update\n\
+    --help, -h                  Display this help\n\
+    --version, -v               Display version information\n\
+    --bytes, -B                 Report bytes in / out\n\
+    --packets, -P               Report packets in / out\n\
+    --errors, -E                Report errors in / out\n\
+    --dropped, -D               Report dropped packets in / out\n\
+    --fifo, -F                  Report fifo in / out\n\
+    --frame, -R                 Report framing errors / collisions\n\
+");
+}
+
+void version(void)
+{
+	fprintf(stderr, "rrdproc v0.0\n");
+}
+
+const char *skip_columns(const char *p, int num_columns)
+{
+	int c;
+	
+	for(c = 0; c < num_columns; c++)
+	{
+		/* Skip numbers */
+		while(*p && (*p != ' '))
+			p++;
+
+		/* Skip space */
+		while(*p && (*p == ' '))
+			p++;
+
+		if (!*p)
+		{
+			/* Line finished early */
+			printf("U:U\n");
+			syslog(LOG_WARNING, "Couldn't parse interface statistics");
+			return;
+		}
+	}
+	
+	return(p);
+}

Added: trunk/orca/packages/rrdtool-1.0.13/contrib/rrdproc/README
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/contrib/rrdproc/README	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/contrib/rrdproc/README	Sat Jul 13 21:08:04 2002
@@ -0,0 +1,30 @@
+* rrdproc.c Copyright 1999 Damien Miller <djm at mindrot.org>
+**
+**
+** This program is a very lightweight collecter for rrdtool. It reads
+** and parses /proc/net/dev and sends a rrdtool remote control update
+** command to stdout.
+**
+** rrdproc will sleep a user-defined amount of time between reads from
+** /proc/net/dev. This time should match the sample rate you created your
+** RRD files with.
+**
+** Example:
+**
+** rrdproc --interface=ppp0 \
+**         --wait 30 \
+**         --filename=/home/djm/traffic-ppp0.rrd | rrdtool -
+**
+** This will update the RRD file /home/djm/traffic-eth0.rrd with bytes
+** received and sent on eth0 every 30 seconds.
+**
+** rrdproc --interface=eth0 \
+**         --wait 300 \
+**         --frame \
+**         --filename=/home/djm/traffic-eth0.rrd | rrdtool -
+**
+** Will update /home/djm/traffic-eth0.rrd with counts of framing errors and
+** collisions every 5 minutes
+**
+** rrdproc is licensed under the GNU GPL version 2. Please refer to
+** http://www.fsf.org/copyleft/gpl.html for details.

Modified: trunk/orca/packages/rrdtool-1.0.13/contrib/log2rrd/Makefile.in
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/contrib/log2rrd/Makefile.in	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/contrib/log2rrd/Makefile.in	Sat Jul 13 21:08:04 2002
@@ -95,7 +95,7 @@
 
 DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
 
-TAR = tar
+TAR = gtar
 GZIP_ENV = --best
 all: all-redirect
 .SUFFIXES:

Modified: trunk/orca/packages/rrdtool-1.0.13/contrib/README
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/contrib/README	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/contrib/README	Sat Jul 13 21:08:05 2002
@@ -1,6 +1,6 @@
 This directory should contain YOUR scripts ... please sent them to me ...
 
-each script should come with an apropriate README file ...
+each script should come with an appropriate README file ...
 
-cheees
-tobi
+cheers
+Tobi

Modified: trunk/orca/packages/rrdtool-1.0.13/contrib/trytime/Makefile.in
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/contrib/trytime/Makefile.in	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/contrib/trytime/Makefile.in	Sat Jul 13 21:08:05 2002
@@ -75,12 +75,30 @@
 RANLIB = @RANLIB@
 ZLIB_LIB_DIR = @ZLIB_LIB_DIR@
 
+INCLUDES = -I../../src -I../../gd1.3
 EXTRA_DIST = trytime.c
 contribdir = $(prefix)/contrib/trytime
 contrib_DATA = README trytime.c
+bin_PROGRAMS = trytime
+trytime_SOURCES = trytime.c
+trytime_LDADD = ../../src/librrd.la
 mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
 CONFIG_HEADER = ../../config/config.h
 CONFIG_CLEAN_FILES = 
+PROGRAMS =  $(bin_PROGRAMS)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I../../config
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+trytime_OBJECTS =  trytime.o
+trytime_DEPENDENCIES =  ../../src/librrd.la
+trytime_LDFLAGS = 
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
 DATA =  $(contrib_DATA)
 
 DIST_COMMON =  README Makefile.am Makefile.in
@@ -91,10 +109,14 @@
 
 DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
 
-TAR = tar
+TAR = gtar
 GZIP_ENV = --best
+SOURCES = $(trytime_SOURCES)
+OBJECTS = $(trytime_OBJECTS)
+
 all: all-redirect
 .SUFFIXES:
+.SUFFIXES: .S .c .lo .o .s
 $(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
 	cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps contrib/trytime/Makefile
 
@@ -103,6 +125,73 @@
 	  && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
 
 
+mostlyclean-binPROGRAMS:
+
+clean-binPROGRAMS:
+	-test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+
+distclean-binPROGRAMS:
+
+maintainer-clean-binPROGRAMS:
+
+install-binPROGRAMS: $(bin_PROGRAMS)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(bindir)
+	@list='$(bin_PROGRAMS)'; for p in $$list; do \
+	  if test -f $$p; then \
+	    echo " $(LIBTOOL)  --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \
+	    $(LIBTOOL)  --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+	  else :; fi; \
+	done
+
+uninstall-binPROGRAMS:
+	@$(NORMAL_UNINSTALL)
+	list='$(bin_PROGRAMS)'; for p in $$list; do \
+	  rm -f $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+	done
+
+.c.o:
+	$(COMPILE) -c $<
+
+.s.o:
+	$(COMPILE) -c $<
+
+.S.o:
+	$(COMPILE) -c $<
+
+mostlyclean-compile:
+	-rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+	-rm -f *.tab.c
+
+maintainer-clean-compile:
+
+.c.lo:
+	$(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+.s.lo:
+	$(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+.S.lo:
+	$(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+
+maintainer-clean-libtool:
+
+trytime: $(trytime_OBJECTS) $(trytime_DEPENDENCIES)
+	@rm -f trytime
+	$(LINK) $(trytime_LDFLAGS) $(trytime_OBJECTS) $(trytime_LDADD) $(LIBS)
+
 install-contribDATA: $(contrib_DATA)
 	@$(NORMAL_INSTALL)
 	$(mkinstalldirs) $(DESTDIR)$(contribdir)
@@ -121,9 +210,35 @@
 	list='$(contrib_DATA)'; for p in $$list; do \
 	  rm -f $(DESTDIR)$(contribdir)/$$p; \
 	done
+
 tags: TAGS
-TAGS:
 
+ID: $(HEADERS) $(SOURCES) $(LISP)
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	here=`pwd` && cd $(srcdir) \
+	  && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+	  || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags  $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+	-rm -f TAGS ID
+
+maintainer-clean-tags:
 
 distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
 
@@ -140,6 +255,10 @@
 	    || cp -p $$d/$$file $(distdir)/$$file || :; \
 	  fi; \
 	done
+trytime.o: trytime.c ../../src/getopt.h ../../src/rrd_tool.h \
+	../../config/config.h ../../src/parsetime.h \
+	../../src/rrd_format.h ../../gd1.3/gd.h
+
 info-am:
 info: info-am
 dvi-am:
@@ -148,7 +267,7 @@
 check: check-am
 installcheck-am:
 installcheck: installcheck-am
-install-exec-am:
+install-exec-am: install-binPROGRAMS
 install-exec: install-exec-am
 
 install-data-am: install-contribDATA
@@ -157,14 +276,14 @@
 install-am: all-am
 	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
 install: install-am
-uninstall-am: uninstall-contribDATA
+uninstall-am: uninstall-binPROGRAMS uninstall-contribDATA
 uninstall: uninstall-am
-all-am: Makefile $(DATA)
+all-am: Makefile $(PROGRAMS) $(DATA)
 all-redirect: all-am
 install-strip:
 	$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
 installdirs:
-	$(mkinstalldirs)  $(DESTDIR)$(contribdir)
+	$(mkinstalldirs)  $(DESTDIR)$(bindir) $(DESTDIR)$(contribdir)
 
 
 mostlyclean-generic:
@@ -176,31 +295,44 @@
 	-rm -f config.cache config.log stamp-h stamp-h[0-9]*
 
 maintainer-clean-generic:
-mostlyclean-am:  mostlyclean-generic
+mostlyclean-am:  mostlyclean-binPROGRAMS mostlyclean-compile \
+		mostlyclean-libtool mostlyclean-tags \
+		mostlyclean-generic
 
 mostlyclean: mostlyclean-am
 
-clean-am:  clean-generic mostlyclean-am
+clean-am:  clean-binPROGRAMS clean-compile clean-libtool clean-tags \
+		clean-generic mostlyclean-am
 
 clean: clean-am
 
-distclean-am:  distclean-generic clean-am
+distclean-am:  distclean-binPROGRAMS distclean-compile distclean-libtool \
+		distclean-tags distclean-generic clean-am
 	-rm -f libtool
 
 distclean: distclean-am
 
-maintainer-clean-am:  maintainer-clean-generic distclean-am
+maintainer-clean-am:  maintainer-clean-binPROGRAMS \
+		maintainer-clean-compile maintainer-clean-libtool \
+		maintainer-clean-tags maintainer-clean-generic \
+		distclean-am
 	@echo "This command is intended for maintainers to use;"
 	@echo "it deletes files that may require special tools to rebuild."
 
 maintainer-clean: maintainer-clean-am
 
-.PHONY: uninstall-contribDATA install-contribDATA tags distdir info-am \
-info dvi-am dvi check check-am installcheck-am installcheck \
-install-exec-am install-exec install-data-am install-data install-am \
-install uninstall-am uninstall all-redirect all-am all installdirs \
-mostlyclean-generic distclean-generic clean-generic \
-maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \
+maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile mostlyclean-libtool distclean-libtool \
+clean-libtool maintainer-clean-libtool uninstall-contribDATA \
+install-contribDATA tags mostlyclean-tags distclean-tags clean-tags \
+maintainer-clean-tags distdir info-am info dvi-am dvi check check-am \
+installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
 
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.

Modified: trunk/orca/packages/rrdtool-1.0.13/contrib/trytime/Makefile.am
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/contrib/trytime/Makefile.am	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/contrib/trytime/Makefile.am	Sat Jul 13 21:08:05 2002
@@ -1,4 +1,8 @@
 ## Process this file with automake to produce Makefile.in
+INCLUDES = -I../../src -I../../gd1.3
 EXTRA_DIST = trytime.c
 contribdir = $(prefix)/contrib/trytime
 contrib_DATA = README trytime.c
+bin_PROGRAMS    = trytime
+trytime_SOURCES  = trytime.c
+trytime_LDADD    = ../../src/librrd.la

Modified: trunk/orca/packages/rrdtool-1.0.13/contrib/trytime/trytime.c
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/contrib/trytime/trytime.c	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/contrib/trytime/trytime.c	Sat Jul 13 21:08:05 2002
@@ -2,7 +2,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include "getopt.h"
+#include <getopt.h>
 #include <rrd_tool.h>
 
 #ifndef	WANT_AT_STYLE_TIMESPEC

Added: trunk/orca/packages/rrdtool-1.0.13/contrib/add_ds/batch.pl.in
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/contrib/add_ds/batch.pl.in	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/contrib/add_ds/batch.pl.in	Sat Jul 13 21:08:05 2002
@@ -0,0 +1,95 @@
+#! @PERL@
+
+# batch.pl, simple program to help add datasources to an existing RRD
+#   goes with add_ds.pl
+#
+#    Copyright (C) 2000 Selena M. Brewington
+#
+#    This program is free software; you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation; either version 2 of the License, or
+#    (at your option) any later version.
+#
+#    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
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program; if not, write to the Free Software
+#    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+# 
+# for use with add_ds.pl script to add datasources to an RRD
+#
+# usage: ls -1 | ./batch.pl [-o] <# ds to add>
+#
+# -o will let you overwrite your rrds.  i don't recommend using this 
+# switch the first time you run this program.  If something
+# gets messed up, the original xml files will be in the xml
+# directory and you can run 'rrdtool restore' on all of them
+# uncomment the commented out lines below to make this work.
+#
+# also, you can change the name of the directory the XML is
+# getting dumped to, where your rrdtool binary is located, 
+# and where add_ds.pl is located.  the variables are listed 
+# below.
+#
+# This script could theoretically take fully-qualified pathnames
+# as input from STDIN rather than the output from ls -1. 
+#
+
+use strict;
+
+########### USER CONFIGURABLE SECTION #######################
+
+my $newdir = "xml";
+my $rrdtool = "@prefix@/bin/rrdtool";
+my $add_ds = "./add_ds.pl";  # path to add_ds.pl script
+
+########### END CONFIGURE SECTION ###########################
+
+
+my $ds = shift || die 'need number of datasources to add';
+
+my $overwrite = 0;
+
+if ($ds eq '-o') {
+  $overwrite = 1;
+  $ds = shift || die 'need number of datasources to add';
+} 
+
+if (! (-x $newdir)) {
+  `mkdir xml` || die "can't make directory xml";
+}
+
+while (<STDIN>) {
+
+  next if (! /rrd/);
+  chop;
+  my $file = $_;
+
+  $_ =~ s/rrd$/xml/;
+
+  open(FILE, ">$newdir/$_");
+
+  my @output = `$rrdtool dump $file`;
+  print FILE @output;
+
+  close(FILE);
+
+  open (FILE, ">$newdir/$_.2");
+
+  my @new = `cat $newdir/$_ | $add_ds $ds`; 
+
+  print FILE @new;
+
+  close (FILE);
+
+  system("$rrdtool restore $newdir/$_.2 $newdir/$file") == 0 
+    or die "rrdtool restore failed for $file";
+
+  if ($overwrite == 1) {
+    system("mv $newdir/$file $file") == 0
+      or die "can't overwrite $file";
+  }
+}

Added: trunk/orca/packages/rrdtool-1.0.13/contrib/add_ds/Makefile.in
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/contrib/add_ds/Makefile.in	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/contrib/add_ds/Makefile.in	Sat Jul 13 21:08:05 2002
@@ -0,0 +1,236 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ../..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_alias = @build_alias@
+build_triplet = @build@
+host_alias = @host_alias@
+host_triplet = @host@
+target_alias = @target_alias@
+target_triplet = @target@
+CC = @CC@
+CFLAGS = @CFLAGS@
+CGI_LIB_DIR = @CGI_LIB_DIR@
+COMP_PERL = @COMP_PERL@
+CPP = @CPP@
+GD_LIB_DIR = @GD_LIB_DIR@
+LIBTOOL = @LIBTOOL@
+PERL = @PERL@
+PNG_LIB_DIR = @PNG_LIB_DIR@
+RANLIB = @RANLIB@
+ZLIB_LIB_DIR = @ZLIB_LIB_DIR@
+
+EXTRA_DIST = add_ds.pl.in batch.pl.in
+
+contribdir = $(prefix)/contrib/add_ds
+contrib_DATA = README
+contrib_SCRIPTS = add_ds.pl  batch.pl
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = ../../config/config.h
+CONFIG_CLEAN_FILES =  add_ds.pl batch.pl
+SCRIPTS =  $(contrib_SCRIPTS)
+
+DATA =  $(contrib_DATA)
+
+DIST_COMMON =  README Makefile.am Makefile.in add_ds.pl.in batch.pl.in
+
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+all: all-redirect
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+	cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps contrib/add_ds/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+add_ds.pl: $(top_builddir)/config.status add_ds.pl.in
+	cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+batch.pl: $(top_builddir)/config.status batch.pl.in
+	cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+install-contribSCRIPTS: $(contrib_SCRIPTS)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(contribdir)
+	@list='$(contrib_SCRIPTS)'; for p in $$list; do \
+	  if test -f $$p; then \
+	    echo " $(INSTALL_SCRIPT) $$p $(DESTDIR)$(contribdir)/`echo $$p|sed '$(transform)'`"; \
+	    $(INSTALL_SCRIPT) $$p $(DESTDIR)$(contribdir)/`echo $$p|sed '$(transform)'`; \
+	  else if test -f $(srcdir)/$$p; then \
+	    echo " $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(contribdir)/`echo $$p|sed '$(transform)'`"; \
+	    $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(contribdir)/`echo $$p|sed '$(transform)'`; \
+	  else :; fi; fi; \
+	done
+
+uninstall-contribSCRIPTS:
+	@$(NORMAL_UNINSTALL)
+	list='$(contrib_SCRIPTS)'; for p in $$list; do \
+	  rm -f $(DESTDIR)$(contribdir)/`echo $$p|sed '$(transform)'`; \
+	done
+
+install-contribDATA: $(contrib_DATA)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(contribdir)
+	@list='$(contrib_DATA)'; for p in $$list; do \
+	  if test -f $(srcdir)/$$p; then \
+	    echo " $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(contribdir)/$$p"; \
+	    $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(contribdir)/$$p; \
+	  else if test -f $$p; then \
+	    echo " $(INSTALL_DATA) $$p $(DESTDIR)$(contribdir)/$$p"; \
+	    $(INSTALL_DATA) $$p $(DESTDIR)$(contribdir)/$$p; \
+	  fi; fi; \
+	done
+
+uninstall-contribDATA:
+	@$(NORMAL_UNINSTALL)
+	list='$(contrib_DATA)'; for p in $$list; do \
+	  rm -f $(DESTDIR)$(contribdir)/$$p; \
+	done
+tags: TAGS
+TAGS:
+
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = contrib/add_ds
+
+distdir: $(DISTFILES)
+	@for file in $(DISTFILES); do \
+	  d=$(srcdir); \
+	  if test -d $$d/$$file; then \
+	    cp -pr $$/$$file $(distdir)/$$file; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+	    || cp -p $$d/$$file $(distdir)/$$file || :; \
+	  fi; \
+	done
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am: install-contribSCRIPTS install-contribDATA
+install-data: install-data-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-contribSCRIPTS uninstall-contribDATA
+uninstall: uninstall-am
+all-am: Makefile $(SCRIPTS) $(DATA)
+all-redirect: all-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+	$(mkinstalldirs)  $(DESTDIR)$(contribdir) $(DESTDIR)$(contribdir)
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+	-rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-generic clean-am
+	-rm -f libtool
+
+distclean: distclean-am
+
+maintainer-clean-am:  maintainer-clean-generic distclean-am
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: uninstall-contribSCRIPTS install-contribSCRIPTS \
+uninstall-contribDATA install-contribDATA tags distdir info-am info \
+dvi-am dvi check check-am installcheck-am installcheck install-exec-am \
+install-exec install-data-am install-data install-am install \
+uninstall-am uninstall all-redirect all-am all installdirs \
+mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: trunk/orca/packages/rrdtool-1.0.13/contrib/add_ds/Makefile.am
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/contrib/add_ds/Makefile.am	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/contrib/add_ds/Makefile.am	Sat Jul 13 21:08:06 2002
@@ -0,0 +1,7 @@
+## Process this file with automake to produce Makefile.in
+
+EXTRA_DIST = add_ds.pl.in batch.pl.in
+
+contribdir = $(prefix)/contrib/add_ds
+contrib_DATA = README
+contrib_SCRIPTS =  add_ds.pl  batch.pl

Added: trunk/orca/packages/rrdtool-1.0.13/contrib/add_ds/add_ds.pl.in
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/contrib/add_ds/add_ds.pl.in	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/contrib/add_ds/add_ds.pl.in	Sat Jul 13 21:08:06 2002
@@ -0,0 +1,113 @@
+#! @PERL@
+
+# add_ds.pl, program to add datasources to an existing RRD 
+#
+#    Copyright (C) 2000 Selena M. Brewington 
+#
+#    This program is free software; you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation; either version 2 of the License, or
+#    (at your option) any later version.
+#
+#    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
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program; if not, write to the Free Software
+#    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+use strict;
+
+my $ds = shift || die "need number of additional datasources desired";
+if ($ds eq '-h') {
+  &Usage;
+  exit 0;
+}
+
+my $default_val = shift || 'NaN';
+my $type = shift || 'COUNTER';
+my $heartbeat = shift || '1800';
+my $rrdmin = shift || 'NaN';
+my $rrdmax = shift || 'NaN';
+
+my $cdp_prep_end = '</cdp_prep>';
+
+my $row_end = '</row>';
+my $name = '<name>';
+my $name_end = '</name>';
+
+my $field = '<v> ' . $default_val . ' </v>';
+
+my $found_ds = 0;
+my $num_sources = 0;
+my $last;
+my $fields = " ";
+my $datasource;
+my $x;
+
+while (<STDIN>) {
+
+  if (($_ =~ s/$row_end$/$fields$row_end/) && $found_ds) {
+    # need to hit <ds> types first, if we don't, we're screwed
+    print $_; 
+
+  } elsif (/$cdp_prep_end/) {
+    print "\t\t\t<ds><value> NaN </value>  <unknown_datapoints> 0 </unknown_datapoints></ds>\n" x $ds;
+    print $_;
+
+  } elsif (/$name_end$/) {
+    ($datasource) = /$name (\w+)/;
+    $found_ds++;
+    print $_;
+
+  } elsif (/Round Robin Archives/) {
+    # print out additional datasource definitions
+
+    ($num_sources) = ($datasource =~ /(\d+)/);
+    
+    for ($x = $num_sources+1; $x < $num_sources+$ds+1; $x++) {
+
+      $fields .= $field;
+      
+      print "\n\t<ds>\n";
+      print "\t\t<name> ds$x <\/name>\n";
+      print "\t\t<type> $type <\/type>\n";
+      print "\t\t<minimal_heartbeat> $heartbeat <\/minimal_heartbeat>\n";
+      print "\t\t<min> $rrdmin <\/min>\n";
+      print "\t\t<max> $rrdmax <\/max>\n\n";
+      print "\t\t<!-- PDP Status-->\n";
+      print "\t\t<last_ds> NaN <\/last_ds>\n";
+      print "\t\t<value> NaN <\/value>\n";
+      print "\t\t<unknown_sec> NaN <\/unknown_sec>\n"; 
+      print "\t<\/ds>\n\n";
+
+    }
+
+    print $_;
+  } else {
+    print $_;
+  }
+
+  $last = $_;
+}
+
+
+
+
+sub Usage {
+
+  print "add-ds.pl <add'l ds> [default_val] [type] [heartbeat] [rrdmin] [rrdmax] < file.xml\n";
+  print "\t<add'l ds>\tnumber of additional datasources\n";
+  print "\t[default_val]\tdefault value to be entered in add'l fields\n";
+  print "\t[type]\ttype of datasource (i.e. COUNTER, GAUGE...)\n";
+  print "\t[heatbeat]\tlength of time in seconds before RRD thinks your DS is dead\n";
+  print "\t[rrdmin]\tminimum value allowed for each datasource\n";
+  print "\t[rrdmax]\tmax value allowed for each datasource\n\n";
+  print "\tOptions are read in order, so if you want to change the\n";
+  print "\tdefault heartbeat, you need to specify the default_val and\n";
+  print "\ttype as well, etc.\n";
+  print "\n\tOutput goes to STDOUT.\n";
+}
+

Added: trunk/orca/packages/rrdtool-1.0.13/contrib/add_ds/README
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/contrib/add_ds/README	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/contrib/add_ds/README	Sat Jul 13 21:08:06 2002
@@ -0,0 +1,32 @@
+# README
+# From: Selena Brewington <selena at chesnok.com>
+
+The two scripts included in here are for taking an existing RRD,
+dumping out its XML contents, mucking with the XML to add an
+arbitrary number of datasources, and then creating a new RRD with
+the new XML information. 'add_ds.pl' is what is doing all the
+work.  'batch.pl' does the legwork of running rrdtool and 
+moving around the output from the various commands.
+
+Easiest way to use these:
+* Put batch.pl and add_ds.pl in the same directory as the RRDs
+you want to modify and run:
+
+    $ ls -1 | ./batch.pl <# new datasources you want to add>
+
+You'll end up with an 'xml' directory where all the xml files
+and your new RRDs are available.  Copy the new RRDs back over
+the old RRDs once you've convinced yourself that the new RRDs
+have been formed correctly (try using the rrd-dump tool that is
+in the cricket/utils directory, for example).
+
+I put some options that you can configure at the top of the
+batch.pl script.  Also, add_ds.pl has a bunch of stuff you can
+modify at the command line or, again, change inside the script
+itself - warning: it's not fancy.  Try: ./add_ds.pl -h
+
+batch.pl has an 'overwrite' option that can be invoked, but I
+highly recommend that you check that this script does what you want,
+the way you want it, before you go and trample all over your 
+existing RRDs. 
+

Modified: trunk/orca/packages/rrdtool-1.0.13/perl-piped/RRDp.pm
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/perl-piped/RRDp.pm	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/perl-piped/RRDp.pm	Sat Jul 13 21:08:06 2002
@@ -110,7 +110,7 @@
 sub end ();
 sub read ();
 
-$VERSION = 1.000072 ;
+$VERSION = 1.000131 ;
 
 sub start ($){
   croak "rrdtool is already running"

Modified: trunk/orca/packages/rrdtool-1.0.13/config/acconfig.h
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/config/acconfig.h	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/config/acconfig.h	Sat Jul 13 21:08:06 2002
@@ -32,23 +32,53 @@
 # endif
 #endif
 
+
 #if NO_NULL_REALLOC
 # define rrd_realloc(a,b) ( (a) == NULL ? malloc( (b) ) : realloc( (a) , (b) ))
 #else
 # define rrd_realloc(a,b) realloc((a), (b))
 #endif      
 
-#if (! defined(HAVE_FINITE) && defined(HAVE_ISNAN) && defined(HAVE_ISINF))
-#define HAVE_FINITE 1
-#define finite(a) (! isnan(a) && ! isinf(a))
-#endif
+#if HAVE_MATH_H
+#  include <math.h>                                                                                                                      
+#endif                                                                                                                                   
+                                                                                                                                         
+#if HAVE_FLOAT_H                                                                                                                         
+#  include <float.h>                                                                                                                     
+#endif                                                                                                                                   
+ 
 
+/* for Solaris */
 #if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASS))
 #define HAVE_ISINF 1
 #include <ieeefp.h>
 #define isinf(a) (fpclass(a) == FP_NINF || fpclass(a) == FP_PINF)
 #endif
 
+/* for OSF1 Digital Unix */
+#if (! defined(HAVE_ISINF) && defined(HAVE_FP_CLASS) && defined(HAVE_FP_CLASS_H))
+#  define HAVE_ISINF 1
+#  include <fp_class.h>
+#  define isinf(a) (fp_class(a) == FP_NEG_INF || fp_class(a) == FP_POS_INF)
+#endif
+
+/* for HP-UX 10.20 */
+#if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASSIFY) )
+#  define HAVE_ISINF 1
+#  define isinf(a) (fpclassify(a) == FP_MINUS_INF || fpclassify(a) == FP_PLUS_INF)  
+#endif
+
+/* for AIX */
+#if (! defined(HAVE_ISINF) && defined(HAVE_CLASS))
+#  define HAVE_ISINF 1
+#  define isinf(a) (class(a) == FP_MINUS_INF || class(a) == FP_PLUS_INF)
+#endif
+
+#if (! defined(HAVE_FINITE) && defined(HAVE_ISNAN) && defined(HAVE_ISINF))
+#define HAVE_FINITE 1
+#define finite(a) (! isnan(a) && ! isinf(a))
+#endif
+
 #ifndef HAVE_FINITE
 #error "Can't compile without finite function"
 #endif

Modified: trunk/orca/packages/rrdtool-1.0.13/config/config.h.in
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/config/config.h.in	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/config/config.h.in	Sat Jul 13 21:08:06 2002
@@ -32,12 +32,21 @@
 /* realloc does not support NULL as argument */
 #undef NO_NULL_REALLOC
 
+/* Define if you have the class function.  */
+#undef HAVE_CLASS
+
 /* Define if you have the finite function.  */
 #undef HAVE_FINITE
 
+/* Define if you have the fp_class function.  */
+#undef HAVE_FP_CLASS
+
 /* Define if you have the fpclass function.  */
 #undef HAVE_FPCLASS
 
+/* Define if you have the fpclassify function.  */
+#undef HAVE_FPCLASSIFY
+
 /* Define if you have the getrusage function.  */
 #undef HAVE_GETRUSAGE
 
@@ -62,15 +71,27 @@
 /* Define if you have the strchr function.  */
 #undef HAVE_STRCHR
 
+/* Define if you have the vsnprintf function.  */
+#undef HAVE_VSNPRINTF
+
 /* Define if you have the <fcntl.h> header file.  */
 #undef HAVE_FCNTL_H
 
+/* Define if you have the <float.h> header file.  */
+#undef HAVE_FLOAT_H
+
+/* Define if you have the <fp_class.h> header file.  */
+#undef HAVE_FP_CLASS_H
+
 /* Define if you have the <malloc.h> header file.  */
 #undef HAVE_MALLOC_H
 
 /* Define if you have the <math.h> header file.  */
 #undef HAVE_MATH_H
 
+/* Define if you have the <sys/param.h> header file.  */
+#undef HAVE_SYS_PARAM_H
+
 /* Define if you have the <sys/resource.h> header file.  */
 #undef HAVE_SYS_RESOURCE_H
 
@@ -110,23 +131,53 @@
 # endif
 #endif
 
+
 #if NO_NULL_REALLOC
 # define rrd_realloc(a,b) ( (a) == NULL ? malloc( (b) ) : realloc( (a) , (b) ))
 #else
 # define rrd_realloc(a,b) realloc((a), (b))
 #endif      
 
-#if (! defined(HAVE_FINITE) && defined(HAVE_ISNAN) && defined(HAVE_ISINF))
-#define HAVE_FINITE 1
-#define finite(a) (! isnan(a) && ! isinf(a))
-#endif
+#if HAVE_MATH_H
+#  include <math.h>                                                                                                                      
+#endif                                                                                                                                   
+                                                                                                                                         
+#if HAVE_FLOAT_H                                                                                                                         
+#  include <float.h>                                                                                                                     
+#endif                                                                                                                                   
+ 
 
+/* for Solaris */
 #if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASS))
 #define HAVE_ISINF 1
 #include <ieeefp.h>
 #define isinf(a) (fpclass(a) == FP_NINF || fpclass(a) == FP_PINF)
 #endif
 
+/* for OSF1 Digital Unix */
+#if (! defined(HAVE_ISINF) && defined(HAVE_FP_CLASS) && defined(HAVE_FP_CLASS_H))
+#  define HAVE_ISINF 1
+#  include <fp_class.h>
+#  define isinf(a) (fp_class(a) == FP_NEG_INF || fp_class(a) == FP_POS_INF)
+#endif
+
+/* for HP-UX 10.20 */
+#if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASSIFY) )
+#  define HAVE_ISINF 1
+#  define isinf(a) (fpclassify(a) == FP_MINUS_INF || fpclassify(a) == FP_PLUS_INF)  
+#endif
+
+/* for AIX */
+#if (! defined(HAVE_ISINF) && defined(HAVE_CLASS))
+#  define HAVE_ISINF 1
+#  define isinf(a) (class(a) == FP_MINUS_INF || class(a) == FP_PLUS_INF)
+#endif
+
+#if (! defined(HAVE_FINITE) && defined(HAVE_ISNAN) && defined(HAVE_ISINF))
+#define HAVE_FINITE 1
+#define finite(a) (! isnan(a) && ! isinf(a))
+#endif
+
 #ifndef HAVE_FINITE
 #error "Can't compile without finite function"
 #endif

Modified: trunk/orca/packages/rrdtool-1.0.13/config/Makefile.in
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/config/Makefile.in	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/config/Makefile.in	Sat Jul 13 21:08:07 2002
@@ -99,7 +99,7 @@
 
 DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
 
-TAR = tar
+TAR = gtar
 GZIP_ENV = --best
 all: all-redirect
 .SUFFIXES:

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/Makefile.in
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/Makefile.in	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/Makefile.in	Sat Jul 13 21:08:07 2002
@@ -83,7 +83,7 @@
 
 CLEANFILES = *.1 *.html *.txt *-dircache *.pm
 
-POD = rrdtool.pod rrdlast.pod rrdcreate.pod rrdupdate.pod 	rrdgraph.pod  bin_dec_hex.pod rrdfetch.pod 	rrdrestore.pod rrddump.pod rrdtune.pod rrdresize.pod 	rrdcgi.pod rrdtutorial.pod
+POD = rrdtool.pod rrdlast.pod rrdcreate.pod rrdupdate.pod 	cdeftutorial.pod rpntutorial.pod rrdgraph.pod  bin_dec_hex.pod 	rrdfetch.pod rrdrestore.pod rrddump.pod rrdtune.pod rrdresize.pod 	rrdcgi.pod rrdtutorial.pod
 
 
 PMP = RRDs.pm RRDp.pm
@@ -115,7 +115,7 @@
 
 DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
 
-TAR = tar
+TAR = gtar
 GZIP_ENV = --best
 all: all-redirect
 .SUFFIXES:

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/rrdtune.html
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/rrdtune.html	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/rrdtune.html	Sat Jul 13 21:08:07 2002
@@ -1,11 +1,10 @@
-    <HTML> 
-	<HEAD> 
-	    <TITLE>tune - Modify some basic properties of a Round Robin Database
+<HTML>
+<HEAD>
+<TITLE>rrdtune</TITLE>
+<LINK REV="made" HREF="mailto:karrer at zinal.ee.ethz.ch">
+</HEAD>
 
-</TITLE> 
-	</HEAD>
-
-	<BODY>
+<BODY>
 
 <!-- INDEX BEGIN -->
 <!--
@@ -22,19 +21,14 @@
 <!-- INDEX END -->
 
 <P>
-<H1><A NAME="NAME">NAME
-
-</A></H1>
-rrdtool tune - Modify some basic properties of a Round Robin Database
-
-
+<H1><A NAME="NAME">NAME</A></H1>
 <P>
+rrdtool tune - Modify some basic properties of a Round Robin Database
 
 <P>
 <HR>
-<H1><A NAME="SYNOPSIS">SYNOPSIS
-
-</A></H1>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
 <STRONG>rrdtool</STRONG>  <STRONG>tune</STRONG>  <EM>filename</EM> 
  
 [<STRONG>--heartbeat</STRONG>|<STRONG>-h</STRONG>&nbsp;<EM>ds-name</EM>:<EM>heartbeat</EM>] 
@@ -49,111 +43,67 @@
 
 
 
-
-<P>
-
 <P>
 <HR>
-<H1><A NAME="DESCRIPTION">DESCRIPTION
-
-</A></H1>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
 The tune option allows you to alter some of the basic configuration values
 stored in the header area of a Round Robin Database (<STRONG>RRD</STRONG>). All these tunable parameters together decide when data fed into an 
 <STRONG>RRD</STRONG> is to be regarded as invalid. Invalid data is entered into the database as
 *UNKNOWN*.
 
-
 <P>
-
 The main application of the <STRONG>tune</STRONG> function is to relax the validation rules on an <STRONG>RRD</STRONG>. This allows to fill a new <STRONG>RRD</STRONG> with data available in larger intervals than what you would normally want
 to permit.
 
-
-<P>
-
 <DL>
-<DT><STRONG><A NAME="item_filename">filename
-
-</A></STRONG><DD>
+<DT><STRONG><A NAME="item_filename">filename</A></STRONG><DD>
+<P>
 The name of the <STRONG>RRD</STRONG> you want to tune.
 
-
+<DT><STRONG><A NAME="item__heartbeat_h">--heartbeat|-h ds-name:heartbeat</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__heartbeat_h">--heartbeat|-h ds-name:heartbeat
-
-</A></STRONG><DD>
 modify the <EM>heartbeat</EM> of a data source. By setting this to a high value the rrd will accept
 things like one value per day ...
 
-
+<DT><STRONG><A NAME="item__minimum_i">--minimum|-i ds-name:min</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__minimum_i">--minimum|-i ds-name:min
-
-</A></STRONG><DD>
 alter the minimum value acceptable as input from the data source. Setting <EM>min</EM> to 'U' will disable this limit.
 
-
+<DT><STRONG><A NAME="item__maximum_a">--maximum|-a ds-name:max</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__maximum_a">--maximum|-a ds-name:max
-
-</A></STRONG><DD>
 alter the maximum value acceptable as input from the data source. Setting <EM>max</EM> to 'U' will disable this limit.
 
-
+<DT><STRONG><A NAME="item__data_source_type_d">--data-source-type|-d ds-name:DST</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__data_source_type_d">--data-source-type|-d ds-name:DST
-
-</A></STRONG><DD>
 alter the type <STRONG>DST</STRONG> of a data source.
 
-
+<DT><STRONG><A NAME="item__data_source_rename_r">[--data-source-rename|-r old-name:new-name]</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__data_source_rename_r">[--data-source-rename|-r old-name:new-name]
-
-</A></STRONG><DD>
 rename a data source
 
-
-<P>
-
 </DL>
 <P>
 <HR>
-<H1><A NAME="EXAMPLE">EXAMPLE
-
-</A></H1>
+<H1><A NAME="EXAMPLE">EXAMPLE</A></H1>
+<P>
 <CODE>rrdtool tune data.rrd -h in:100000 -h in:100000 -h in:100000</CODE>
 
 
 
-
 <P>
-
 Set the minimum required heartbeat for data sources 'in', 'out' and
 'through' to 10000 seconds which is a little over one day in data.rrd. This
 would allow to feed old data from mrtg-2.0 right into rrdtool without
 generating *UNKNOWN* entries.
 
-
-<P>
-
 <P>
 <HR>
-<H1><A NAME="AUTHOR">AUTHOR
-
-</A></H1>
-Tobias Oetiker <A
-HREF="MAILTO:<oetiker at ee.ethz.ch>"><oetiker at ee.ethz.ch></A>
-
-
+<H1><A NAME="AUTHOR">AUTHOR</A></H1>
 <P>
+Tobias Oetiker &lt;<A
+HREF="mailto:oetiker at ee.ethz.ch">oetiker at ee.ethz.ch</A>&gt;
 
-</DL>
-    </BODY>
+</BODY>
 
-    </HTML>
+</HTML>

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/rrdresize.txt
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/rrdresize.txt	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/rrdresize.txt	Sat Jul 13 21:08:07 2002
@@ -1,44 +1,44 @@
 
 
 
-RRDRESIZE(1)                 rrdtool                 RRDRESIZE(1)
+rrdtool                                              RRDRESIZE(1)
+
 
 
 NNNNAAAAMMMMEEEE
-       rrdtool resize - alters the size of an RRA.
+     rrdtool resize - alters the size of an RRA.
 
 SSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS
-       rrrrrrrrddddttttoooooooollll rrrreeeessssiiiizzzzeeee _f_i_l_e_n_a_m_e _r_r_a_-_n_u_m  GGGGRRRROOOOWWWW_|SSSSHHHHRRRRIIIINNNNKKKK _r_o_w_s
+     rrrrrrrrddddttttoooooooollll rrrreeeessssiiiizzzzeeee _f_i_l_e_n_a_m_e _r_r_a-_n_u_m  GGGGRRRROOOOWWWW|SSSSHHHHRRRRIIIINNNNKKKK _r_o_w_s
 
 DDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
-       The rrrreeeessssiiiizzzzeeee function is used to modify the number of rows
-       in an RRRRRRRRAAAA.
+     The rrrreeeessssiiiizzzzeeee function is used to modify the number of rows in
+     an RRRRRRRRAAAA.
 
-       _f_i_l_e_n_a_m_e
-               the name of the RRRRRRRRDDDD you want to alter.
+     _f_i_l_e_n_a_m_e
+             the name of the RRRRRRRRDDDD you want to alter.
 
-       _r_r_a_-_n_u_m the RRRRRRRRAAAA you want to alter. You can find the number
-               using rrrrrrrrddddttttoooooooollll dddduuuummmmpppp.
+     _r_r_a-_n_u_m the RRRRRRRRAAAA you want to alter. You can find the number
+             using rrrrrrrrddddttttoooooooollll dddduuuummmmpppp.
 
-       GGGGRRRROOOOWWWW    used if you want to add extra rows to an RRA. The
-               extra rows will be inserted as the rows that are
-               oldest.
+     GGGGRRRROOOOWWWW    used if you want to add extra rows to an RRA. The
+             extra rows will be inserted as the rows that are
+             oldest.
 
-       SSSSHHHHRRRRIIIINNNNKKKK  used if you want to remove rows from an RRA. The
-               rows that will be removed are the oldest rows.
+     SSSSHHHHRRRRIIIINNNNKKKK  used if you want to remove rows from an RRA. The
+             rows that will be removed are the oldest rows.
 
-       _r_o_w_s    the number of rows you want to add or remove.
+     _r_o_w_s    the number of rows you want to add or remove.
 
 NNNNOOOOTTTTEEEESSSS
-       It is possible to abuse this tool and get strange results
-       by first removing some rows and then reinsert the same
-       amount (effectively clearing them to be Unknown). You may
-       thus end up with unknown data in one RRA while at the same
-       timestamp this data is available in another RRA.
+     It is possible to abuse this tool and get strange results by
+     first removing some rows and then reinsert the same amount
+     (effectively clearing them to be Unknown). You may thus end
+     up with unknown data in one RRA while at the same timestamp
+     this data is available in another RRA.
 
 AAAAUUUUTTTTHHHHOOOORRRR
-       Alex van den Bogaerdt <alex at ergens.op.het.net>
-
+     Alex van den Bogaerdt <alex at ergens.op.het.net>
 
 
 
@@ -60,7 +60,7 @@
 
 
 
+24/Oct/1999            Last change: 1.0.13                      1
 
-9/Aug/99                      1.0.7                             1
 
 

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/rrdcreate.txt
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/rrdcreate.txt	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/rrdcreate.txt	Sat Jul 13 21:08:07 2002
@@ -1,165 +1,231 @@
 
 
 
-RRDCREATE(1)                 rrdtool                 RRDCREATE(1)
+rrdtool                                              RRDCREATE(1)
+
 
 
 NNNNAAAAMMMMEEEE
-       rrdtool create - Set up a new Round Robin Database
+     rrdtool create - Set up a new Round Robin Database
 
 SSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS
-       rrrrrrrrddddttttoooooooollll ccccrrrreeeeaaaatttteeee _f_i_l_e_n_a_m_e [--------ssssttttaaaarrrrtttt|----bbbb _s_t_a_r_t _t_i_m_e]
-       [--------sssstttteeeepppp|----ssss _s_t_e_p] [DDDDSSSS::::_d_s_-_n_a_m_e::::_D_S_T::::_h_e_a_r_t_b_e_a_t::::_m_i_n::::_m_a_x]
-       [RRRRRRRRAAAA::::_C_F::::_x_f_f::::_s_t_e_p_s::::_r_o_w_s]
+     rrrrrrrrddddttttoooooooollll ccccrrrreeeeaaaatttteeee _f_i_l_e_n_a_m_e [--------ssssttttaaaarrrrtttt|----bbbb _s_t_a_r_t _t_i_m_e] [--------
+     sssstttteeeepppp|----ssss _s_t_e_p] [DDDDSSSS::::_d_s-_n_a_m_e::::_D_S_T::::_h_e_a_r_t_b_e_a_t::::_m_i_n::::_m_a_x]
+     [RRRRRRRRAAAA::::_C_F::::_x_f_f::::_s_t_e_p_s::::_r_o_w_s]
 
 DDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
-       The create function of the RRDtool lets you set up new
-       Round Robin Database (RRRRRRRRDDDD) files.  The file is created at
-       its final, full size and filled with _*_U_N_K_N_O_W_N_* data.
+     The create function of the RRDtool lets you set up new Round
+     Robin Database (RRRRRRRRDDDD) files. The file is created at its
+     final, full size and filled with *_U_N_K_N_O_W_N* data.
+
+     _f_i_l_e_n_a_m_e
+             The name of the RRRRRRRRDDDD you want to create. RRRRRRRRDDDD files
+             should end with the extension ._r_r_d. However, rrrrrrrrddddttttoooooooollll
+             will accept any filename.
+
+     --------ssssttttaaaarrrrtttt|-bbbb _s_t_a_r_t _t_i_m_e (default: now - 10s)
+             Specifies the time in seconds since 1970-01-01 UTC
+             when the first value should be added to the RRRRRRRRDDDD.
+             rrrrrrrrddddttttoooooooollll will not accept any data timed before or at
+             the time specified.
+
+             See also AT-STYLE TIME SPECIFICATION section in the
+             _r_r_d_f_e_t_c_h documentation for more ways to specify
+             time.
+
+     --------sssstttteeeepppp|-ssss _s_t_e_p (default: 300 seconds)
+             Specifies the base interval in seconds with which
+             data will be fed into the RRRRRRRRDDDD.
+
+     DDDDSSSS::::_d_s-_n_a_m_e::::_D_S_T::::_h_e_a_r_t_b_e_a_t::::_m_i_n::::_m_a_x
+             A single RRRRRRRRDDDD can accept input from several data
+             sources (DDDDSSSS).  (e.g. Incoming and Outgoing traffic
+             on a specific communication line). With the DDDDSSSS
+             configuration option you must define some basic
+             properties of each data source you want to use to
+             feed the RRRRRRRRDDDD.
+
+             _d_s-_n_a_m_e is the name you will use to reference this
+             particular data source from an RRRRRRRRDDDD. A _d_s-_n_a_m_e must
+             be 1 to 19 characters long in the characters [a-
+             zA-Z0-9_].
 
-       _f_i_l_e_n_a_m_e
-               The name of the RRRRRRRRDDDD you want to create. RRRRRRRRDDDD files
-               should end with the extension _._r_r_d. However,
-               rrrrrrrrddddttttoooooooollll will accept any filename.
+             _D_S_T defines the Data Source Type. It can be one of
+             the following:
 
-       --------ssssttttaaaarrrrtttt|----bbbb _s_t_a_r_t _t_i_m_e (default: now - 10s)
-               Specifies the time in seconds since 1970-01-01 UTC
-               when the first value should be added to the RRRRRRRRDDDD.
-               rrrrrrrrddddttttoooooooollll will not accept any data timed before or
-               at the time specified.
+     GGGGAAAAUUUUGGGGEEEE       is for things like temperatures or number of
+                 people in a room or value of a RedHat share.
 
-               See also AT-STYLE TIME SPECIFICATION section in
-               the _r_r_d_f_e_t_c_h documentation for more ways to
-               specify time.
 
-       --------sssstttteeeepppp|----ssss _s_t_e_p (default: 300 seconds)
-               Specifies the base interval in seconds with which
-               data will be fed into the RRRRRRRRDDDD.
 
-       DDDDSSSS::::_d_s_-_n_a_m_e::::_D_S_T::::_h_e_a_r_t_b_e_a_t::::_m_i_n::::_m_a_x
-               A single RRRRRRRRDDDD can accept input from several data
-               sources (DDDDSSSS).  (e.g. Incoming and Outgoing traffic
-               on a specific communication line). With the DDDDSSSS
-               configuration option you must define some basic
-               properties of each data source you want to use to
-               feed the RRRRRRRRDDDD.
 
-               _d_s_-_n_a_m_e is the name you will use to reference this
-               particular data source from an RRRRRRRRDDDD. A _d_s_-_n_a_m_e must
-               be 1 to 19 characters long in the characters [a-
-               zA-Z0-9_].
 
-               _D_S_T defines the Data Source Type. It can be one of
-               the following: GGGGAAAAUUUUGGGGEEEE this is for things like
-               temperatures or number of people in a room.
-               CCCCOOOOUUUUNNNNTTTTEEEERRRR is for continuous incrementing counters
-               like the InOctets counter in a router. The CCCCOOOOUUUUNNNNTTTTEEEERRRR
-               data source assumes that the counter never
-               decreases, except when a counter overflows.  The
-               update function takes the overflow into account.
-               The counter is stored as a per-second rate. DDDDEEEERRRRIIIIVVVVEEEE
+12/Feb/2000            Last change: 1.0.13                      1
 
 
 
-20/Aug/99                     1.0.7                             1
 
 
 
+rrdtool                                              RRDCREATE(1)
 
 
-RRDCREATE(1)                 rrdtool                 RRDCREATE(1)
 
+     CCCCOOOOUUUUNNNNTTTTEEEERRRR     is for continuous incrementing counters like the
+                 InOctets counter in a router. The CCCCOOOOUUUUNNNNTTTTEEEERRRR data
+                 source assumes that the counter never decreases,
+                 except when a counter overflows.  The update
+                 function takes the overflow into account.  The
+                 counter is stored as a per-second rate. When the
+                 counter overflows, RRDtool checks if the
+                 overflow happened at the 32bit or 64bit border
+                 and acts accordingly by adding an appropriate
+                 value to the result.
 
-               will store the the derivative of the line going
-               from the last to the current value of the data
-               source. This can be useful for gauges, for
-               example, to measure the rate of people entering or
-               leaving a room. AAAABBBBSSSSOOOOLLLLUUUUTTTTEEEE is for counters which get
-               reset upon reading.
+     DDDDEEEERRRRIIIIVVVVEEEE      will store the the derivative of the line going
+                 from the last to the current value of the data
+                 source. This can be useful for gauges, for
+                 example, to measure the rate of people entering
+                 or leaving a room. Internally, derive works
+                 exaclty like COUNTER but without overflow
+                 checks. So if your counter does not reset at 32
+                 or 64 bit you might want to use DERIVE and
+                 combine it with a MIN value of 0.
 
-               _h_e_a_r_t_b_e_a_t defines the maximum number of seconds
-               that may pass between two updates of this data
-               source before the value of the data source is
-               assumed to be _*_U_N_K_N_O_W_N_*.
+     AAAABBBBSSSSOOOOLLLLUUUUTTTTEEEE    is for counters which get reset upon reading.
+                 This is used for fast counters which tend to
+                 overflow. So instead of reading them normally
+                 you reset them after every read to make sure you
+                 have a maximal time available before the next
+                 overflow.
 
-               _m_i_n and _m_a_x are optional entries defining the
-               expected range of the data supplied by this data
-               source. If _m_i_n and/or _m_a_x are defined, any value
-               outside the defined range will be regarded as
-               _*_U_N_K_N_O_W_N_*. If you do not know or care about min
-               and max, set them to U for unknown. Note that min
-               and max always refer to the processed values of
-               the DS. For a traffic-CCCCOOOOUUUUNNNNTTTTEEEERRRR type DS this would
-               be the max and min data-rate expected from the
-               device.
+                 _h_e_a_r_t_b_e_a_t defines the maximum number of seconds
+                 that may pass between two updates of this data
+                 source before the value of the data source is
+                 assumed to be *_U_N_K_N_O_W_N*.
 
-               _I_f _i_n_f_o_r_m_a_t_i_o_n _o_n _m_i_n_i_m_a_l_/_m_a_x_i_m_a_l _e_x_p_e_c_t_e_d _v_a_l_u_e_s
-               _i_s _a_v_a_i_l_a_b_l_e_, _a_l_w_a_y_s _s_e_t _t_h_e _m_i_n _a_n_d_/_o_r _m_a_x
-               _p_r_o_p_e_r_t_i_e_s_. _T_h_i_s _w_i_l_l _h_e_l_p _R_R_D_t_o_o_l _i_n _d_o_i_n_g _a
-               _s_i_m_p_l_e _s_a_n_i_t_y _c_h_e_c_k _o_n _t_h_e _d_a_t_a _s_u_p_p_l_i_e_d _w_h_e_n
-               _r_u_n_n_i_n_g _u_p_d_a_t_e_.
+                 _m_i_n and _m_a_x are optional entries defining the
+                 expected range of the data supplied by this data
+                 source. If _m_i_n and/or _m_a_x are defined, any value
+                 outside the defined range will be regarded as
+                 *_U_N_K_N_O_W_N*. If you do not know or care about min
+                 and max, set them to U for unknown. Note that
+                 min and max always refer to the processed values
+                 of the DS. For a traffic-CCCCOOOOUUUUNNNNTTTTEEEERRRR type DS this
+                 would be the max and min data-rate expected from
+                 the device.
 
-       RRRRRRRRAAAA::::_C_F::::_x_f_f::::_s_t_e_p_s::::_r_o_w_s
-               The purpose of an RRRRRRRRDDDD is to store data in the
-               round robin archives (RRRRRRRRAAAA). An archive consists of
-               a number of data values from all the defined data-
-               sources (DDDDSSSS) and is defined with an RRRRRRRRAAAA line.
+                 _I_f _i_n_f_o_r_m_a_t_i_o_n _o_n _m_i_n_i_m_a_l/_m_a_x_i_m_a_l _e_x_p_e_c_t_e_d
+                 _v_a_l_u_e_s _i_s _a_v_a_i_l_a_b_l_e, _a_l_w_a_y_s _s_e_t _t_h_e _m_i_n _a_n_d/_o_r
+                 _m_a_x _p_r_o_p_e_r_t_i_e_s. _T_h_i_s _w_i_l_l _h_e_l_p _R_R_D_t_o_o_l _i_n _d_o_i_n_g
+                 _a _s_i_m_p_l_e _s_a_n_i_t_y _c_h_e_c_k _o_n _t_h_e _d_a_t_a _s_u_p_p_l_i_e_d _w_h_e_n
+                 _r_u_n_n_i_n_g _u_p_d_a_t_e.
 
-               When data is entered into an RRRRRRRRDDDD, it is first fit
-               into time slots of the length defined with the ----ssss
-               option becoming a _p_r_i_m_a_r_y _d_a_t_a _p_o_i_n_t.
+     RRRRRRRRAAAA::::_C_F::::_x_f_f::::_s_t_e_p_s::::_r_o_w_s
+             The purpose of an RRRRRRRRDDDD is to store data in the round
 
-               The data is also consolidated with the
-               consolidation function (_C_F) of the archive. The
-               following consolidation functions are defined:
-               AAAAVVVVEEEERRRRAAAAGGGGEEEE, MMMMIIIINNNN, MMMMAAAAXXXX, LLLLAAAASSSSTTTT.
 
-               _x_f_f The xfiles factor defines what part of a
-               consolidation interval may be made up from
-               _*_U_N_K_N_O_W_N_* data while the consolidated value is
-               sill regarded as known.
 
-               _s_t_e_p_s defines how many of these _p_r_i_m_a_r_y _d_a_t_a
-               _p_o_i_n_t_s are used to build a _c_o_n_s_o_l_i_d_a_t_e_d _d_a_t_a _p_o_i_n_t
-               which then goes into the archive.
+12/Feb/2000            Last change: 1.0.13                      2
 
-               _r_o_w_s defines how many generations of data values
 
 
 
-20/Aug/99                     1.0.7                             2
 
 
+rrdtool                                              RRDCREATE(1)
 
 
 
-RRDCREATE(1)                 rrdtool                 RRDCREATE(1)
+             robin archives (RRRRRRRRAAAA). An archive consists of a
+             number of data values from all the defined data-
+             sources (DDDDSSSS) and is defined with an RRRRRRRRAAAA line.
 
+             When data is entered into an RRRRRRRRDDDD, it is first fit
+             into time slots of the length defined with the ----ssss
+             option becoming a _p_r_i_m_a_r_y _d_a_t_a _p_o_i_n_t.
 
-               are kept in an RRRRRRRRAAAA.
+             The data is also consolidated with the consolidation
+             function (_C_F) of the archive. The following
+             consolidation functions are defined:  AAAAVVVVEEEERRRRAAAAGGGGEEEE, MMMMIIIINNNN,
+             MMMMAAAAXXXX, LLLLAAAASSSSTTTT.
+
+             _x_f_f The xfiles factor defines what part of a
+             consolidation interval may be made up from *_U_N_K_N_O_W_N*
+             data while the consolidated value is still regarded
+             as known.
+
+             _s_t_e_p_s defines how many of these _p_r_i_m_a_r_y _d_a_t_a _p_o_i_n_t_s
+             are used to build a _c_o_n_s_o_l_i_d_a_t_e_d _d_a_t_a _p_o_i_n_t which
+             then goes into the archive.
+
+             _r_o_w_s defines how many generations of data values are
+             kept in an RRRRRRRRAAAA.
 
 EEEEXXXXAAAAMMMMPPPPLLLLEEEE
-       rrdtool create temperature.rrd --step 300
-       DS:temp:GAUGE:600:-273:5000 RRA:AVERAGE:0.5:1:1200
-       RRA:MIN:0.5:12:2400 RRA:MAX:0.5:12:2400
-       RRA:AVERAGE:0.5:12:2400
-
-       This sets up an RRRRRRRRDDDD called _t_e_m_p_e_r_a_t_u_r_e_._r_r_d which accepts
-       one temperature value every 300 seconds. If no new data is
-       supplied for more than 600 seconds, the temperature
-       becomes _*_U_N_K_N_O_W_N_*.  The minimum acceptable value is -273
-       and the maximum is 5000.
-
-       A few archives areas are also defined. The first stores
-       the temperatures supplied for 100 hours (1200 * 300
-       seconds = 100 hours). The second RRA stores the minimum
-       temperature recorded over every hour (12 * 300 seconds = 1
-       hour), for 100 days (2400 hours). The third and the fourth
-       RRA's do the same with the for the maximum and average
-       temperature, respectively.
+     rrdtool create temperature.rrd --step 300
+     DS:temp:GAUGE:600:-273:5000 RRA:AVERAGE:0.5:1:1200
+     RRA:MIN:0.5:12:2400 RRA:MAX:0.5:12:2400
+     RRA:AVERAGE:0.5:12:2400
+
+     This sets up an RRRRRRRRDDDD called _t_e_m_p_e_r_a_t_u_r_e._r_r_d which accepts one
+     temperature value every 300 seconds. If no new data is
+     supplied for more than 600 seconds, the temperature becomes
+     *_U_N_K_N_O_W_N*.  The minimum acceptable value is -273 and the
+     maximum is 5000.
+
+     A few archives areas are also defined. The first stores the
+     temperatures supplied for 100 hours (1200 * 300 seconds =
+     100 hours). The second RRA stores the minimum temperature
+     recorded over every hour (12 * 300 seconds = 1 hour), for
+     100 days (2400 hours). The third and the fourth RRA's do the
+     same with the for the maximum and average temperature,
+     respectively.
 
 AAAAUUUUTTTTHHHHOOOORRRR
-       Tobias Oetiker <oetiker at ee.ethz.ch>
+     Tobias Oetiker <oetiker at ee.ethz.ch>
+
+
+
+
+
+
+
+
+12/Feb/2000            Last change: 1.0.13                      3
+
+
+
+
+
+
+rrdtool                                              RRDCREATE(1)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 
 
 
@@ -189,10 +255,10 @@
 
 
 
+12/Feb/2000            Last change: 1.0.13                      4
 
 
 
 
-20/Aug/99                     1.0.7                             3
 
 

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/bin_dec_hex.html
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/bin_dec_hex.html	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/bin_dec_hex.html	Sat Jul 13 21:08:07 2002
@@ -1,11 +1,10 @@
-    <HTML> 
-	<HEAD> 
-	    <TITLE>Hexadecimal - How does it wok
+<HTML>
+<HEAD>
+<TITLE>bin_dec_hex</TITLE>
+<LINK REV="made" HREF="mailto:karrer at zinal.ee.ethz.ch">
+</HEAD>
 
-</TITLE> 
-	</HEAD>
-
-	<BODY>
+<BODY>
 
 <!-- INDEX BEGIN -->
 <!--
@@ -20,33 +19,24 @@
 <!-- INDEX END -->
 
 <P>
-<H1><A NAME="NAME">NAME
-
-</A></H1>
-Binary Decimal Hexadecimal - How does it wok
-
-
+<H1><A NAME="NAME">NAME</A></H1>
 <P>
+Binary Decimal Hexadecimal - How does it work
 
 <P>
 <HR>
-<H1><A NAME="DESCRIPTION">DESCRIPTION
-
-</A></H1>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
 Most people use the decimal numbering system. This system uses ten symbols
 to represent numbers. When those ten symbols are used up, they start all
 over again and increment the position just before this. The digit 0 is only
 shown if it is the only symbol in the sequence, or if it is not the first
 one.
 
-
 <P>
-
 If this sounds as crypto to you, this is what I've said in numbers:
 
-
 <P>
-
 <PRE>     0
      1
      2
@@ -62,14 +52,10 @@
     12
     13
 </PRE>
-
 <P>
-
 and so on.
 
-
 <P>
-
 Each time the digit nine should be incremented, it is reset to 0 and the
 position before is incremented. Then number 9 can be seen as ``00009'' and
 when we should increment 9, we reset it to zero and increment the digit
@@ -78,17 +64,13 @@
 digit: ``00010'' -&gt; `` 0010'' -&gt; `` 010'' -&gt; `` 10''. It is not ``
 1 ''.
 
-
 <P>
-
 This was pretty basic, you already knew this. Why did I tell it ? Well,
 computers do not represent numbers with 10 different digits. They know of
 only two different symbols, being 0 and 1. Apply the same rules to this set
 of digits and you get the binary numbering system:
 
-
 <P>
-
 <PRE>     0
      1
     10
@@ -104,14 +86,10 @@
   1100
   1101
 </PRE>
-
 <P>
-
 and so on.
 
-
 <P>
-
 If you count the number of rows, you'll see that these are again 14
 different numbers. The numbers are the same and mean the same. It is only a
 different representation. This means that you have to know the
@@ -123,30 +101,22 @@
 down a number in the binary form. It is the number ten. If you would write
 1010 it means the number one thousand and ten.
 
-
 <P>
-
 In books, another form is most used. It uses subscript (little chars, more
 or less in between two rows). You can leave out the parentheses in that
 case and write down the number in normal characters followed with a little
 two just behind it.
 
-
 <P>
-
 The numbering system used is also called the base. We talk of the number
 1100 base 2, the number 12 base 10.
 
-
 <P>
-
 For the binary system, is is common to write leading zero's. The numbers
 are written down in series of four, eight or sixteen depending on the
 context.
 
-
 <P>
-
 We can use the binary form when talking to computers (...programming...)
 but the numbers will have large representations. The number 65535 would be
 written down as <CODE>1111111111111111(2)</CODE> which is 16 times the
@@ -157,25 +127,19 @@
 E and F. This system is chosen because the hexadecimal form can be
 converted into the binary system very easy (and back).
 
-
 <P>
-
 There is yet another system in use, called the octal system. This was more
 common in the old days but not anymore. You will find it in use on some
 places so get used to it. The same story applies, but now with only eight
 different symbols.
 
-
 <P>
-
 <PRE> Binary      (2)
  Octal       (8)
  Decimal     (10)
  Hexadecimal (16)
 </PRE>
-
 <P>
-
 <PRE> (2)    (8) (10) (16)
  00000   0    0    0
  00001   1    1    1
@@ -200,9 +164,7 @@
  10100  24   20   14
  10101  25   21   15
 </PRE>
-
 <P>
-
 Most computers used nowadays are using bytes of eight bits. This means that
 they store eight bits at a time. You can see why the octal system is not
 the most preferred for that: You'd need three digits to represent the eight
@@ -210,15 +172,11 @@
 only two bits (2+3+3=8). This is a waste. For hexadecimal digits, you need
 only two digits which are used completely:
 
-
 <P>
-
 <PRE> (2)      (8)  (10) (16)
  11111111 377  255   FF
 </PRE>
-
 <P>
-
 You can see why binary and hexadecimal can be converted quickly: For each
 hexadecimal digit there are exactly four binary digits. Take a binary
 number. Each time take four digits from the right and make a hexadecimal
@@ -226,9 +184,7 @@
 Other way around: Take a hexadecimal number. For each digit, write down its
 binary equivalent.
 
-
 <P>
-
 Computers (or rather the parsers running on them) would have a hard time
 converting a number like <CODE>1234(16).</CODE> Therefore hexadecimal
 numbers get a prefix. This prefix depends on the language you're writing
@@ -239,121 +195,85 @@
 following numbers are all the same, just the way they are written is
 different: 021 0x11 17 <CODE>%00010001</CODE>
 
-
 <P>
-
 To do arithmetics and conversions you need to understand one more thing. It
 is something you already know but perhaps you do not ``see'' it yet:
 
-
 <P>
-
 If you write down 1234, (so it is decimal) you are talking about the number
 one thousand, two hundred and thirty four. In sort of a formula:
 
-
 <P>
-
 <PRE> 1 * 1000 = 1000
  2 *  100 =  200
  3 *   10 =   30
  4 *    1 =    4
 </PRE>
-
 <P>
-
 This can also be written as:
 
-
 <P>
-
 <PRE> 1 * 10^3
  2 * 10^2
  3 * 10^1
  4 * 10^0
 </PRE>
-
 <P>
-
 where ^ means ``to the power of''.
 
-
 <P>
-
 We are using the base 10, and the positions 0,1,2 and 3. The right-most
 position should NOT be multiplied with 10. The second from the right should
 be multiplied one time with 10. The third from the right is multiplied with
 10 two times. This continues for whatever positions are used.
 
-
 <P>
-
 It is the same in all other representations:
 
-
 <P>
-
 0x1234 will be
 
-
 <P>
-
 <PRE> 1 * 16^3
  2 * 16^2
  3 * 16^1
  4 * 16^0
 </PRE>
-
 <P>
-
 01234 would be
 
-
 <P>
-
 <PRE> 1 * 8^3
  2 * 8^2
  3 * 8^1
  4 * 8^0
 </PRE>
-
 <P>
-
 This example can not be done for binary as that system can only use two
 symbols. Another example:
 
-
 <P>
-
 <CODE>%1010</CODE> would be
 
-
 <P>
-
 <PRE> 1 * 2^3
  0 * 2^2
  1 * 2^1
  0 * 2^0
 </PRE>
-
 <P>
-
 It would have been more easy to convert it to its hexadecimal form and just
 translate <CODE>%1010</CODE> into 0xA. After a while you get used to it.
 You will not need to do any calculations anymore but just know that 0xA
 means 10.
 
-
 <P>
-
 To convert a decimal number into a hexadecimal one you could use the next
 method. It will take some time to be able to do the estimates but it will
 be more and more easy when you use the system more frequent. Another way is
 presented to you thereafter.
 
-
 <P>
-
 First you will need to know how many positions will be used in the other
 system. To do so, you need to know the maximum numbers. Well, that's not so
 hard as it looks. In decimal, the maximum number that you can form with two
@@ -361,31 +281,23 @@
 need an extra position. Reverse this idea and you will see that the number
 can be found by taking 10^3 (10*10*10 is 1000) minus 1 or 10^2 minus one.
 
-
 <P>
-
 This can be done for hexadecimal too:
 
-
 <P>
-
 <PRE> 16^4 = 0x10000 = 65536
  16^3 =  0x1000 =  4096
  16^2 =   0x100 =   256
  16^1 =    0x10 =    16
 </PRE>
-
 <P>
-
 If a number is smaller than 65536 it will thus fit in four positions. If
 the number is bigger than 4095, you will need to use position 4. How many
 times can you take 4096 from the number without going below zero is the
 first digit you write down. This will always be a number from 1 to 15 (0x1
 to 0xF). Do the same for the other positions.
 
-
 <P>
-
 Number is 41029. It is smaller than 16^4 but bigger than 16^3-1. This means
 that we have to use four positions. We can subtract 16^3 from 41029 ten
 times without going below zero. The leftmost digit will be ``A'' so we have
@@ -396,23 +308,17 @@
 ``4'' to get 0xA04?. Take 64 from 69 (69 - 4*16) and the last digit is 5
 --&gt; 0xA045.
 
-
 <P>
-
 The other method builds the number from the right. Take again 41029. Divide
 by 16 and do not use fractions (only whole numbers).
 
-
 <P>
-
 <PRE> 41029 / 16 is 2564 with a remainder of 5. Write down 5.
  2564 / 16 is 160 with a remainder of 4. Write the 4 before the 5.
  160 / 16 is 10 with no remainder. Prepend 45 with 0.
  10 / 16 is below one. End here and prepend 0xA. End up with 0xA045.
 </PRE>
-
 <P>
-
 Which method to use is up to you. Use whatever works for you. Personally I
 use them both without being able to tell what method I use in each case, it
 just depends on the number, I think. Fact is, some numbers will occur
@@ -420,9 +326,7 @@
 first method (like 32770, translate into 32768 + 2 and just know that it is
 0x8000 + 0x2 = 0x8002).
 
-
 <P>
-
 For binary the same approach can be used. The base is 2 and not 16, and the
 number of positions will grow rapidly. Using the second method has the
 advantage that you can see very simple if you should write down a zero or a
@@ -435,37 +339,25 @@
 remainder 0 5 / 2 = 2 remainder 1 2 / 2 = 1 remainder 0 1 / 2 below 0
 remainder 1
 
-
 <P>
-
 Write down the results from right to left: <CODE>%1010000001000101</CODE>
 
-
 <P>
-
 Group by four:
 
-
 <P>
-
 <PRE> %1010000001000101
  %101000000100 0101
  %10100000 0100 0101
  %1010 0000 0100 0101
 </PRE>
-
 <P>
-
 Convert into hexadecimal: 0xA045
 
-
 <P>
-
 Group <CODE>%1010000001000101</CODE> by three and convert into octal:
 
-
 <P>
-
 <PRE> %1010000001000101
  %1010000001000 101
  %1010000001 000 101
@@ -475,16 +367,12 @@
  %001 010 000 001 000 101
     1   2   0   1   0   5 --&gt; 0120105
 </PRE>
-
 <P>
-
 <PRE> So: %1010000001000101 = 0120105 = 0xA045 = 41029
  Or: 1010000001000101(2) = 120105(8) = A045(16) = 41029(10)
  Or: 1010000001000101(2) = 120105(8) = A045(16) = 41029
 </PRE>
-
 <P>
-
 At first while adding numbers, you'll convert them to their decimal form
 and then back into their original form after doing the addition. If you use
 the other numbering system often, you will see that you'll be able to do
@@ -493,19 +381,13 @@
 result, remember the other digits and use them in the next round. Continue
 with the second digits from the right and so on:
 
-
 <P>
-
 <PRE>    %1010 + %0111 --&gt; 10 + 7 --&gt; 17 --&gt; %00010001
 </PRE>
-
 <P>
-
 will become
 
-
 <P>
-
 <PRE>    %1010
     %0111 +
      ||||
@@ -517,53 +399,37 @@
  --------
    %10001 is the result, I like to write it as %00010001
 </PRE>
-
 <P>
-
 For low values, try to do the calculations yourself, check them with a
 calculator. The more you do the calculations yourself, the more you find
 that you didn't make mistakes. In the end, you'll do calculi in other bases
 as easy as you do in decimal.
 
-
 <P>
-
 When the numbers get bigger, you'll have to realize that a computer is not
 called a computer just to have a nice name. There are many different
 calculators available. Use them. For Unix you could use ``bc'' which is
 called so as it is short for Binary Calculator. It calculates not only in
 decimal, but in all bases you'll ever use (among them Binary).
 
-
 <P>
-
 For people on Windows: Start the calculator
 (start-&gt;programs-&gt;accessories-&gt;calculator) and if necessary click
 view-&gt;scientific. You now have a scientific calculator and can compute
 in binary or hexadecimal.
 
-
-<P>
-
 <P>
 <HR>
-<H1><A NAME="AUTHOR">AUTHOR
-
-</A></H1>
+<H1><A NAME="AUTHOR">AUTHOR</A></H1>
+<P>
 I hope you enjoyed the examples and their descriptions. If you do, help
 other people by pointing them to this document when they are asking basic
 questions. They will not only get their answer but at the same time learn a
 whole lot more.
 
-
 <P>
+Alex van den Bogaerdt &lt;<A
+HREF="mailto:alex at ergens.op.het.net">alex at ergens.op.het.net</A>&gt;
+</BODY>
 
-Alex van den Bogaerdt <A
-HREF="MAILTO:<alex at ergens.op.het.net>"><alex at ergens.op.het.net></A>
-
-<P>
-
-</DL>
-    </BODY>
-
-    </HTML>
+</HTML>

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/rrdcreate.pod
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/rrdcreate.pod	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/rrdcreate.pod	Sat Jul 13 21:08:08 2002
@@ -51,16 +51,39 @@
 the characters [a-zA-Z0-9_].
 
 I<DST> defines the Data Source Type. It can be one of the following:
-B<GAUGE> this is for things like temperatures or number of people in a
-room. B<COUNTER> is for continuous incrementing counters like the
+
+=over 4
+
+=item B<GAUGE> 
+
+is for things like temperatures or number of people in a
+room or value of a RedHat share.
+
+=item B<COUNTER>
+
+is for continuous 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.  The counter is stored as a
-per-second rate. B<DERIVE> will store the
-the derivative of the line going from the last to the current value of the
-data source. This can be useful for gauges,
-for example, to measure the rate of people
-entering or leaving a room. B<ABSOLUTE> is for counters which get reset upon reading.
+per-second rate. When the counter overflows, RRDtool checks if the overflow happened at
+the 32bit or 64bit border and acts accordingly by adding an appropriate value to the result.
+
+=item B<DERIVE>
+
+will store the the derivative of the line going from the last to the current
+value of the data source. This can be useful for gauges, for example, to
+measure the rate of people entering or leaving a room. Internally, derive works exaclty like
+COUNTER but without overflow checks. So if your counter does not reset at 32 or 64 bit
+you might want to use DERIVE and combine it with a MIN value of 0.
+
+=item B<ABSOLUTE> 
+
+is for counters which get reset upon reading. This is used for fast counters
+which tend to overflow. So instead of reading them normally you reset them
+after every read to make sure you have a maximal time available before the
+next overflow.
+
+=back
 
 I<heartbeat> defines the maximum number of seconds that may pass
 between two updates of this data source before the value of the 
@@ -92,7 +115,7 @@
 B<AVERAGE>, B<MIN>, B<MAX>, B<LAST>.
 
 I<xff> The xfiles factor defines what part of a consolidation interval may
-be made up from I<*UNKNOWN*> data while the consolidated value is sill
+be made up from I<*UNKNOWN*> data while the consolidated value is still
 regarded as known.
 
 I<steps> defines how many of these I<primary data points> are used to

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/rrdupdate.html
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/rrdupdate.html	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/rrdupdate.html	Sat Jul 13 21:08:08 2002
@@ -1,11 +1,10 @@
-    <HTML> 
-	<HEAD> 
-	    <TITLE>update - Store a new set of values into the rrd
+<HTML>
+<HEAD>
+<TITLE>rrdupdate</TITLE>
+<LINK REV="made" HREF="mailto:karrer at zinal.ee.ethz.ch">
+</HEAD>
 
-</TITLE> 
-	</HEAD>
-
-	<BODY>
+<BODY>
 
 <!-- INDEX BEGIN -->
 <!--
@@ -22,19 +21,14 @@
 <!-- INDEX END -->
 
 <P>
-<H1><A NAME="NAME">NAME
-
-</A></H1>
-rrdtool update - Store a new set of values into the rrd
-
-
+<H1><A NAME="NAME">NAME</A></H1>
 <P>
+rrdtool update - Store a new set of values into the rrd
 
 <P>
 <HR>
-<H1><A NAME="SYNOPSIS">SYNOPSIS
-
-</A></H1>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
 <STRONG>rrdtool</STRONG>  <STRONG>update</STRONG>  <EM>filename</EM> 
  
 [<STRONG>--template</STRONG>|<STRONG>-t</STRONG>&nbsp;<EM>ds-name</EM>[<STRONG>:</STRONG><EM>ds-name</EM>]...] 
@@ -45,49 +39,31 @@
 
 
 
-
-<P>
-
 <P>
 <HR>
-<H1><A NAME="DESCRIPTION">DESCRIPTION
-
-</A></H1>
-The <STRONG>update</STRONG> function feeds new data values into an <STRONG>RRD</STRONG>. The data gets time aligned according to the properties of the <STRONG>RRD</STRONG> to which the data is written.
-
-
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
 <P>
+The <STRONG>update</STRONG> function feeds new data values into an <STRONG>RRD</STRONG>. The data gets time aligned according to the properties of the <STRONG>RRD</STRONG> to which the data is written.
 
 <DL>
-<DT><STRONG><A NAME="item_filename">filename
-
-</A></STRONG><DD>
+<DT><STRONG><A NAME="item_filename">filename</A></STRONG><DD>
+<P>
 The name of the <STRONG>RRD</STRONG> you want to update.
 
-
+<DT><STRONG><A NAME="item__template_t">--template|-t ds-name[:ds-name]...</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__template_t">--template|-t ds-name[:ds-name]...
-
-</A></STRONG><DD>
 by default, the update function expects the data input in the order, the
 data sources are defined in the RRD. This is not very error resistant, as
 you might be sending the wrong data into a RRD.
 
-
 <P>
-
 The template switch allows you to specify which data sources you are going
 to update and in which order. If the data sources specified in the template
 are not available in the rrd file, the update process will abort with an
 error message.
 
-
+<DT><STRONG><A NAME="item_N">N|timestamp:value[:value...]</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_N">N|timestamp:value[:value...]
-
-</A></STRONG><DD>
 The data used for updating the RRD was acquired at a certain time. This
 time can either be defined in seconds since 1970-01-01. Or by using the
 letter 'N' the update time is set to be the current time. Negative time
@@ -96,70 +72,48 @@
 of type <STRONG>COUNTER</STRONG>,
 <STRONG>DERIVE</STRONG> or <STRONG>ABSOLUTE</STRONG>. 
 
-
 <P>
-
 The remaining elements of the argument are DS updates. The order of this
 list is the same as the order the data sources were defined in the rra. If
 there is no data for a certain data-source, the letter 
 <STRONG>U</STRONG> (eg. N:0.1:U:1) can be defined.
 
-
 <P>
-
 The format of the value acquired from the data source is dependent of the
 data source type chosen. Normally it will be numeric, but the data
 acquisition modules my impose their very own parsing of this parameter as
 long as the colon (<STRONG>:</STRONG>) remains the data source value separator.
 
-
-<P>
-
 </DL>
 <P>
 <HR>
-<H1><A NAME="EXAMPLE">EXAMPLE
-
-</A></H1>
+<H1><A NAME="EXAMPLE">EXAMPLE</A></H1>
+<P>
 <CODE>rrdtool update demo1.rrd N:3.44:3.15:U:23</CODE>
 
 
 
-
 <P>
-
 Update the database file demo1.rrd with 3 known and one <EM>*UNKNOWN*</EM>
 value. Use the current time as the update time.
 
-
 <P>
-
 <CODE>rrdtool update demo2.rrd 887457267:U 887457521:22 88745790:2.7</CODE>
 
 
 
-
 <P>
-
 Update the database file demo2.rrd which expects data from a single
 data-source, three times. First with an <EM>*UNKNOWN*</EM> value then with two normal readings. The update interval seems to be around
 300 seconds.
 
-
-<P>
-
 <P>
 <HR>
-<H1><A NAME="AUTHOR">AUTHOR
-
-</A></H1>
-Tobias Oetiker <A
-HREF="MAILTO:<oetiker at ee.ethz.ch>"><oetiker at ee.ethz.ch></A>
-
-
+<H1><A NAME="AUTHOR">AUTHOR</A></H1>
 <P>
+Tobias Oetiker &lt;<A
+HREF="mailto:oetiker at ee.ethz.ch">oetiker at ee.ethz.ch</A>&gt;
 
-</DL>
-    </BODY>
+</BODY>
 
-    </HTML>
+</HTML>

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/rrdtune.txt
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/rrdtune.txt	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/rrdtune.txt	Sat Jul 13 21:08:08 2002
@@ -1,82 +1,82 @@
 
 
 
-RRDTUNE(1)                   rrdtool                   RRDTUNE(1)
+rrdtool                                                RRDTUNE(1)
+
 
 
 NNNNAAAAMMMMEEEE
-       rrdtool tune - Modify some basic properties of a Round
-       Robin Database
+     rrdtool tune - Modify some basic properties of a Round Robin
+     Database
 
 SSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS
-       rrrrrrrrddddttttoooooooollll ttttuuuunnnneeee _f_i_l_e_n_a_m_e [--------hhhheeeeaaaarrrrttttbbbbeeeeaaaatttt|----hhhh _d_s_-_n_a_m_e:_h_e_a_r_t_b_e_a_t]
-       [--------mmmmiiiinnnniiiimmmmuuuummmm|----iiii _d_s_-_n_a_m_e:_m_i_n] [--------mmmmaaaaxxxxiiiimmmmuuuummmm|----aaaa _d_s_-_n_a_m_e:_m_a_x]
-       [--------ddddaaaattttaaaa----ssssoooouuuurrrrcccceeee----ttttyyyyppppeeee|----dddd _d_s_-_n_a_m_e:_D_S_T]
-       [--------ddddaaaattttaaaa----ssssoooouuuurrrrcccceeee----rrrreeeennnnaaaammmmeeee|----rrrr _o_l_d_-_n_a_m_e:_n_e_w_-_n_a_m_e]
+     rrrrrrrrddddttttoooooooollll ttttuuuunnnneeee _f_i_l_e_n_a_m_e [--------hhhheeeeaaaarrrrttttbbbbeeeeaaaatttt|----hhhh _d_s-_n_a_m_e:_h_e_a_r_t_b_e_a_t] [----
+     ----mmmmiiiinnnniiiimmmmuuuummmm|----iiii _d_s-_n_a_m_e:_m_i_n] [--------mmmmaaaaxxxxiiiimmmmuuuummmm|----aaaa _d_s-_n_a_m_e:_m_a_x] [--------
+     ddddaaaattttaaaa----ssssoooouuuurrrrcccceeee----ttttyyyyppppeeee|----dddd _d_s-_n_a_m_e:_D_S_T] [--------ddddaaaattttaaaa----ssssoooouuuurrrrcccceeee----
+     rrrreeeennnnaaaammmmeeee|----rrrr _o_l_d-_n_a_m_e:_n_e_w-_n_a_m_e]
 
 DDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
-       The tune option allows you to alter some of the basic
-       configuration values stored in the header area of a Round
-       Robin Database (RRRRRRRRDDDD).  All these tunable parameters
-       together decide when data fed into an RRRRRRRRDDDD is to be
-       regarded as invalid. Invalid data is entered into the
-       database as *UNKNOWN*.
-
-       The main application of the ttttuuuunnnneeee function is to relax the
-       validation rules on an RRRRRRRRDDDD. This allows to fill a new RRRRRRRRDDDD
-       with data available in larger intervals than what you
-       would normally want to permit.
-
-       _f_i_l_e_n_a_m_e
-               The name of the RRRRRRRRDDDD you want to tune.
-
-       --------hhhheeeeaaaarrrrttttbbbbeeeeaaaatttt|----hhhh _d_s_-_n_a_m_e:_h_e_a_r_t_b_e_a_t
-               modify the _h_e_a_r_t_b_e_a_t of a data source. By setting
-               this to a high value the rrd will accept things
-               like one value per day ...
-
-       --------mmmmiiiinnnniiiimmmmuuuummmm|----iiii _d_s_-_n_a_m_e:_m_i_n
-               alter the minimum value acceptable as input from
-               the data source.  Setting _m_i_n to 'U' will disable
-               this limit.
-
-       --------mmmmaaaaxxxxiiiimmmmuuuummmm|----aaaa _d_s_-_n_a_m_e:_m_a_x
-               alter the maximum value acceptable as input from
-               the data source.  Setting _m_a_x to 'U' will disable
-               this limit.
+     The tune option allows you to alter some of the basic
+     configuration values stored in the header area of a Round
+     Robin Database (RRRRRRRRDDDD).  All these tunable parameters together
+     decide when data fed into an RRRRRRRRDDDD is to be regarded as
+     invalid. Invalid data is entered into the database as
+     *UNKNOWN*.
+
+     The main application of the ttttuuuunnnneeee function is to relax the
+     validation rules on an RRRRRRRRDDDD. This allows to fill a new RRRRRRRRDDDD
+     with data available in larger intervals than what you would
+     normally want to permit.
+
+     _f_i_l_e_n_a_m_e
+             The name of the RRRRRRRRDDDD you want to tune.
+
+     --------hhhheeeeaaaarrrrttttbbbbeeeeaaaatttt|-hhhh _d_s-_n_a_m_e:_h_e_a_r_t_b_e_a_t
+             modify the _h_e_a_r_t_b_e_a_t of a data source. By setting
+             this to a high value the rrd will accept things like
+             one value per day ...
+
+     --------mmmmiiiinnnniiiimmmmuuuummmm|-iiii _d_s-_n_a_m_e:_m_i_n
+             alter the minimum value acceptable as input from the
+             data source.  Setting _m_i_n to 'U' will disable this
+             limit.
+
+     --------mmmmaaaaxxxxiiiimmmmuuuummmm|-aaaa _d_s-_n_a_m_e:_m_a_x
+             alter the maximum value acceptable as input from the
+             data source.  Setting _m_a_x to 'U' will disable this
+             limit.
 
-       --------ddddaaaattttaaaa----ssssoooouuuurrrrcccceeee----ttttyyyyppppeeee|----dddd _d_s_-_n_a_m_e:_D_S_T
-               alter the type DDDDSSSSTTTT of a data source.
+     --------ddddaaaattttaaaa----ssssoooouuuurrrrcccceeee----ttttyyyyppppeeee|-dddd _d_s-_n_a_m_e:_D_S_T
+             alter the type DDDDSSSSTTTT of a data source.
 
-       [--------ddddaaaattttaaaa----ssssoooouuuurrrrcccceeee----rrrreeeennnnaaaammmmeeee|----rrrr _o_l_d_-_n_a_m_e:_n_e_w_-_n_a_m_e]
-               rename a data source
+     [--------ddddaaaattttaaaa----ssssoooouuuurrrrcccceeee----rrrreeeennnnaaaammmmeeee|-rrrr _o_l_d-_n_a_m_e:_n_e_w-_n_a_m_e]
+             rename a data source
 
 EEEEXXXXAAAAMMMMPPPPLLLLEEEE
-       rrdtool tune data.rrd -h in:100000 -h in:100000 -h
-       in:100000
+     rrdtool tune data.rrd -h in:100000 -h in:100000 -h in:100000
 
-       Set the minimum required heartbeat for data sources 'in',
-       'out' and 'through' to 10000 seconds which is a little
-       over one day in data.rrd.  This would allow to feed old
+     Set the minimum required heartbeat for data sources 'in',
+     'out' and 'through' to 10000 seconds which is a little over
 
 
 
-9/Aug/99                      1.0.7                             1
+24/Oct/1999            Last change: 1.0.13                      1
 
 
 
 
 
-RRDTUNE(1)                   rrdtool                   RRDTUNE(1)
 
+rrdtool                                                RRDTUNE(1)
 
-       data from mrtg-2.0 right into rrdtool without generating
-       *UNKNOWN* entries.
 
-AAAAUUUUTTTTHHHHOOOORRRR
-       Tobias Oetiker <oetiker at ee.ethz.ch>
 
+     one day in data.rrd.  This would allow to feed old data from
+     mrtg-2.0 right into rrdtool without generating *UNKNOWN*
+     entries.
 
+AAAAUUUUTTTTHHHHOOOORRRR
+     Tobias Oetiker <oetiker at ee.ethz.ch>
 
 
 
@@ -126,7 +126,7 @@
 
 
 
+24/Oct/1999            Last change: 1.0.13                      2
 
-9/Aug/99                      1.0.7                             2
 
 

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/rrdfetch.html
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/rrdfetch.html	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/rrdfetch.html	Sat Jul 13 21:08:08 2002
@@ -1,11 +1,10 @@
-    <HTML> 
-	<HEAD> 
-	    <TITLE>fetch - fetch data from an rrd.
+<HTML>
+<HEAD>
+<TITLE>rrdfetch</TITLE>
+<LINK REV="made" HREF="mailto:karrer at zinal.ee.ethz.ch">
+</HEAD>
 
-</TITLE> 
-	</HEAD>
-
-	<BODY>
+<BODY>
 
 <!-- INDEX BEGIN -->
 <!--
@@ -29,19 +28,14 @@
 <!-- INDEX END -->
 
 <P>
-<H1><A NAME="NAME">NAME
-
-</A></H1>
-rrdtool fetch - fetch data from an rrd.
-
-
+<H1><A NAME="NAME">NAME</A></H1>
 <P>
+rrdtool fetch - fetch data from an rrd.
 
 <P>
 <HR>
-<H1><A NAME="SYNOPSIS">SYNOPSIS
-
-</A></H1>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
 <STRONG>rrdtool</STRONG>  <STRONG>fetch</STRONG>  <EM>filename</EM>  <EM>CF</EM> 
  
 [<STRONG>--resolution</STRONG>|<STRONG>-r</STRONG>&nbsp;<EM>resolution</EM>] 
@@ -52,131 +46,87 @@
 
  
 
-
-<P>
-
 <P>
 <HR>
-<H1><A NAME="DESCRIPTION">DESCRIPTION
-
-</A></H1>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
 The <STRONG>fetch</STRONG> function is normally used internally by the graph function, to get data
 from <STRONG>RRD</STRONG>s. <STRONG>fetch</STRONG> will analyze the <STRONG>RRD</STRONG> and will try to retrieve the data in the resolution requested. The data
 fetched is printed to stdout. <EM>*UNKNOWN*</EM> data is often represented by the string ``NaN'' depending on your OSs
 printf function.
 
-
-<P>
-
 <DL>
-<DT><STRONG><A NAME="item_filename">filename 
-
-</A></STRONG><DD>
+<DT><STRONG><A NAME="item_filename">filename</A></STRONG><DD>
+<P>
 the name of the <STRONG>RRD</STRONG> you want to fetch the data from.
 
-
+<DT><STRONG><A NAME="item_CF">CF</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_CF">CF 
-
-</A></STRONG><DD>
 which consolidation function should have been applied to the data you want
 to fetch? (AVERAGE,MIN,MAX,LAST)
 
-
+<DT><STRONG><A NAME="item__resolution_r">--resolution|-r resolution (default is the highest resolution)</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__resolution_r">--resolution|-r resolution (default is the highest resolution)
-
-</A></STRONG><DD>
 what interval should the values have (seconds per value). <STRONG>rrdfetch</STRONG> will try to match your request, but it will return data even if no absolute
 match is possible.
 
-
+<DT><STRONG><A NAME="item__start_s">--start|-s start (default end-1day)</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__start_s">--start|-s start (default end-1day)
-
-</A></STRONG><DD>
 when should the data begin. A time in seconds since epoch (1970-01-01) is
 required. Negative numbers are relative to the current time. By default one
 day worth of data will be fetched. See also AT-STYLE TIME SPECIFICATION
 section for a detailed explanation on ways to specify start time.
 
-
+<DT><STRONG><A NAME="item__end_e">--end|-e end (default now)</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__end_e">--end|-e end (default now)
-
-</A></STRONG><DD>
 when should the data end. Time in seconds since epoch. See also AT-STYLE
 TIME SPECIFICATION section for a detailed explanation of how to specify end
 time.
 
-
-<P>
-
 </DL>
 <P>
 <HR>
-<H2><A NAME="AT_STYLE_TIME_SPECIFICATION">AT-STYLE TIME SPECIFICATION
-
-</A></H2>
+<H2><A NAME="AT_STYLE_TIME_SPECIFICATION">AT-STYLE TIME SPECIFICATION</A></H2>
+<P>
 Apart from the traditional <EM>Seconds since epoch</EM>, rrdtool does also understand at-style time specification. The
 specification is called ``at-style'' after Unix command <CODE>at(1)</CODE>
 that has moderately complex ways to specify time to run your job at. The
 at-style specification consists of two parts: <STRONG>TIME REFERENCE</STRONG> specification and <STRONG>TIME
 OFFSET</STRONG> specification.
 
-
-<P>
-
 <P>
 <HR>
-<H2><A NAME="TIME_REFERENCE_SPECIFICATION">TIME REFERENCE SPECIFICATION
-
-</A></H2>
+<H2><A NAME="TIME_REFERENCE_SPECIFICATION">TIME REFERENCE SPECIFICATION</A></H2>
+<P>
 Time reference specification is used, well,... to establish a reference
 moment in time (for time offset to be applied to). When present, it should
 come first, when omitted, it defaults to <STRONG>now</STRONG>. On its own part, time reference consists of <EM>time-of-day</EM> reference (which should come first, if present) and <EM>day</EM> reference.
 
-
 <P>
-
 <EM>Time-of-day</EM> can be specified as <STRONG>HH:MM</STRONG>, <STRONG>HH.MM</STRONG>, or just <STRONG>HH</STRONG>, you can suffix it with <STRONG>am</STRONG> or <STRONG>pm</STRONG> or use 24-hours clock. The few special times of day are understood as well,
 these include <STRONG>midnight</STRONG> (00:00), <STRONG>noon</STRONG> (12:00) and British
 <STRONG>teatime</STRONG> (16:00).
 
-
 <P>
-
 The <EM>day</EM> can be specified as <EM>month-name</EM>  <EM>day-of-the-month</EM>
 and optional 2- or 4-digit <EM>year</EM> number (e.g. March 8 1999). Alternatively, you can use <EM>day-of-week-name</EM> (e.g. Monday), or one of the words: <STRONG>yesterday</STRONG>, <STRONG>today</STRONG>, <STRONG>tomorrow</STRONG>. You can also specify <EM>day</EM> as a full date in several numerical formats; these include: <STRONG>MM/DD/[YY]YY</STRONG>, <STRONG>DD.MM.[YY]YY</STRONG>, <STRONG>YYYYMMDD</STRONG>
 (<EM>NOTE1</EM>: this is different from the original <CODE>at(1)</CODE> behavior, which
 interprets a single-number date as MMDD[YY]YY)
 <EM>NOTE2</EM>: if you specify <EM>day</EM> this way, the <EM>time-of-day</EM> is REQUIRED to be present.
 
-
 <P>
-
 Finally, you can use words <STRONG>now</STRONG>, <STRONG>start</STRONG>, or <STRONG>end</STRONG> as your time reference. <STRONG>Now</STRONG> refers to the current moment (and is also a default time reference). <STRONG>Start</STRONG> (<STRONG>end</STRONG>) can be used to specify time relative to the start (end) time for those
 tools that use these categories (rrdfetch, rrdgraph).
 
-
 <P>
-
 Month and weekday names can be used in their naturally abbreviated form
 (e.g., Dec for December, Sun for Sunday, etc.). The words <STRONG>now</STRONG>,
 <STRONG>start</STRONG>, <STRONG>end</STRONG> can be abbreviated to <STRONG>n</STRONG>, <STRONG>s</STRONG>, <STRONG>e</STRONG>.
 
-
-<P>
-
 <P>
 <HR>
-<H2><A NAME="TIME_OFFSET_SPECIFICATION">TIME OFFSET SPECIFICATION
-
-</A></H2>
+<H2><A NAME="TIME_OFFSET_SPECIFICATION">TIME OFFSET SPECIFICATION</A></H2>
+<P>
 Time offset specification is used to add (or subtract) certain time
 interval to (from) the time reference moment. It consists of <EM>sign</EM>
 (<STRONG>+</STRONG>&nbsp;or&nbsp;<STRONG>-</STRONG>) and <EM>amount</EM>. The following time units can be used to specify the <EM>amount</EM>: <STRONG>years</STRONG>, <STRONG>months</STRONG>, <STRONG>weeks</STRONG>, <STRONG>days</STRONG>,
@@ -186,9 +136,7 @@
 concatenated (e.g., -5h45min = -5h-45min = -6h+15min = -7h+1h30m-15min,
 etc.)
 
-
 <P>
-
 <EM>NOTE3</EM>: If you specify time offset in days, weeks, months, or years, you will end
 with the time offset that may vary depending on you time reference, because
 all those time units have no single well defined time interval value (1&nbsp;year contains either 365 or 366 days, 1&nbsp;month
@@ -209,116 +157,74 @@
 8:00&nbsp;Mar&nbsp;27&nbsp;1999 and 8:00&nbsp;Mar&nbsp;29&nbsp;1999 equals 47 hours; on the other hand,
 '8:00&nbsp;Mar&nbsp;27&nbsp;1999&nbsp;+48&nbsp;hours' = '9:00&nbsp;Mar&nbsp;29&nbsp;1999', as expected)
 
-
 <P>
-
 <EM>NOTE4</EM>: The single-letter abbreviation for both <STRONG>months</STRONG> and <STRONG>minutes</STRONG>
 is <STRONG>m</STRONG>. To disambiguate, the parser tries to read your mind&nbsp;:)
 by applying the following two heuristics:
 
-
-<P>
-
 <OL>
-<LI><STRONG><A NAME="item_">
-
-</A></STRONG>
+<LI>
+<P>
 If <STRONG>m</STRONG> is used in context of (i.e. right after the) years, months, weeks, or days
 it is assumed to mean <STRONG>months</STRONG>, while in the context of hours, minutes, and seconds it means minutes.
 (e.g., in -1y6m or +3w1m <STRONG>m</STRONG> means <STRONG>months</STRONG>, while in -3h20m or +5s2m <STRONG>m</STRONG> means <STRONG>minutes</STRONG>)
 
-
+<LI>
 <P>
-
-<LI><STRONG><A NAME="item_">
-
-</A></STRONG>
 Out of context (i.e. right after the <STRONG>+</STRONG> or <STRONG>-</STRONG> sign) the meaning of <STRONG>m</STRONG> is guessed from the number it directly follows. Currently, if the number
 absolute value is below 25 it is assumed that <STRONG>m</STRONG> means <STRONG>months</STRONG>, otherwise it is treated as <STRONG>minutes</STRONG>. (e.g., -25m == -25 minutes, while +24m == +24 months)
 
-
-<P>
-
 </OL>
+<P>
 <EM>Final NOTES</EM>: Time specification is case-insensitive. Whitespace can be inserted freely
 or omitted altogether, there are, however, cases when whitespace is
 required (e.g., 'midnight&nbsp;Thu'). In this case you should either quote the whole phrase to prevent it from
 being taken apart by your shell or use '_' (underscore) or ',' (comma)
 which also count as whitespace (e.g., midnight_Thu or midnight,Thu)
 
-
-<P>
-
 <P>
 <HR>
-<H2><A NAME="TIME_SPECIFICATION_EXAMPLES">TIME SPECIFICATION EXAMPLES
-
-</A></H2>
+<H2><A NAME="TIME_SPECIFICATION_EXAMPLES">TIME SPECIFICATION EXAMPLES</A></H2>
+<P>
 <EM>Oct 12</EM> -- October 12 this year
 
-
 <P>
-
 <EM>-1month</EM> or <EM>-1m</EM> -- current time of day, only a month before (may yield surprises, see the
 NOTE3 above)
 
-
 <P>
-
 <EM>noon yesterday -3hours</EM> -- yesterday morning; can be put also as <EM>9am-1day</EM>
 
 
 
-
 <P>
-
 <EM>23:59 31.12.1999</EM> -- 1 minute to the year 2000
 
-
 <P>
-
 <EM>12/31/99 11:59pm</EM> -- 1 minute to the year 2000 for imperialists
 
-
 <P>
-
 <EM>12am 01/01/01</EM> -- start of the new millennium
 
-
 <P>
-
 <EM>end-3weeks</EM> or <EM>e-3w</EM> -- 3 weeks before end time (may be used as start time specification)
 
-
 <P>
-
 <EM>start+6hours</EM> or <EM>s+6h</EM> -- 6 hours after start time (may be used as end time specification)
 
-
 <P>
-
 <EM>931225537</EM> -- 18:45 July 5th, 1999 (yes, seconds since 1970 are valid as well)
 
-
 <P>
-
 <EM>19970703 12:45</EM> -- 12:45 July 3th, 1997 (not quote standard, but I love this ...)
 
-
-<P>
-
 <P>
 <HR>
-<H1><A NAME="AUTHOR">AUTHOR
-
-</A></H1>
-Tobias Oetiker <A
-HREF="MAILTO:<oetiker at ee.ethz.ch>"><oetiker at ee.ethz.ch></A>
-
-
+<H1><A NAME="AUTHOR">AUTHOR</A></H1>
 <P>
+Tobias Oetiker &lt;<A
+HREF="mailto:oetiker at ee.ethz.ch">oetiker at ee.ethz.ch</A>&gt;
 
-</DL>
-    </BODY>
+</BODY>
 
-    </HTML>
+</HTML>

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/bin_dec_hex.txt
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/bin_dec_hex.txt	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/bin_dec_hex.txt	Sat Jul 13 21:08:08 2002
@@ -1,54 +1,55 @@
 
 
 
-BIN_DEC_HEX(1)               rrdtool               BIN_DEC_HEX(1)
+rrdtool                                            BIN_DEC_HEX(1)
+
 
 
 NNNNAAAAMMMMEEEE
-       Binary Decimal Hexadecimal - How does it wok
+     Binary Decimal Hexadecimal - How does it work
 
 DDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
-       Most people use the decimal numbering system. This system
-       uses ten symbols to represent numbers. When those ten
-       symbols are used up, they start all over again and
-       increment the position just before this. The digit 0 is
-       only shown if it is the only symbol in the sequence, or if
-       it is not the first one.
+     Most people use the decimal numbering system. This system
+     uses ten symbols to represent numbers. When those ten
+     symbols are used up, they start all over again and increment
+     the position just before this. The digit 0 is only shown if
+     it is the only symbol in the sequence, or if it is not the
+     first one.
 
-       If this sounds as crypto to you, this is what I've said in
-       numbers:
+     If this sounds as crypto to you, this is what I've said in
+     numbers:
 
-            0
-            1
-            2
-            3
-            4
-            5
-            6
-            7
-            8
-            9
-           10
-           11
-           12
-           13
+          0
+          1
+          2
+          3
+          4
+          5
+          6
+          7
+          8
+          9
+         10
+         11
+         12
+         13
 
-       and so on.
+     and so on.
 
-       Each time the digit nine should be incremented, it is
-       reset to 0 and the position before is incremented. Then
-       number 9 can be seen as "00009" and when we should
-       increment 9, we reset it to zero and increment the digit
-       just before the 9 so the number becomes "00010". For
-       zero's we write a space if it is not the only digit (so:
-       number 0) and if it is the first digit: "00010" -> " 0010"
-       -> "  010" -> "   10". It is not "   1 ".
+     Each time the digit nine should be incremented, it is reset
+     to 0 and the position before is incremented. Then number 9
+     can be seen as "00009" and when we should increment 9, we
+     reset it to zero and increment the digit just before the 9
+     so the number becomes "00010". For zero's we write a space
+     if it is not the only digit (so: number 0) and if it is the
+     first digit: "00010" -> " 0010" -> "  010" -> "   10". It is
+     not "   1 ".
 
-       This was pretty basic, you already knew this. Why did I
-       tell it ?  Well, computers do not represent numbers with
-       10 different digits. They know of only two different
-       symbols, being 0 and 1. Apply the same rules to this set
-       of digits and you get the binary numbering system:
+     This was pretty basic, you already knew this. Why did I tell
+     it ?  Well, computers do not represent numbers with 10
+     different digits. They know of only two different symbols,
+     being 0 and 1. Apply the same rules to this set of digits
+     and you get the binary numbering system:
 
 
 
@@ -59,439 +60,438 @@
 
 
 
+24/Oct/1999            Last change: 1.0.13                      1
 
 
-9/Aug/99                      1.0.7                             1
 
 
 
 
+rrdtool                                            BIN_DEC_HEX(1)
 
-BIN_DEC_HEX(1)               rrdtool               BIN_DEC_HEX(1)
 
 
-            0
-            1
-           10
-           11
-          100
-          101
-          110
-          111
-         1000
-         1001
-         1010
-         1011
-         1100
-         1101
+          0
+          1
+         10
+         11
+        100
+        101
+        110
+        111
+       1000
+       1001
+       1010
+       1011
+       1100
+       1101
 
-       and so on.
+     and so on.
 
-       If you count the number of rows, you'll see that these are
-       again 14 different numbers. The numbers are the same and
-       mean the same. It is only a different representation. This
-       means that you have to know the representation used, or as
-       it is called the numbering system or base.  Normally if we
-       do not speak about the numbering system used, we're using
-       the decimal system. If we are talking about another
-       numbering system, we'll have to make that clear. There are
-       a few wide-spread methods to do so. One common form is to
-       write _1_0_1_0(2) which means that you wrote down a number in
-       the binary form. It is the number ten.  If you would write
-       1010 it means the number one thousand and ten.
+     If you count the number of rows, you'll see that these are
+     again 14 different numbers. The numbers are the same and
+     mean the same. It is only a different representation. This
+     means that you have to know the representation used, or as
+     it is called the numbering system or base.  Normally if we
+     do not speak about the numbering system used, we're using
+     the decimal system. If we are talking about another
+     numbering system, we'll have to make that clear. There are a
+     few wide-spread methods to do so. One common form is to
+     write _1_0_1_0(2) which means that you wrote down a number in
+     the binary form. It is the number ten.  If you would write
+     1010 it means the number one thousand and ten.
 
-       In books, another form is most used. It uses subscript
-       (little chars, more or less in between two rows). You can
-       leave out the parentheses in that case and write down the
-       number in normal characters followed with a little two
-       just behind it.
+     In books, another form is most used. It uses subscript
+     (little chars, more or less in between two rows). You can
+     leave out the parentheses in that case and write down the
+     number in normal characters followed with a little two just
+     behind it.
 
-       The numbering system used is also called the base. We talk
-       of the number 1100 base 2, the number 12 base 10.
+     The numbering system used is also called the base. We talk
+     of the number 1100 base 2, the number 12 base 10.
 
-       For the binary system, is is common to write leading
-       zero's. The numbers are written down in series of four,
-       eight or sixteen depending on the context.
+     For the binary system, is is common to write leading zero's.
+     The numbers are written down in series of four, eight or
+     sixteen depending on the context.
 
-       We can use the binary form when talking to computers
-       (...programming...)  but the numbers will have large
-       representations. The number 65535 would be written down as
-       _1_1_1_1_1_1_1_1_1_1_1_1_1_1_1_1(2) which is 16 times the digit 1.  This
-       is difficult and prone to errors. Therefore we normally
-       would use another base, called hexadecimal. It uses 16
-       different symbols. First the symbols from the decimal
-       system are used, thereafter we continue with the
-       alphabetic characters. We get 0, 1, 2, 3, 4, 5, 6, 7, 8,
-       9, A, B, C, D, E and F. This system is chosen because the
-       hexadecimal form can be converted into the binary system
+     We can use the binary form when talking to computers
+     (...programming...)  but the numbers will have large
+     representations. The number 65535 would be written down as
+     _1_1_1_1_1_1_1_1_1_1_1_1_1_1_1_1(2) which is 16 times the digit 1.  This is
+     difficult and prone to errors. Therefore we normally would
+     use another base, called hexadecimal. It uses 16 different
+     symbols. First the symbols from the decimal system are used,
+     thereafter we continue with the alphabetic characters. We
+     get 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E and F. This
 
 
 
-9/Aug/99                      1.0.7                             2
+24/Oct/1999            Last change: 1.0.13                      2
 
 
 
 
 
-BIN_DEC_HEX(1)               rrdtool               BIN_DEC_HEX(1)
 
+rrdtool                                            BIN_DEC_HEX(1)
 
-       very easy (and back).
 
-       There is yet another system in use, called the octal
-       system. This was more common in the old days but not
-       anymore. You will find it in use on some places so get
-       used to it. The same story applies, but now with only
-       eight different symbols.
 
-        Binary      (2)
-        Octal       (8)
-        Decimal     (10)
-        Hexadecimal (16)
+     system is chosen because the hexadecimal form can be
+     converted into the binary system very easy (and back).
 
-        (2)    (8) (10) (16)
-        00000   0    0    0
-        00001   1    1    1
-        00010   2    2    2
-        00011   3    3    3
-        00100   4    4    4
-        00101   5    5    5
-        00110   6    6    6
-        00111   7    7    7
-        01000  10    8    8
-        01001  11    9    9
-        01010  12   10    A
-        01011  13   11    B
-        01100  14   12    C
-        01101  15   13    D
-        01110  16   14    E
-        01111  17   15    F
-        10000  20   16   10
-        10001  21   17   11
-        10010  22   18   12
-        10011  23   19   13
-        10100  24   20   14
-        10101  25   21   15
+     There is yet another system in use, called the octal system.
+     This was more common in the old days but not anymore. You
+     will find it in use on some places so get used to it. The
+     same story applies, but now with only eight different
+     symbols.
 
-       Most computers used nowadays are using bytes of eight
-       bits. This means that they store eight bits at a time. You
-       can see why the octal system is not the most preferred for
-       that: You'd need three digits to represent the eight bits
-       and this means that you'd have to use one complete digit
-       to represent only two bits (2+3+3=8). This is a waste. For
-       hexadecimal digits, you need only two digits which are
-       used completely:
+      Binary      (2)
+      Octal       (8)
+      Decimal     (10)
+      Hexadecimal (16)
 
-        (2)      (8)  (10) (16)
-        11111111 377  255   FF
+      (2)    (8) (10) (16)
+      00000   0    0    0
+      00001   1    1    1
+      00010   2    2    2
+      00011   3    3    3
+      00100   4    4    4
+      00101   5    5    5
+      00110   6    6    6
+      00111   7    7    7
+      01000  10    8    8
+      01001  11    9    9
+      01010  12   10    A
+      01011  13   11    B
+      01100  14   12    C
+      01101  15   13    D
+      01110  16   14    E
+      01111  17   15    F
+      10000  20   16   10
+      10001  21   17   11
+      10010  22   18   12
+      10011  23   19   13
+      10100  24   20   14
+      10101  25   21   15
 
-       You can see why binary and hexadecimal can be converted
-       quickly: For each hexadecimal digit there are exactly four
-       binary digits.  Take a binary number. Each time take four
-       digits from the right and make a hexadecimal digit from it
-       (see the table above). Stop when there are no more digits.
+     Most computers used nowadays are using bytes of eight bits.
+     This means that they store eight bits at a time. You can see
+     why the octal system is not the most preferred for that:
+     You'd need three digits to represent the eight bits and this
+     means that you'd have to use one complete digit to represent
+     only two bits (2+3+3=8). This is a waste. For hexadecimal
+     digits, you need only two digits which are used completely:
 
+      (2)      (8)  (10) (16)
+      11111111 377  255   FF
 
+     You can see why binary and hexadecimal can be converted
+     quickly:  For each hexadecimal digit there are exactly four
+     binary digits.  Take a binary number. Each time take four
 
-9/Aug/99                      1.0.7                             3
 
 
+24/Oct/1999            Last change: 1.0.13                      3
 
 
 
-BIN_DEC_HEX(1)               rrdtool               BIN_DEC_HEX(1)
 
 
-       Other way around: Take a hexadecimal number. For each
-       digit, write down its binary equivalent.
 
-       Computers (or rather the parsers running on them) would
-       have a hard time converting a number like _1_2_3_4(16).
-       Therefore hexadecimal numbers get a prefix. This prefix
-       depends on the language you're writing in. Some of the
-       prefixes are "0x" for C, "$" for Pascal, "#" for HTML.  It
-       is common to assume that if a number starts with a zero,
-       it is octal.  It does not matter what is used as long as
-       you know what it is.  I will use "0x" for hexadecimal, "%"
-       for binary and "0" for octal.  The following numbers are
-       all the same, just the way they are written is different:
-       021  0x11  17  %00010001
+rrdtool                                            BIN_DEC_HEX(1)
 
-       To do arithmetics and conversions you need to understand
-       one more thing.  It is something you already know but
-       perhaps you do not "see" it yet:
 
-       If you write down 1234, (so it is decimal) you are talking
-       about the number one thousand, two hundred and thirty
-       four. In sort of a formula:
 
-        1 * 1000 = 1000
-        2 *  100 =  200
-        3 *   10 =   30
-        4 *    1 =    4
+     digits from the right and make a hexadecimal digit from it
+     (see the table above). Stop when there are no more digits.
+     Other way around: Take a hexadecimal number. For each digit,
+     write down its binary equivalent.
 
-       This can also be written as:
+     Computers (or rather the parsers running on them) would have
+     a hard time converting a number like _1_2_3_4(16). Therefore
+     hexadecimal numbers get a prefix. This prefix depends on the
+     language you're writing in. Some of the prefixes are "0x"
+     for C, "$" for Pascal, "#" for HTML.  It is common to assume
+     that if a number starts with a zero, it is octal.  It does
+     not matter what is used as long as you know what it is.  I
+     will use "0x" for hexadecimal, "%" for binary and "0" for
+     octal.  The following numbers are all the same, just the way
+     they are written is different:  021  0x11  17  %00010001
 
-        1 * 10^3
-        2 * 10^2
-        3 * 10^1
-        4 * 10^0
+     To do arithmetics and conversions you need to understand one
+     more thing.  It is something you already know but perhaps
+     you do not "see" it yet:
 
-       where ^ means "to the power of".
+     If you write down 1234, (so it is decimal) you are talking
+     about the number one thousand, two hundred and thirty four.
+     In sort of a formula:
 
-       We are using the base 10, and the positions 0,1,2 and 3.
-       The right-most position should NOT be multiplied with 10.
-       The second from the right should be multiplied one time
-       with 10. The third from the right is multiplied with 10
-       two times. This continues for whatever positions are used.
+      1 * 1000 = 1000
+      2 *  100 =  200
+      3 *   10 =   30
+      4 *    1 =    4
 
-       It is the same in all other representations:
+     This can also be written as:
 
-       0x1234 will be
+      1 * 10^3
+      2 * 10^2
+      3 * 10^1
+      4 * 10^0
 
-        1 * 16^3
-        2 * 16^2
-        3 * 16^1
-        4 * 16^0
+     where ^ means "to the power of".
 
-       01234 would be
+     We are using the base 10, and the positions 0,1,2 and 3.
+     The right-most position should NOT be multiplied with 10.
+     The second from the right should be multiplied one time with
+     10. The third from the right is multiplied with 10 two
+     times. This continues for whatever positions are used.
 
+     It is the same in all other representations:
 
+     0x1234 will be
 
+      1 * 16^3
+      2 * 16^2
+      3 * 16^1
+      4 * 16^0
 
-9/Aug/99                      1.0.7                             4
 
 
+24/Oct/1999            Last change: 1.0.13                      4
 
 
 
-BIN_DEC_HEX(1)               rrdtool               BIN_DEC_HEX(1)
 
 
-        1 * 8^3
-        2 * 8^2
-        3 * 8^1
-        4 * 8^0
 
-       This example can not be done for binary as that system can
-       only use two symbols. Another example:
+rrdtool                                            BIN_DEC_HEX(1)
 
-       %1010 would be
 
-        1 * 2^3
-        0 * 2^2
-        1 * 2^1
-        0 * 2^0
 
-       It would have been more easy to convert it to its
-       hexadecimal form and just translate %1010 into 0xA. After
-       a while you get used to it. You will not need to do any
-       calculations anymore but just know that 0xA means 10.
+     01234 would be
 
-       To convert a decimal number into a hexadecimal one you
-       could use the next method. It will take some time to be
-       able to do the estimates but it will be more and more easy
-       when you use the system more frequent. Another way is
-       presented to you thereafter.
+      1 * 8^3
+      2 * 8^2
+      3 * 8^1
+      4 * 8^0
 
-       First you will need to know how many positions will be
-       used in the other system. To do so, you need to know the
-       maximum numbers. Well, that's not so hard as it looks. In
-       decimal, the maximum number that you can form with two
-       digits is "99". The maximum for three: "999". The next
-       number would need an extra position. Reverse this idea and
-       you will see that the number can be found by taking 10^3
-       (10*10*10 is 1000) minus 1 or 10^2 minus one.
+     This example can not be done for binary as that system can
+     only use two symbols. Another example:
 
-       This can be done for hexadecimal too:
+     %1010 would be
 
-        16^4 = 0x10000 = 65536
-        16^3 =  0x1000 =  4096
-        16^2 =   0x100 =   256
-        16^1 =    0x10 =    16
+      1 * 2^3
+      0 * 2^2
+      1 * 2^1
+      0 * 2^0
 
-       If a number is smaller than 65536 it will thus fit in four
-       positions.  If the number is bigger than 4095, you will
-       need to use position 4.  How many times can you take 4096
-       from the number without going below zero is the first
-       digit you write down. This will always be a number from 1
-       to 15 (0x1 to 0xF). Do the same for the other positions.
+     It would have been more easy to convert it to its
+     hexadecimal form and just translate %1010 into 0xA. After a
+     while you get used to it. You will not need to do any
+     calculations anymore but just know that 0xA means 10.
 
-       Number is 41029. It is smaller than 16^4 but bigger than
-       16^3-1. This means that we have to use four positions.  We
-       can subtract 16^3 from 41029 ten times without going below
-       zero.  The leftmost digit will be "A" so we have 0xA????.
-       The number is reduced to 41029 - 10*4096 = 41029-40960 =
+     To convert a decimal number into a hexadecimal one you could
+     use the next method. It will take some time to be able to do
+     the estimates but it will be more and more easy when you use
+     the system more frequent. Another way is presented to you
+     thereafter.
 
+     First you will need to know how many positions will be used
+     in the other system. To do so, you need to know the maximum
+     numbers. Well, that's not so hard as it looks. In decimal,
+     the maximum number that you can form with two digits is
+     "99". The maximum for three: "999". The next number would
+     need an extra position. Reverse this idea and you will see
+     that the number can be found by taking 10^3 (10*10*10 is
+     1000) minus 1 or 10^2 minus one.
 
+     This can be done for hexadecimal too:
 
-9/Aug/99                      1.0.7                             5
+      16^4 = 0x10000 = 65536
+      16^3 =  0x1000 =  4096
+      16^2 =   0x100 =   256
+      16^1 =    0x10 =    16
 
+     If a number is smaller than 65536 it will thus fit in four
+     positions.  If the number is bigger than 4095, you will need
+     to use position 4.  How many times can you take 4096 from
+     the number without going below zero is the first digit you
+     write down. This will always be a number from 1 to 15 (0x1
+     to 0xF). Do the same for the other positions.
 
 
 
 
-BIN_DEC_HEX(1)               rrdtool               BIN_DEC_HEX(1)
 
+24/Oct/1999            Last change: 1.0.13                      5
 
-       69.  69 is smaller than 16^3 but not bigger than 16^2-1.
-       The second digit is therefore "0" and we know 0xA0??.  69
-       is smaller than 16^2 and bigger than 16^1-1. We can
-       subtract 16^1 (which is just plain 16) four times and
-       write down "4" to get 0xA04?.  Take 64 from 69 (69 - 4*16)
-       and the last digit is 5 --> 0xA045.
 
-       The other method builds the number from the right. Take
-       again 41029.  Divide by 16 and do not use fractions (only
-       whole numbers).
 
-        41029 / 16 is 2564 with a remainder of 5. Write down 5.
-        2564 / 16 is 160 with a remainder of 4. Write the 4 before the 5.
-        160 / 16 is 10 with no remainder. Prepend 45 with 0.
-        10 / 16 is below one. End here and prepend 0xA. End up with 0xA045.
 
-       Which method to use is up to you. Use whatever works for
-       you. Personally I use them both without being able to tell
-       what method I use in each case, it just depends on the
-       number, I think. Fact is, some numbers will occur
-       frequently while programming, if the number is close then
-       I will use the first method (like 32770, translate into
-       32768 + 2 and just know that it is 0x8000 + 0x2 = 0x8002).
 
-       For binary the same approach can be used. The base is 2
-       and not 16, and the number of positions will grow rapidly.
-       Using the second method has the advantage that you can see
-       very simple if you should write down a zero or a one: if
-       you divide by two the remainder will be zero if it was an
-       even number and one if it was an odd number:
 
-        41029 / 2 = 20514 remainder 1
-        20514 / 2 = 10257 remainder 0
-        10257 / 2 =  5128 remainder 1
-         5128 / 2 =  2564 remainder 0
-         2564 / 2 =  1282 remainder 0
-         1282 / 2 =   641 remainder 0
-          641 / 2 =   320 remainder 1
-          320 / 2 =   160 remainder 0
-          160 / 2 =    80 remainder 0
-           80 / 2 =    40 remainder 0
-           40 / 2 =    20 remainder 0
-           20 / 2 =    10 remainder 0
-           10 / 2 =     5 remainder 0
-            5 / 2 =     2 remainder 1
-            2 / 2 =     1 remainder 0
-            1 / 2 below 0 remainder 1
+rrdtool                                            BIN_DEC_HEX(1)
 
-       Write down the results from right to left:
-       %1010000001000101
 
-       Group by four:
 
+     Number is 41029. It is smaller than 16^4 but bigger than
+     16^3-1. This means that we have to use four positions.  We
+     can subtract 16^3 from 41029 ten times without going below
+     zero.  The leftmost digit will be "A" so we have 0xA????.
+     The number is reduced to 41029 - 10*4096 = 41029-40960 = 69.
+     69 is smaller than 16^3 but not bigger than 16^2-1. The
+     second digit is therefore "0" and we know 0xA0??.  69 is
+     smaller than 16^2 and bigger than 16^1-1. We can subtract
+     16^1 (which is just plain 16) four times and write down "4"
+     to get 0xA04?.  Take 64 from 69 (69 - 4*16) and the last
+     digit is 5 --> 0xA045.
 
+     The other method builds the number from the right. Take
+     again 41029.  Divide by 16 and do not use fractions (only
+     whole numbers).
 
+      41029 / 16 is 2564 with a remainder of 5. Write down 5.
+      2564 / 16 is 160 with a remainder of 4. Write the 4 before the 5.
+      160 / 16 is 10 with no remainder. Prepend 45 with 0.
+      10 / 16 is below one. End here and prepend 0xA. End up with 0xA045.
 
+     Which method to use is up to you. Use whatever works for
+     you. Personally I use them both without being able to tell
+     what method I use in each case, it just depends on the
+     number, I think. Fact is, some numbers will occur frequently
+     while programming, if the number is close then I will use
+     the first method (like 32770, translate into 32768 + 2 and
+     just know that it is 0x8000 + 0x2 = 0x8002).
 
-9/Aug/99                      1.0.7                             6
+     For binary the same approach can be used. The base is 2 and
+     not 16, and the number of positions will grow rapidly. Using
+     the second method has the advantage that you can see very
+     simple if you should write down a zero or a one: if you
+     divide by two the remainder will be zero if it was an even
+     number and one if it was an odd number:
 
+      41029 / 2 = 20514 remainder 1
+      20514 / 2 = 10257 remainder 0
+      10257 / 2 =  5128 remainder 1
+       5128 / 2 =  2564 remainder 0
+       2564 / 2 =  1282 remainder 0
+       1282 / 2 =   641 remainder 0
+        641 / 2 =   320 remainder 1
+        320 / 2 =   160 remainder 0
+        160 / 2 =    80 remainder 0
+         80 / 2 =    40 remainder 0
+         40 / 2 =    20 remainder 0
+         20 / 2 =    10 remainder 0
+         10 / 2 =     5 remainder 0
+          5 / 2 =     2 remainder 1
+          2 / 2 =     1 remainder 0
+          1 / 2 below 0 remainder 1
 
 
 
+24/Oct/1999            Last change: 1.0.13                      6
 
-BIN_DEC_HEX(1)               rrdtool               BIN_DEC_HEX(1)
 
 
-        %1010000001000101
-        %101000000100 0101
-        %10100000 0100 0101
-        %1010 0000 0100 0101
 
-       Convert into hexadecimal: 0xA045
 
-       Group %1010000001000101 by three and convert into octal:
 
-        %1010000001000101
-        %1010000001000 101
-        %1010000001 000 101
-        %1010000 001 000 101
-        %1010 000 001 000 101
-        %1 010 000 001 000 101
-        %001 010 000 001 000 101
-           1   2   0   1   0   5 --> 0120105
+rrdtool                                            BIN_DEC_HEX(1)
 
-        So: %1010000001000101 = 0120105 = 0xA045 = 41029
-        Or: 1010000001000101(2) = 120105(8) = A045(16) = 41029(10)
-        Or: 1010000001000101(2) = 120105(8) = A045(16) = 41029
 
-       At first while adding numbers, you'll convert them to
-       their decimal form and then back into their original form
-       after doing the addition.  If you use the other numbering
-       system often, you will see that you'll be able to do
-       arithmetics in the base that is used.  In any
-       representation it is the same, add the numbers on the
-       right, write down the rightmost digit from the result,
-       remember the other digits and use them in the next round.
-       Continue with the second digits from the right and so on:
 
-           %1010 + %0111 --> 10 + 7 --> 17 --> %00010001
+     Write down the results from right to left: %1010000001000101
 
-       will become
+     Group by four:
 
-           %1010
-           %0111 +
-            ||||
-            |||+-- add 0 + 1, result is 1, nothing to remember
-            ||+--- add 1 + 1, result is %10, write down 0 and remember 1
-            |+---- add 0 + 1 + 1(remembered), result = 0, remember 1
-            +----- add 1 + 0 + 1(remembered), result = 0, remember 1
-                   nothing to add, 1 remembered, result = 1
-        --------
-          %10001 is the result, I like to write it as %00010001
+      %1010000001000101
+      %101000000100 0101
+      %10100000 0100 0101
+      %1010 0000 0100 0101
 
-       For low values, try to do the calculations yourself, check
-       them with a calculator. The more you do the calculations
-       yourself, the more you find that you didn't make mistakes.
-       In the end, you'll do calculi in other bases as easy as
-       you do in decimal.
+     Convert into hexadecimal: 0xA045
 
-       When the numbers get bigger, you'll have to realize that a
+     Group %1010000001000101 by three and convert into octal:
 
+      %1010000001000101
+      %1010000001000 101
+      %1010000001 000 101
+      %1010000 001 000 101
+      %1010 000 001 000 101
+      %1 010 000 001 000 101
+      %001 010 000 001 000 101
+         1   2   0   1   0   5 --> 0120105
 
+      So: %1010000001000101 = 0120105 = 0xA045 = 41029
+      Or: 1010000001000101(2) = 120105(8) = A045(16) = 41029(10)
+      Or: 1010000001000101(2) = 120105(8) = A045(16) = 41029
 
-9/Aug/99                      1.0.7                             7
+     At first while adding numbers, you'll convert them to their
+     decimal form and then back into their original form after
+     doing the addition.  If you use the other numbering system
+     often, you will see that you'll be able to do arithmetics in
+     the base that is used.  In any representation it is the
+     same, add the numbers on the right, write down the rightmost
+     digit from the result, remember the other digits and use
+     them in the next round. Continue with the second digits from
+     the right and so on:
 
+         %1010 + %0111 --> 10 + 7 --> 17 --> %00010001
 
+     will become
 
+         %1010
+         %0111 +
+          ||||
+          |||+-- add 0 + 1, result is 1, nothing to remember
+          ||+--- add 1 + 1, result is %10, write down 0 and remember 1
+          |+---- add 0 + 1 + 1(remembered), result = 0, remember 1
+          +----- add 1 + 0 + 1(remembered), result = 0, remember 1
+                 nothing to add, 1 remembered, result = 1
+      --------
+        %10001 is the result, I like to write it as %00010001
 
+     For low values, try to do the calculations yourself, check
 
-BIN_DEC_HEX(1)               rrdtool               BIN_DEC_HEX(1)
 
 
-       computer is not called a computer just to have a nice
-       name. There are many different calculators available. Use
-       them. For Unix you could use "bc" which is called so as it
-       is short for Binary Calculator. It calculates not only in
-       decimal, but in all bases you'll ever use (among them
-       Binary).
+24/Oct/1999            Last change: 1.0.13                      7
+
+
 
-       For people on Windows: Start the calculator
-       (start->programs->accessories->calculator) and if
-       necessary click view->scientific. You now have a
-       scientific calculator and can compute in binary or
-       hexadecimal.
 
-AAAAUUUUTTTTHHHHOOOORRRR
-       I hope you enjoyed the examples and their descriptions. If
-       you do, help other people by pointing them to this
-       document when they are asking basic questions. They will
-       not only get their answer but at the same time learn a
-       whole lot more.
 
-       Alex van den Bogaerdt <alex at ergens.op.het.net>
 
+rrdtool                                            BIN_DEC_HEX(1)
 
 
 
+     them with a calculator. The more you do the calculations
+     yourself, the more you find that you didn't make mistakes.
+     In the end, you'll do calculi in other bases as easy as you
+     do in decimal.
+
+     When the numbers get bigger, you'll have to realize that a
+     computer is not called a computer just to have a nice name.
+     There are many different calculators available. Use them.
+     For Unix you could use "bc" which is called so as it is
+     short for Binary Calculator. It calculates not only in
+     decimal, but in all bases you'll ever use (among them
+     Binary).
+
+     For people on Windows:  Start the calculator (start-
+     >programs->accessories->calculator) and if necessary click
+     view->scientific. You now have a scientific calculator and
+     can compute in binary or hexadecimal.
+
+AAAAUUUUTTTTHHHHOOOORRRR
+     I hope you enjoyed the examples and their descriptions. If
+     you do, help other people by pointing them to this document
+     when they are asking basic questions. They will not only get
+     their answer but at the same time learn a whole lot more.
 
+     Alex van den Bogaerdt <alex at ergens.op.het.net>
 
 
 
@@ -522,7 +522,7 @@
 
 
 
+24/Oct/1999            Last change: 1.0.13                      8
 
-9/Aug/99                      1.0.7                             8
 
 

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/bin_dec_hex.pod
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/bin_dec_hex.pod	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/bin_dec_hex.pod	Sat Jul 13 21:08:09 2002
@@ -1,6 +1,6 @@
 =head1 NAME
 
-Binary Decimal Hexadecimal - How does it wok
+Binary Decimal Hexadecimal - How does it work
 
 =head1 DESCRIPTION
 

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/RRDp.html
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/RRDp.html	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/RRDp.html	Sat Jul 13 21:08:09 2002
@@ -1,11 +1,10 @@
-    <HTML> 
-	<HEAD> 
-	    <TITLE>RRDp - Attach rrdtool from within a perl script via a set of pipes;
+<HTML>
+<HEAD>
+<TITLE>RRDp</TITLE>
+<LINK REV="made" HREF="mailto:karrer at zinal.ee.ethz.ch">
+</HEAD>
 
-</TITLE> 
-	</HEAD>
-
-	<BODY>
+<BODY>
 
 <!-- INDEX BEGIN -->
 <!--
@@ -23,113 +22,74 @@
 <!-- INDEX END -->
 
 <P>
-<H1><A NAME="NAME">NAME
-
-</A></H1>
-RRDp - Attach rrdtool from within a perl script via a set of pipes;
-
-
+<H1><A NAME="NAME">NAME</A></H1>
 <P>
+RRDp - Attach rrdtool from within a perl script via a set of pipes;
 
 <P>
 <HR>
-<H1><A NAME="SYNOPSIS">SYNOPSIS
-
-</A></H1>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
 use <STRONG>RRDp</STRONG>
 
 
 
-
 <P>
-
 <STRONG>RRDp::start</STRONG>  <EM>path to rrdtool executable</EM>
 
 
 
-
 <P>
-
 <STRONG>RRDp::cmd</STRONG>    <EM>rrdtool commandline</EM>
 
 
 
-
 <P>
-
 <CODE>$answer</CODE> = <STRONG>RRD::read</STRONG>
 
 
 
-
 <P>
-
 <CODE>$status</CODE> = <STRONG>RRD::end</STRONG>
 
 
 
-
 <P>
-
 <STRONG>$RRDp::user</STRONG>,  <STRONG>$RRDp::sys</STRONG>, <STRONG>$RRDp::real</STRONG>
 
 
 
-
-<P>
-
 <P>
 <HR>
-<H1><A NAME="DESCRIPTION">DESCRIPTION
-
-</A></H1>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
 With this module you can safely communicate with the rrdtool. 
 
-
 <P>
-
 After every <STRONG>RRDp::cmd</STRONG> you have to issue an <STRONG>RRDp::read</STRONG> command to get
 <STRONG>rrdtool</STRONG>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, <STRONG>RRDp::read</STRONG> will return an undefined variable. 
 
-
 <P>
-
 If you import the PERFORMANCE variables into your namespace, you can access
 rrdtools internal performance measurements.
 
-
-<P>
-
 <DL>
-<DT><STRONG><A NAME="item_use">use RRDp
-
-</A></STRONG><DD>
+<DT><STRONG><A NAME="item_use">use RRDp</A></STRONG><DD>
+<P>
 Load the RRDp::pipe module.
 
-
+<DT><STRONG><A NAME="item_RRDp">RRDp::start path to rrdtool executable</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_RRDp">RRDp::start path to rrdtool executable
-
-</A></STRONG><DD>
 start rrdtool. The argument must be the path to the rrdtool executable
 
-
+<DT><STRONG><A NAME="item_RRDp">RRDp::cmd rrdtool commandline</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_RRDp">RRDp::cmd rrdtool commandline
-
-</A></STRONG><DD>
 pass commands on to rrdtool. check the rrdtool documentation for more info
 on the rrdtool commands.
 
-
+<DT><STRONG><A NAME="item__answer">$answer = RRDp::read</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__answer">$answer = RRDp::read
-
-</A></STRONG><DD>
 read rrdtools response to your command. Note that the <CODE>$answer</CODE>
 variable will only contain a pointer to the returned data. The reason for
 this is, that rrdtool can potentially return quite excessive amounts of
@@ -137,40 +97,26 @@
 access the contents of <CODE>$answer</CODE> you have to use
 <CODE>$$answer</CODE> which dereferences the variable.
 
-
+<DT><STRONG><A NAME="item__status">$status = RRDp::end</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__status">$status = RRDp::end
-
-</A></STRONG><DD>
 terminates rrdtool and returns rrdtools status ... 
 
-
+<DT><STRONG><A NAME="item__RRDp_user_">$RRDp::user,  $RRDp::sys, $RRDp::real</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__RRDp_user_">$RRDp::user,  $RRDp::sys, $RRDp::real
-
-</A></STRONG><DD>
 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.
 
-
 <P>
-
 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.
 
-
-<P>
-
 </DL>
 <P>
 <HR>
-<H1><A NAME="EXAMPLE">EXAMPLE
-
-</A></H1>
+<H1><A NAME="EXAMPLE">EXAMPLE</A></H1>
+<P>
 <PRE> use RRDp;
  RRDp::start &quot;/usr/local/bin/rrdtool&quot;;
  RRDp::cmd   qw(create demo.rrd --step 100 
@@ -180,31 +126,19 @@
  print $$answer;
  ($usertime,$systemtime,$realtime) =  ($RRDp::user,$RRDp::sys,$RRDp::real);
 </PRE>
-
-<P>
-
 <P>
 <HR>
-<H1><A NAME="SEE_ALSO">SEE ALSO
-
-</A></H1>
-For more information on how to use rrdtool, check the manpages.
-
-
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
 <P>
+For more information on how to use rrdtool, check the manpages.
 
 <P>
 <HR>
-<H1><A NAME="AUTHOR">AUTHOR
-
-</A></H1>
-Tobias Oetiker <A
-HREF="MAILTO:<oetiker at ee.ethz.ch>"><oetiker at ee.ethz.ch></A>
-
-
+<H1><A NAME="AUTHOR">AUTHOR</A></H1>
 <P>
+Tobias Oetiker &lt;<A
+HREF="mailto:oetiker at ee.ethz.ch">oetiker at ee.ethz.ch</A>&gt;
 
-</DL>
-    </BODY>
+</BODY>
 
-    </HTML>
+</HTML>

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/rrdgraph.html
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/rrdgraph.html	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/rrdgraph.html	Sat Jul 13 21:08:09 2002
@@ -1,11 +1,10 @@
-    <HTML> 
-	<HEAD> 
-	    <TITLE>graph - Create a graph based on data from one or several RRD
+<HTML>
+<HEAD>
+<TITLE>rrdgraph</TITLE>
+<LINK REV="made" HREF="mailto:karrer at zinal.ee.ethz.ch">
+</HEAD>
 
-</TITLE> 
-	</HEAD>
-
-	<BODY>
+<BODY>
 
 <!-- INDEX BEGIN -->
 <!--
@@ -15,31 +14,32 @@
 	<LI><A HREF="#NAME">NAME</A>
 	<LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
 	<LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
-	<LI><A HREF="#NOTE">NOTE</A>
-	<LI><A HREF="#NOTE_2">NOTE 2</A>
-	<LI><A HREF="#NOTE_3">NOTE 3</A>
-	<LI><A HREF="#EXAMPLE">EXAMPLE</A>
-	<LI><A HREF="#EXAMPLE2">EXAMPLE2</A>
-	<LI><A HREF="#EXAMPLE3">EXAMPLE3</A>
+	<LI><A HREF="#NOTES_on_legend_arguments">NOTES on legend arguments</A>
+	<UL>
+
+		<LI><A HREF="#Escaping_the_colon">Escaping the colon</A>
+		<LI><A HREF="#String_Formatting">String Formatting</A>
+	</UL>
+
+	<LI><A HREF="#NOTE_on_Return_Values">NOTE on Return Values</A>
+	<LI><A HREF="#EXAMPLE_1">EXAMPLE 1</A>
+	<LI><A HREF="#EXAMPLE_2">EXAMPLE 2</A>
+	<LI><A HREF="#EXAMPLE_3">EXAMPLE 3</A>
+	<LI><A HREF="#AUTHOR">AUTHOR</A>
 	<LI><A HREF="#REFERENCES">REFERENCES</A>
 </UL>
 -->
 <!-- INDEX END -->
 
 <P>
-<H1><A NAME="NAME">NAME
-
-</A></H1>
-rrdtool graph - Create a graph based on data from one or several RRD
-
-
+<H1><A NAME="NAME">NAME</A></H1>
 <P>
+rrdtool graph - Create a graph based on data from one or several RRD
 
 <P>
 <HR>
-<H1><A NAME="SYNOPSIS">SYNOPSIS
-
-</A></H1>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
 <STRONG>rrdtool</STRONG>  <STRONG>graph</STRONG>  <EM>filename</EM> 
  
 [<STRONG>-s</STRONG>|<STRONG>--start</STRONG>&nbsp;<EM>seconds</EM>] 
@@ -82,9 +82,7 @@
 
 
 
-
 <P>
-
 [<STRONG>-t</STRONG>|<STRONG>--title</STRONG>&nbsp;<EM>title</EM>]
 
 [<STRONG>DEF:</STRONG><EM>vname</EM><STRONG>=</STRONG><EM>rrd</EM><STRONG>:</STRONG><EM>ds-name</EM><STRONG>:</STRONG><EM>CF</EM>]
@@ -109,114 +107,76 @@
 
 
 
-
-<P>
-
 <P>
 <HR>
-<H1><A NAME="DESCRIPTION">DESCRIPTION
-
-</A></H1>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
 The <STRONG>graph</STRONG> functions main purpose is to create graphical representations of the data
 stored in one or several <STRONG>RRD</STRONG>s. Apart from generating graphs, it can also extract numerical reports.
 
-
-<P>
-
 <DL>
-<DT><STRONG><A NAME="item_filename">filename 
-
-</A></STRONG><DD>
+<DT><STRONG><A NAME="item_filename">filename</A></STRONG><DD>
+<P>
 The name of the graph to generate. Since <STRONG>rrdtool</STRONG> outputs GIFs and PNGs, it's recommended that the filename end in either
 <EM>.gif</EM> or <EM>.png</EM>.  <STRONG>rrdtool</STRONG> does not enforce this, however. If the  <EM>filename</EM> is set to '-' the image file will be written to standard out. All other
 output will get suppressed.
 
-
 <P>
-
 PNG output is recommended, since it takes up to 40% less disk space and
 20-30% less time to generate than a GIF file.
 
-
 <P>
-
 If no graph functions are called, the graph will not be created.
 
-
+<DT><STRONG><A NAME="item__s_start">-s|--start seconds (default end-1day)</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__s_start">-s|--start seconds (default end-1day)
-
-</A></STRONG><DD>
 The time when the graph should begin. Time in seconds since epoch
 (1970-01-01) is required. Negative numbers are relative to the current
 time. By default one day worth of data will be graphed. See also AT-STYLE
 TIME SPECIFICATION section in the <EM>rrdfetch</EM>
 documentation for a detailed explanation on how to specify time.
 
-
+<DT><STRONG><A NAME="item__e_end">-e|--end seconds (default now)</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__e_end">-e|--end seconds (default now)
-
-</A></STRONG><DD>
 The time when the graph should end. Time in seconds since epoch. See also
 AT-STYLE TIME SPECIFICATION section in the <EM>rrdfetch</EM>
 documentation for a detailed explanation of ways to specify time.
 
-
+<DT><STRONG><A NAME="item__x_x_grid">-x|--x-grid x-axis grid and label (default autoconfigure)</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__x_x_grid">-x|--x-grid x-axis grid and label (default autoconfigure)
-
-</A></STRONG><DD>
 The x-axis label is quite complex to configure. So if you don't have very
 special needs, you can rely on the autoconfiguration to get this right.
 
-
 <P>
-
 The x-axis label is configured, using the following format:
 
-
 <P>
-
 <EM>GTM</EM><STRONG>:</STRONG><EM>GST</EM><STRONG>:</STRONG><EM>MTM</EM><STRONG>:</STRONG><EM>MST</EM><STRONG>:</STRONG><EM>LTM</EM>:<EM>LST</EM><STRONG>:</STRONG><EM>LPR</EM><STRONG>:</STRONG><EM>LFM</EM>
 
 
 
-
 <P>
-
 You have to configure three elements making up the x-axis labels and grid.
 The base grid (<EM>G??</EM>), the major grid (<EM>M??</EM>) and the labels (<EM>L??</EM>). The configuration is based on the idea that you first specify a well
 known amount of time (<EM>?TM</EM>) and then say how many times it has to pass between each grid line or
 label (<EM>?ST</EM>). For the label you have to define two additional items: The precision of
 the label in seconds (<EM>LPR</EM>) and the strftime format used to generate the text of the label (<EM>LFM</EM>).
 
-
 <P>
-
 The <EM>?TM</EM> elements must be one of the following keywords: <STRONG>SECOND</STRONG>,
 <STRONG>MINUTE</STRONG>, <STRONG>HOUR</STRONG>, <STRONG>DAY</STRONG>, <STRONG>WEEK</STRONG>, <STRONG>MONTH</STRONG> or <STRONG>YEAR</STRONG>.
 
-
 <P>
-
 If you wanted a graph with a base grid every 10 minutes and a major one
 every hour, with labels every hour you would use the following x-axis
 definition.
 
-
 <P>
-
 <CODE>MINUTE:10:HOUR:1:HOUR:1:0:%X</CODE>
 
 
 
-
 <P>
-
 The precision in this example is 0 because the <CODE>%X</CODE> format is
 exact. If the label was the name of the day, we would have had a precision
 of 24 hours, because when you say something like 'Monday' you mean the
@@ -224,33 +184,21 @@
 at noon. By defining a precision of 24 hours or rather 86400 seconds, you
 make sure that this happens.
 
-
+<DT><STRONG><A NAME="item__y_y_grid">-y|--y-grid grid step:label factor (default autoconfigure)</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__y_y_grid">-y--y-grid grid step:label factor (default autoconfigure)
-
-</A></STRONG><DD>
 Makes vertical grid lines appear at <EM>grid step</EM> interval. Every
 <EM>label factor</EM> gridstep, a major grid line is printed, along with label showing the value
 of the grid line.
 
-
+<DT><STRONG><A NAME="item__alt_y_grid">--alt-y-grid</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__alt_y_grid">--alt-y-grid
-
-</A></STRONG><DD>
 Place Y grid dynamically based on graph Y range. Algorithm ensures that you
 always have grid, that there are enough but not too many grid lines and the
 grid is metric. That is grid lines are placed every 1, 2, 5 or 10 units.
 (contributed by Sasha Mikheev)
 
-
+<DT><STRONG><A NAME="item__alt_autoscale">--alt-autoscale</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__alt_autoscale">--alt-autoscale
-
-</A></STRONG><DD>
 Compute Y range based on function absolute minimum and maximum values.
 Default algorithm uses predefined set of ranges. This is good in many cases
 but it fails miserably when you need to graph something like 260 + 0.001 *
@@ -259,160 +207,103 @@
 range will be from slightly less the 260 - 0.001 to slightly more then 260
 + 0.001 and periodic behavior will be seen. (contributed by Sasha Mikheev)
 
-
+<DT><STRONG><A NAME="item__v_vertical_label">-v|--vertical-label text</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__v_vertical_label">-v|--vertical-label text
-
-</A></STRONG><DD>
 vertical label on the left side of the graph. This is normally used to
 specify the units used.
 
-
+<DT><STRONG><A NAME="item__w_width">-w|--width pixels (default 400 pixel)</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__w_width">-w|--width pixels (default 400 pixel)
-
-</A></STRONG><DD>
 Width of the drawing area within the graph. This affects the size of the
 gif.
 
-
+<DT><STRONG><A NAME="item__h_height">-h|--height pixels (default 100 pixel)</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__h_height">-h|--height pixels (default 100 pixel)
-
-</A></STRONG><DD>
 Width of the drawing area within the graph. This affects the size of the
 gif.
 
-
+<DT><STRONG><A NAME="item__i_interlaced">-i|--interlaced (default: false)</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__i_interlaced">-i|--interlaced (default: false)
-
-</A></STRONG><DD>
 If you set this option, then the resulting GIF will be interlaced. Most web
 browsers display these incrementally as they load. If you do not use this
 option, the GIFs default to being progressive scanned. The only effect of
 this option is to control the format of the GIF on disk. It makes no
 changes to the layout or contents of the graph.
 
-
+<DT><STRONG><A NAME="item__f_imginfo">-f|--imginfo formatstring</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__f_imginfo">-f|--imginfo formatstring
-
-</A></STRONG><DD>
 After the image has been created, the graph function uses printf together
 with this format string to create output similar to the PRINT function,
 only that the printf is supplied with the parameters
 <EM>filename</EM>, <EM>xsize</EM> and <EM>ysize</EM>. In order to generate an <STRONG>IMG</STRONG> tag suitable for including the graph into a web page, the command line
 would look like this:
 
-
 <P>
-
 <PRE> --imginfo '&lt;IMG SRC=&quot;/img/%s&quot; WIDTH=&quot;%lu&quot; HEIGHT=&quot;%lu&quot; ALT=&quot;Demo&quot;&gt;'
 </PRE>
-
+<DT><STRONG><A NAME="item__a_imgformat">-a|--imgformat GIF|PNG (default: GIF)</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__a_imgformat">-a|--imgformat GIF|PNG (default: GIF)
-
-</A></STRONG><DD>
 Allows you to produce PNG output from rrdtool. 
 
-
+<DT><STRONG><A NAME="item__z_lazy">-z|--lazy (default: false)</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__z_lazy">-z|--lazy (default: false)
-
-</A></STRONG><DD>
 Only generate the graph, if the current gif is out of date or not existent.
 
-
+<DT><STRONG><A NAME="item__u_upper_limit">-u|--upper-limit value (default autoconfigure)</A></STRONG><DD>
 <P>
+This is not the upper limit of a graph! But rather, this is the minimum
+upper bound of a graph. Use this to expand graphs up. For example, the
+value 100 will result in graphs that have a upper bound of 100 or more.
+Setting the upper limit to the maximum value for some DS will result in
+disabling RRDtool's autoscaling down (ie it will ``expand'' graphs up.) To
+disable RRDtool's autoscaling up (to the max value for the DSs graphed),
+use a nifty CDEF like so: CDEF:mcpu=cpu,100,GT,100,cpu,IF. If this CDEF is
+applied to all DSs in a graph, then the graph will have an upper limit of
+100.
+
+<DT><STRONG><A NAME="item__l_lower_limit">-l|--lower-limit value (default autoconfigure)</A></STRONG><DD>
+<P>
+This is not the lower limit of a graph. But rather, this is the maximum
+lower bound of a graph. For example, the value -100 will result in a graph
+that has a lower limit of -100 or less. Use this keyword to expand graphs
+down.
 
-<DT><STRONG><A NAME="item__u_upper_limit">-u|--upper-limit value (default autoconfigure)
-
-</A></STRONG><DD>
-The maximum value to be graphed. By default This will be autoconfigured
-from the data you select with the graphing functions.
-
-
+<DT><STRONG><A NAME="item__r_rigid">-r|--rigid</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__l_lower_limit">-l|--lower-limit value (default autoconfigure)
-
-</A></STRONG><DD>
-The minimum value to be graphed. By default This will be autoconfigured
-from the data you select with the graphing functions.
-
-
-<P>
-
-<DT><STRONG><A NAME="item__r_rigid">-r|--rigid
-
-</A></STRONG><DD>
 rigid boundaries mode. Normally rrdgraph will automatically expand the
 lower and upper limit if the graph contains a value outside the valid
 range. With the r option you can disable this behavior
 
-
+<DT><STRONG><A NAME="item__b_base">-b|--base value</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__b_base">-b|--base value
-
-</A></STRONG><DD>
 if you are graphing memory (and NOT network traffic) this switch should be
 set to 1024 so that one Kb is 1024 byte. For traffic measurement, 1 kb/s is
 1000 b/s.
 
-
+<DT><STRONG><A NAME="item__o_logarithmic">-o|--logarithmic</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__o_logarithmic">-o|--logarithmic
-
-</A></STRONG><DD>
 logarithmic y-axis scaling
 
-
+<DT><STRONG><A NAME="item__c_color">-c|--color COLORTAG#rrggbb (default colors)</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__c_color">-c|--color COLORTAG#rrggbb (default colors)
-
-</A></STRONG><DD>
 override the colors for the standard elements of the graph. The <EM>COLORTAG</EM>
 must be one of the following symbolic names: <STRONG>BACK</STRONG> ground, <STRONG>CANVAS</STRONG>,
 <STRONG>SHADEA</STRONG> left/top border, <STRONG>SHADEB</STRONG> right/bottom border, <STRONG>GRID</STRONG>, <STRONG>MGRID</STRONG>
 major grid, <STRONG>FONT</STRONG>, <STRONG>FRAME</STRONG> and axis of the graph or <STRONG>ARROW</STRONG>. This option can be called multiple times to set several colors.
 
-
+<DT><STRONG><A NAME="item__t_title">-t|--title text (default no title)</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__t_title">-t|--title text (default no title)
-
-</A></STRONG><DD>
 Define a title to be written into the graph
 
-
+<DT><STRONG><A NAME="item_DEF">DEF:vname=rrd:ds-name:CF</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_DEF">DEF:vname=rrd:ds-name:CF
-
-</A></STRONG><DD>
 Define virtual name for a data source. This name can then be used in the
-functions explained below. The DEF call automatically chooses an <STRONG>RRA</STRONG> which provides data in a resolution appropriate for the size of the graph
-to be drawn. Ideally this means that one data point from the <STRONG>RRA</STRONG> should be represented by one pixel in the graph. If the resolution of the <STRONG>RRA</STRONG> is higher than the resolution of the graph, the data in the RRA will be
-consolidated according to the consolidation function (<EM>CF</EM>) chosen.
-
+functions explained below. The DEF call automatically chooses an <STRONG>RRA</STRONG> which contains <EM>CF</EM> consolidated data in a resolution appropriate for the size of the graph to
+be drawn. Ideally this means that one data point from the <STRONG>RRA</STRONG> should be represented by one pixel in the graph. If the resolution of the <STRONG>RRA</STRONG> is higher than the resolution of the graph, the data in the RRA will be
+further consolidated according to the consolidation function (<EM>CF</EM>) chosen.
 
+<DT><STRONG><A NAME="item_CDEF">CDEF:vname=rpn-expression</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_CDEF">CDEF:vname=rpn-expression
-
-</A></STRONG><DD>
 Create a new virtual data source by evaluating a mathematical expression,
 specified in Reverse Polish Notation (RPN). If you have ever used a
 traditional HP calculator you already know RPN. The idea behind RPN
@@ -421,9 +312,7 @@
 as needed. The pushing of data is implicit, so when ever you specify a
 number or a variable, it gets pushed automatically. 
 
-
 <P>
-
 If this is all a big load of incomprehensible words for you, maybe an
 example helps (a more complete explanation is given in [1]): The expression <EM>vname+3/2</EM> becomes <CODE>vname,3,2,/,+</CODE> in RPN. First the three values get pushed onto the stack (which now
 contains (the current value of) vname, a 3 and a 2). Then the / operator
@@ -433,141 +322,93 @@
 added up and the result gets pushes back onto the stack. In the end there
 is only one value left on the stack: The result of the expression.
 
-
 <P>
-
 The <EM>rpn-expression</EM> in the <STRONG>CDEF</STRONG> function takes both, constant values as well as <EM>vname</EM> variables. The following operators can be used on these values: 
 
-
-<P>
-
 <DL>
-<DT><STRONG><A NAME="item__">+, -, *, /, %
-
-</A></STRONG><DD>
+<DT><STRONG><A NAME="item__">+, -, *, /, %</A></STRONG><DD>
+<P>
 pops two values from the stack applies the selected operator and pushes the
 result back onto the stack. The % operator stands for the modulo operation.
 
-
+<DT><STRONG><A NAME="item_SIN">SIN, COS, LOG, EXP</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_SIN">SIN, COS, LOG, EXP
-
-</A></STRONG><DD>
 pops one value from the stack, applies the selected function and pushes the
 result back onto the stack.
 
-
+<DT><STRONG><A NAME="item_LT">LT, LE, GT, GE, EQ</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_LT">LT, LE, GT, GE, EQ
-
-</A></STRONG><DD>
 pops two values from the stack, compares them according to the selected
 condition and pushes either 1 back onto the stack if the condition is true
 and 0 if the condition was not true.
 
-
+<DT><STRONG><A NAME="item_IF">IF</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_IF">IF
-
-</A></STRONG><DD>
 pops three values from the stack. If the last value is not 0, the second
 value will be pushed back onto the stack, otherwise the first value is
 pushed back.
 
-
 <P>
-
 If the stack contains the values A, B, C, D, E are presently on the stack,
 the IF operator will pop the values E D and C of the stack. It will look at
 C and if it is not 0 it will push D back onto the stack, otherwise E will
 be sent back to the stack.
 
-
+<DT><STRONG><A NAME="item_DUP">DUP, EXC, POP</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_DUP">DUP, EXC, POP
-
-</A></STRONG><DD>
 These manipulate the stack directly. DUP will duplicate the top of the
 stack, pushing the result back onto the stack. EXC will exchange the top
 two elements of the stack, and POP will pop off the top element of the
 stack. Having insufficient elements on the stack for these operations is an
 error.
 
-
+<DT><STRONG><A NAME="item_UN">UN</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_UN">UN
-
-</A></STRONG><DD>
 Pops one value off the stack, if it is <EM>*UNKNOWN*</EM>, 1 will be pushed back otherwise 0.
 
-
+<DT><STRONG><A NAME="item_UNKN">UNKN</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_UNKN">UNKN
-
-</A></STRONG><DD>
 Push an <EM>*UNKNOWN*</EM> value onto the stack.
 
-
+<DT><STRONG><A NAME="item_PREV">PREV</A></STRONG><DD>
 <P>
+Push <EM>*UNKNOWN*</EM> if its at the first value of a data set or otherwise the value of this CDEF
+at the previous time step. This allows you to perform calculations across
+the data.
 
-<DT><STRONG><A NAME="item_INF">INF, NEGINF
-
-</A></STRONG><DD>
+<DT><STRONG><A NAME="item_INF">INF, NEGINF</A></STRONG><DD>
+<P>
 Push a positive or negative infinite (oo) value onto the stack. When
 drawing an infinite number it appears right at the top or bottom edge of
 the graph, depending whether you have a positive or negative infinite
 number.
 
-
+<DT><STRONG><A NAME="item_NOW">NOW</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_NOW">NOW
-
-</A></STRONG><DD>
 Push the current (real world) time onto the stack.
 
-
+<DT><STRONG><A NAME="item_TIME">TIME</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_TIME">TIME
-
-</A></STRONG><DD>
 Push the time the current sample was taken onto the stack.
 
-
-<P>
-
 </DL>
+<P>
 Please note that you may only use <EM>vname</EM> variables that you previously defined by either <STRONG>DEF</STRONG> or <STRONG>CDEF</STRONG>. Furthermore, as of this writing (version 0.99.25), you must use at least
 one <EM>vname</EM>
 per expression, that is ``CDEF:fourtytwo=2,40,+'' will yield an error
 message but not a <EM>vname</EM> fourtytwo that's always equal to 42.
 
-
+<DT><STRONG><A NAME="item_PRINT">PRINT:vname:CF:format</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_PRINT">PRINT:vname:CF:format
-
-</A></STRONG><DD>
 Calculate the chosen consolidation function <EM>CF</EM> over the data-source variable <EM>vname</EM> and <CODE>printf</CODE> the result to stdout using <EM>format</EM>. In the <EM>format</EM> string there should be a '%lf' or '%le' marker in the place where the
 number should be printed.
 
-
 <P>
-
 If an additional '%s' is found AFTER the marker, the value will be scaled
 and an appropriate SI magnitude unit will be printed in place of the '%s'
 marker. The scaling will take the '--base' argument into consideration!
 
-
 <P>
-
 If a '%S' is used instead of a '%s', then instead of calculating the
 appropriate SI magnitude unit for this value, the previously calculated SI
 magnitude unit will be used. This is useful if you want all the values in a
@@ -577,44 +418,24 @@
 unit and a SI magnitude unit will only be calculated when the next '%s' is
 seen or the next '%S' for a non-zero value.
 
-
+<DT><STRONG><A NAME="item_GPRINT">GPRINT:vname:CF:format</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_GPRINT">GPRINT:vname:CF:format
-
-</A></STRONG><DD>
 Same as <STRONG>PRINT</STRONG> but the result is printed into the graph below the legend.
 
-
+<DT><STRONG><A NAME="item_COMMENT">COMMENT:text</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_COMMENT">COMMENT:text
-
-</A></STRONG><DD>
 Like <STRONG>GPRINT</STRONG> but the <EM>text</EM> is simply printed into the graph.
 
-
+<DT><STRONG><A NAME="item_HRULE">HRULE:value#rrggbb[:legend]</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_HRULE">HRULE:value#rrggbb[:legend]
-
-</A></STRONG><DD>
 Draw a horizontal rule into the graph and optionally add a legend
 
-
+<DT><STRONG><A NAME="item_VRULE">VRULE:time#rrggbb[:legend]</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_VRULE">VRULE:time#rrggbb[:legend]
-
-</A></STRONG><DD>
 Draw a vertical rule into the graph and optionally add a legend
 
-
+<DT><STRONG><A NAME="item_LINE">LINE{1|2|3}:vname[#rrggbb[:legend]]</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_LINE">LINE{1|2|3}:vname[#rrggbb[:legend]]
-
-</A></STRONG><DD>
 Plot for the requested data, using the color specified. Write a legend into
 the graph. The 3 possible keywords <STRONG>LINE1</STRONG>, <STRONG>LINE2</STRONG>, and <STRONG>LINE3</STRONG> 
 generate increasingly wide lines. If no color is defined, the drawing is
@@ -622,102 +443,74 @@
 <STRONG>STACK</STRONG> function when you want to ADD the values of two data-sources without
 showing it in the graph.
 
-
+<DT><STRONG><A NAME="item_AREA">AREA:vname[#rrggbb[:legend]]</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_AREA">AREA:vname[#rrggbb[:legend]]
-
-</A></STRONG><DD>
 Does the same as <STRONG>LINE?</STRONG>, but the area between 0 and the graph will be filled with the color
 specified.
 
-
+<DT><STRONG><A NAME="item_STACK">STACK:vname[#rrggbb[:legend]]</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_STACK">STACK:vname[#rrggbb[:legend]]
-
-</A></STRONG><DD>
 Does the same as <STRONG>LINE?</STRONG>, but the graph gets stacked on top of the previous
 <STRONG>LINE?</STRONG>, <STRONG>AREA</STRONG> or <STRONG>STACK</STRONG> graph. Depending on the type of the previous graph, the <STRONG>STACK</STRONG> will be either a <STRONG>LINE?</STRONG> or an <STRONG>AREA</STRONG>. This obviously implies that the first <STRONG>STACK</STRONG> must be preceded by an
 <STRONG>AREA</STRONG> or <STRONG>LINE?</STRONG> -- you need something to stack something onto in the first place ;) 
 
-
 <P>
-
 Note, that when you STACK onto *UNKNOWN* data, rrdtool will not draw any
 graphics ... *UNKNOWN* is not zero ... if you want it to zero then you
 might want to use a CDEF argument with IF and UN functions to turn
 *UNKNOWN* into zero ... =back
 
-
+<H1><A NAME="NOTES_on_legend_arguments">NOTES on legend arguments</A></H1>
+<H2><A NAME="Escaping_the_colon">Escaping the colon</A></H2>
 <P>
-
-<H1><A NAME="NOTE">NOTE
-
-</A></H1>
 In a ':' in a <EM>legend</EM> argument will mark the end of the legend. To enter a ':' into a legend, the
 colon must be escaped with a backslash '\:'. Beware, that many environments
 look for backslashes themselves, so it may be necessary to write two
 backslashes so that one is passed onto rrd_graph.
 
-
+<H2><A NAME="String_Formatting">String Formatting</A></H2>
 <P>
-
-<H1><A NAME="NOTE_2">NOTE 2
-
-</A></H1>
 The text printed below the actual graph can be formated by appending
 special escaped characters at the end of a text. When ever such a character
 occurs, all pending text is pushed onto the graph according to the
 character specified.
 
-
 <P>
-
-Valid characters are: <STRONG>j</STRONG> for justified, <STRONG>l</STRONG> for left aligned, <STRONG>r</STRONG>
-for right aligned and <STRONG>c</STRONG> for centered. In the next section there is an example showing how to use
-centered formating. 
-
+Valid markers are: <STRONG>\j</STRONG> for justified, <STRONG>\l</STRONG> for left aligned, <STRONG>\r</STRONG> for right aligned and <STRONG>\c</STRONG> for centered. In the next section there is an example showing how to use
+centered formating.
 
 <P>
-
-A special case is COMMENT:\s this inserts some additional vertical space
-before placing the next row of legends. 
-
+Normally there are two space characters inserted between every two items
+printed into the graph. The space following a string can be suppressed by
+putting a <STRONG>\g</STRONG> at the end of the string. The <STRONG>\g</STRONG> also squshes any space inside the string if it is at the very end of the
+string. This can be used in connection with <STRONG>%s</STRONG> to supress empty unit strings.
 
 <P>
-
-<H1><A NAME="NOTE_3">NOTE 3
-
-</A></H1>
+<PRE> GPRINT:a:MAX:%lf%s\g
+ 
+A special case is COMMENT:B&lt;\s&gt; this inserts some additional vertical space
+before placing the next row of legends.
+</PRE>
+<H1><A NAME="NOTE_on_Return_Values">NOTE on Return Values</A></H1>
+<P>
 Whenever rrd_graph gets called, it prints a line telling the size of the
 gif it has just created to STDOUT. This line looks like this: XSIZExYSIZE.
 
-
+<H1><A NAME="EXAMPLE_1">EXAMPLE 1</A></H1>
 <P>
-
-<H1><A NAME="EXAMPLE">EXAMPLE
-
-</A></H1>
 <PRE>  rrdtool graph demo.gif --title=&quot;Demo Graph&quot; \
           DEF:cel=demo.rrd:exhaust:AVERAGE \
           &quot;CDEF:far=cel,32,-,0.55555,*&quot; \
           LINE2:cel#00a000:&quot;D. Celsius&quot; \
           LINE2:far#ff0000:&quot;D. Fahrenheit\c&quot;
 </PRE>
-
+<H1><A NAME="EXAMPLE_2">EXAMPLE 2</A></H1>
 <P>
-
-<H1><A NAME="EXAMPLE2">EXAMPLE2
-
-</A></H1>
 This example demonstrates the syntax for using IF and UN to set
 <EM>*UNKNOWN*</EM> values to 0. This technique is useful if you are aggregating interface data
 where the start dates of the data sets doesn't match.
 
-
 <P>
-
 <PRE>  rrdtool graph demo.gif --title=&quot;Demo Graph&quot; \
          DEF:idat1=interface1.rrd:ds0:AVERAGE \
          DEF:idat2=interface2.rrd:ds0:AVERAGE \
@@ -730,33 +523,23 @@
          
 Assuming that idat1 has a data value of I&lt;*UNKNOWN*&gt;, the CDEF expression 
 </PRE>
-
 <P>
-
 <PRE> idat1,UN,0,idat1,IF 
 </PRE>
-
 <P>
-
 leaves us with a stack with contents of 1,0,NaN and the IF function will
 pop off the 3 values and replace them with 0. If idat1 had a real value
 like 7942099, then the stack would have 0,0,7942099 and the real value
 would be the replacement.  
 
-
+<H1><A NAME="EXAMPLE_3">EXAMPLE 3</A></H1>
 <P>
-
-<H1><A NAME="EXAMPLE3">EXAMPLE3
-
-</A></H1>
 This example shows two ways to use the INF function. First it makes the
 background change color during half of the hours. Then, it uses AREA and
 STACK to draw a picture. If one of the inputs was UNKNOWN, all inputs are
 overlaid with another AREA.
 
-
 <P>
-
 <PRE>  rrdtool graph example.png --title=&quot;INF demo&quot; \
          DEF:val1=some.rrd:ds0:AVERAGE \
          DEF:val2=some.rrd:ds1:AVERAGE \
@@ -771,58 +554,42 @@
          STACK:val4#FFC000:Value4 \
          AREA:whipeout#FF0000:Unknown
 </PRE>
-
 <P>
-
 The first CDEF uses val4 as a dummy value. It's value is removed
 immediately from the stack. Then a decision is made based on the time that
 a sample was taken. If it is an even hour (UTC time !) then the area will
 be filled. If it is not, the value is set to UNKN and is not plotted.
 
-
 <P>
-
 The second CDEF looks if any of val1,val2,val3,val4 is unknown. It does so
 by checking the outcome of <CODE>sum(val1,val2,val3,val4).</CODE> Again,
 INF is returned when the condition is true, UNKN is used to not plot the
 data.
 
-
 <P>
-
 The different items are plotted in a particular order. First do the
-background,+then use a normal area to overlay it with data. Stack the other
-data until they+are all plotted. Last but not least, overlay everything
+background, then use a normal area to overlay it with data. Stack the other
+data until they are all plotted. Last but not least, overlay everything
 with eye-hurting red to signal any unknown data.
 
-
 <P>
-
 Note that this example assumesthat your data is in the positive half of the
 y-axis otherwhise you would would have to add NEGINF in order to extend the
-coverage of the rea to whole graph. =head1 AUTHOR
-
+coverage of the rea to whole graph.
 
+<H1><A NAME="AUTHOR">AUTHOR</A></H1>
 <P>
+Tobias Oetiker &lt;<A HREF="mailto:oetiker at ee.ethz.ch">oetiker at ee.ethz.ch</A>&gt;
 
-Tobias Oetiker <A
-HREF="MAILTO:<oetiker at ee.ethz.ch>"><oetiker at ee.ethz.ch></A>
 
 
+<H1><A NAME="REFERENCES">REFERENCES</A></H1>
 <P>
-
-<H1><A NAME="REFERENCES">REFERENCES
-
-</A></H1>
 [1] <A
 HREF="http://www.dotpoint.com/xnumber/rpn_or_adl.htm">http://www.dotpoint.com/xnumber/rpn_or_adl.htm</A>
 
 
-
-<P>
-
-</DL>
 </DL>
-    </BODY>
+</BODY>
 
-    </HTML>
+</HTML>

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/rrdtutorial.html
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/rrdtutorial.html	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/rrdtutorial.html	Sat Jul 13 21:08:09 2002
@@ -1,11 +1,10 @@
-    <HTML> 
-	<HEAD> 
-	    <TITLE>rrdtutorial - Alex van den Bogaerdts RRDtool tutorial
+<HTML>
+<HEAD>
+<TITLE>rrdtutorial</TITLE>
+<LINK REV="made" HREF="mailto:karrer at zinal.ee.ethz.ch">
+</HEAD>
 
-</TITLE> 
-	</HEAD>
-
-	<BODY>
+<BODY>
 
 <!-- INDEX BEGIN -->
 <!--
@@ -48,194 +47,152 @@
 <!-- INDEX END -->
 
 <P>
-<H1><A NAME="NAME">NAME
-
-</A></H1>
-rrdtutorial - Alex van den Bogaerdts RRDtool tutorial
-
-
+<H1><A NAME="NAME">NAME</A></H1>
 <P>
+rrdtutorial - Alex van den Bogaerdt's RRDtool tutorial
 
 <P>
 <HR>
-<H1><A NAME="DESCRIPTION">DESCRIPTION
-
-</A></H1>
-RRDtool is written by Tobias Oetiker <A
-HREF="MAILTO:<oetiker at ee.ethz.ch>"><oetiker at ee.ethz.ch></A> with
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+RRDtool is written by Tobias Oetiker &lt;<A
+HREF="mailto:oetiker at ee.ethz.ch">oetiker at ee.ethz.ch</A>&gt; with
 contributions from many people all around the world. This document is
-written by Alex van den Bogaerdt <A
-HREF="MAILTO:<alex at ergens.op.het.net>"><alex at ergens.op.het.net></A> to help
+written by Alex van den Bogaerdt &lt;<A
+HREF="mailto:alex at ergens.op.het.net">alex at ergens.op.het.net</A>&gt; to help
 you understand what RRDtool is and what it can do for you.
 
-
 <P>
-
 The documentation provided with RRDtool can be too technical for some
-people and here we help you to understand the basics in order to prepare
-you to read the documentation yourself. It also explains the general things
-about statistics with a focus on networking.
-
-
-<P>
+people. This tutorial is here to help you understand the basics of RRDtool.
+It should prepare you to read the documentation yourself. It also explains
+the general things about statistics with a focus on networking.
 
 <P>
 <HR>
-<H1><A NAME="TUTORIAL">TUTORIAL
-
-</A></H1>
+<H1><A NAME="TUTORIAL">TUTORIAL</A></H1>
 <P>
 <HR>
-<H2><A NAME="Important">Important
-
-</A></H2>
-We first have to do some uninteresting reading folks, don't skip this part!
-Later on, in the examples, you need to know the basics.
-
-
+<H2><A NAME="Important">Important</A></H2>
 <P>
+Please don't skip ahead in this document! The first part of this document
+explains the basics and may be boring. But if you don't understand the
+basics, the examples will not be as meaningful to you.
 
 <P>
 <HR>
-<H2><A NAME="What_is_RRDtool_">What is RRDtool ?
-
-</A></H2>
-RRDtool means Round Robin Database tool. Round robin is a technique that
-works with a fixed amount of data, and a pointer to the current element.
-Think of a circle with some dots plotted on the edge, these dots are the
-places where data can be stored. Draw an arrow from the center of the
-circle to one of the dots, this is the pointer. When the current data is
-read or written, the pointer moves to the next element. As we are on a
+<H2><A NAME="What_is_RRDtool_">What is RRDtool ?</A></H2>
+<P>
+RRDtool refers to Round Robin Database tool. Round robin is a technique
+that works with a fixed amount of data, and a pointer to the current
+element. Think of a circle with some dots plotted on the edge, these dots
+are the places where data can be stored. Draw an arrow from the center of
+the circle to one of the dots, this is the pointer. When the current data
+is read or written, the pointer moves to the next element. As we are on a
 circle there is no beginning nor an end, you can go on and on. After a
 while, all the available places will be used and the process automatically
-reuses old locations. RRDtool works with with Round Robin Databases (RRDs).
-It stores and retrieves data from them.
-
-
-<P>
+reuses old locations. This way, the database will not grow in size and
+therefore requires no mainenance. RRDtool works with with Round Robin
+Databases (RRDs). It stores and retrieves data from them.
 
 <P>
 <HR>
-<H2><A NAME="What_data_can_be_put_into_an_RDD">What data can be put into an RDD ?
-
-</A></H2>
+<H2><A NAME="What_data_can_be_put_into_an_RDD">What data can be put into an RDD ?</A></H2>
+<P>
 You name it, it will probably fit. You should be able to measure some value
-at several points in time and provide this to RRDtool. If you can do this,
-RRDtool will probably be able to store it.
-
+at several points in time and provide this information to RRDtool. If you
+can do this, RRDtool will be able to store it. The values need to be
+numerical but don't have to be, as opposed to MRTG, integers.
 
 <P>
-
 Many examples talk about SNMP which is an acronym for Simple Network
-Management Protocol. The ``simple'' is about the protocol, it does not mean
-it is simple to manage a network. After working your way through this
-document, you will know enough to be able to understand what people are
-talking about. For now, just assume SNMP is a way to talk to devices and
-ask those devices about counters they keep. It is the value from those
-counters that are kept in the RRD.
-
-
-<P>
+Management Protocol. ``Simple'' refers to the protocol -- it does not mean
+it is simple to manage or monitor a network. After working your way through
+this document, you should know enough to be able to understand what people
+are talking about. For now, just realize that SNMP is a way to ask devices
+for the values of counters they keep. It is the value from those counters
+that are kept in the RRD.
 
 <P>
 <HR>
-<H2><A NAME="What_can_I_do_with_this_tool_">What can I do with this tool ?
-
-</A></H2>
-RRDtool originated from MRTG (multi router traffic grapher) which itself
-came from a tiny little script to monitor the performance of a connection
-to the Internet. Since then, MRTG has also been used for several other
-purposes including temperature, speed, voltage, number of printouts and
-many other things. Most likely you will start to use the RRDtool to store
-and process data collected via SNMP. The data will most likely be bytes (or
-bits) transfered from and to a network or a computer. RRDtool lets you
-create a database, store data in it, retrieve that data and create graphs
-in GIF format for display on a web browser. Those GIF images are dependent
-on the data you collected and could be, for instance, an overview of the
-average network usage, or rather the peaks that occurred. It can also be
-used to display tidal waves, solar radiation, power consumption, number of
-visitors at an exhibition, noise levels near an airport, temperature on
-your favorite holiday location, temperature in the fridge and whatever you
-imagination can come up with. You need a sensor to measure the data and be
-able to feed the numbers to RRDtool. Many devices have such a sensor.
-
-
-<P>
+<H2><A NAME="What_can_I_do_with_this_tool_">What can I do with this tool ?</A></H2>
+<P>
+RRDtool originated from MRTG (Multi Router Traffic Grapher). MRTG started
+as a tiny little script for graphing the use of a connection to the
+Internet. MRTG evolved into a tool for graphing other data sources
+including temperature, speed, voltage, number of printouts and the like.
+Most likely you will start to use the RRDtool to store and process data
+collected via SNMP. The data will most likely be bytes (or bits) transfered
+from and to a network or a computer. RRDtool lets you create a database,
+store data in it, retrieve that data and create graphs in GIF format for
+display on a web browser. Those GIF images are dependent on the data you
+collected and could be, for instance, an overview of the average network
+usage, or the peaks that occurred. It can also be used to display tidal
+waves, solar radiation, power consumption, number of visitors at an
+exhibition, noise levels near an airport, temperature on your favorite
+holiday location, temperature in the fridge and whatever you imagination
+can come up with. You need a sensor to measure the data and be able to feed
+the numbers to RRDtool.
 
 <P>
 <HR>
-<H2><A NAME="What_if_I_still_have_problems_af">What if I still have problems after reading this document ?
-
-</A></H2>
-More exact, after re-reading this document :) It all depends on the kind of
-problems you have. If you are unable to compile the sources and you have a
-fairly common OS, it will probably not be the fault of RRDtool. There may
-be precompiled versions around on the Internet. If they come from trusted
-sources, get one of those. If on the other hand the program works but does
-not give you the expected results, it will be a problem with configuring
-it. Review your configuration and compare it with the examples that follow.
-
+<H2><A NAME="What_if_I_still_have_problems_af">What if I still have problems after reading this document ?</A></H2>
+<P>
+First of all: read it again! You may have missed something. If you are
+unable to compile the sources and you have a fairly common OS, it will
+probably not be the fault of RRDtool. There may be precompiled versions
+around on the Internet. If they come from trusted sources, get one of
+those. If on the other hand the program works but does not give you the
+expected results, it will be a problem with configuring it. Review your
+configuration and compare it with the examples that follow.
 
 <P>
-
 There is a mailing list and an archive of it. Read the list for a few weeks
 and search the archive. It is considered rude to just ask a question
-without reading the list, your problem may already have been solved for
-somebody else and you will be helped without writing a new a message at all
-... This is true for most, if not all, mailing lists and not only for this
-particular list! Look in the documentation that came with RRDtool for the
-location and usage of the list.
-
+without searching the archives: your problem may already have been solved
+for somebody else! This is true for most, if not all, mailing lists and not
+only for this particular list! Look in the documentation that came with
+RRDtool for the location and usage of the list.
 
 <P>
-
 I suggest you take a moment to subscribe to the mailing list right now by
 sending an email to &lt;<A
-HREF="MAILTO:rrd-users-request at list.ee.ethz.ch">rrd-users-request at list.ee.ethz.ch</A>
+HREF="mailto:rrd-users-request at list.ee.ethz.ch">rrd-users-request at list.ee.ethz.ch</A>
 &gt; with a subject of ``subscribe''. If you ever want to leave this list, you
 write an email to the same address but now with a subject of
 ``unsubscribe''.
 
-
-<P>
-
 <P>
 <HR>
-<H2><A NAME="How_will_you_help_me_">How will you help me ?
-
-</A></H2>
+<H2><A NAME="How_will_you_help_me_">How will you help me ?</A></H2>
+<P>
 By giving you some detailed descriptions with detailed examples. It is
-assumed that following the instructions in the order presented will build
-up enough knowledge of the program to experiment for yourself. If it
-doesn't work the first time, don't give up. Reread the stuff that you did
+assumed that following the instructions in the order presented will give
+you enough knowledge of RRDtool to experiment for yourself. If it doesn't
+work the first time, don't give up. Reread the stuff that you did
 understand, you may have missed something. By following the examples you
 get some hands-on experience and, even more important, some background
 information of how it works.
 
-
 <P>
-
 You will need to know something about hexadecimal numbers. If you don't
 then start with reading ``bin_dec_hex'' before you continue here.
 
-
-<P>
-
 <P>
 <HR>
-<H2><A NAME="Your_first_Round_Robin_Database">Your first Round Robin Database
-
-</A></H2>
+<H2><A NAME="Your_first_Round_Robin_Database">Your first Round Robin Database</A></H2>
+<P>
 In my opinion the best way to learn something is to actually do it. Why not
 start right now? We will create a database, put some values in it and
-extract this data again. It is expected that you get the same results when
-you try these examples yourself so do that. We will start with some easy
-stuff and compare a car with a router, or compare kilometers (miles if you
-wish) with bits and bytes. It's all the same: Some number over some time.
-
+extract this data again. Your output should be the same as the output that
+is included in this document.
 
 <P>
+We will start with some easy stuff and compare a car with a router, or
+compare kilometers (miles if you wish) with bits and bytes. It's all the
+same: some number over some time.
 
+<P>
 Assume we have a device that transfers bytes to and from the Internet. This
 device keeps a counter that starts at zero when it is turned on, increasing
 with every byte that is transfered. This counter will have a maximum value,
@@ -243,63 +200,44 @@
 all over at zero. This is the same as many counters in the world such as
 the mileage counter in a car. Most discussions about networking talk about
 bits per second so lets get used to that right away. Assume a byte is eight
-bits and start to think in bits not bytes. The counter however still counts
-bytes ! In the SNMP world most of the counters are 32 bits. That means they
-are counting from 0 to 4294967295. We will use these values in the
-examples. The device, when asked, returns the current value of the counter.
-We know the time that has passes since we last asked so we now know how
-many bytes have been transfered <CODE>***on</CODE> average*** per second.
-This is not very hard to calculate. First in words, then in calculi:
-
-
-<P>
+bits and start to think in bits not bytes. The counter, however, still
+counts bytes ! In the SNMP world most of the counters are 32 bits. That
+means they are counting from 0 to 4294967295. We will use these values in
+the examples. The device, when asked, returns the current value of the
+counter. We know the time that has passes since we last asked so we now
+know how many bytes have been transfered <CODE>***on</CODE> average*** per
+second. This is not very hard to calculate. First in words, then in
+calculations:
 
 <OL>
-<LI><STRONG><A NAME="item_">
-
-</A></STRONG>
+<LI><STRONG><A NAME="item__">.</A></STRONG>
+<P>
 Take the current counter, subtract the previous value from it.
 
-
+<LI><STRONG>.</STRONG>
 <P>
-
-<LI><STRONG><A NAME="item_">
-
-</A></STRONG>
 Do the same with the current time and the previous time.
 
-
+<LI><STRONG>.</STRONG>
 <P>
-
-<LI><STRONG><A NAME="item_">
-
-</A></STRONG>
 Divide the outcome of (1) by the outcome of (2), the result is the amount
 of bytes per second. Multiply by eight to get the number of bits per second
 (bps).
 
-
+</OL>
 <P>
-
 <PRE>  bps = (counter_now - counter_before) / (time_now - time_before) * 8
 </PRE>
-
 <P>
-
-</OL>
 For some people it may help to translate this to a automobile example: Do
 not try this example, and if you do, don't blame me for the results.
 
-
 <P>
-
 People who are not used to think in kilometers per hour can translate most
 into miles per hour by dividing km by 1.6 (close enough). I will use the
 following abbreviations:
 
-
 <P>
-
 <PRE> M:    meter
  KM:   kilometer (= 1000 meters).
  H:    hour
@@ -307,9 +245,7 @@
  KM/H: kilometers per hour
  M/S:  meters per second
 </PRE>
-
 <P>
-
 You're driving a car. At 12:05 you read the counter in the dashboard and it
 tells you that the car has moved 12345 KM until that moment. At 12:10 you
 look again, it reads 12357 KM. This means you have traveled 12 KM in five
@@ -317,89 +253,76 @@
 makes a nice comparison towards the problem of (bytes per five minutes)
 versus (bits per second).
 
-
 <P>
-
 We traveled 12 kilometers which is 12000 meters. We did that in five
 minutes which translates into 300 seconds. Our speed is 12000M / 300S
 equals 40 M/S.
 
-
 <P>
-
-We could also calculate the speed in KM/H: twelve times five minutes is an
-hour so we have to multiply 12 KM by 12 to get 144 KM/H. For our native
-English speaking friends: this is ninety MPH and therefore not recommended
-to try for yourself where I live :)
-
+We could also calculate the speed in KM/H: 12 times five minutes is an hour
+so we have to multiply 12 KM by 12 to get 144 KM/H. For our native English
+speaking friends: that's 90 MPH so don't try this example at home or where
+I live :)
 
 <P>
-
-Remember: these numbers are averages and there is no way to figure out from
-the numbers we got that you drove at a constant speed.
-
+Remember: these numbers are averages only. There is no way to figure out
+from the numbers, if you drove at a constant speed. There is an example
+later on in this tutorial that explains this.
 
 <P>
-
 I hope you understand that there is no difference in calculating M/S or
-bps, only the way we collect the data is different. Even the K from kilo is
+bps; only the way we collect the data is different. Even the K from kilo is
 the same as in networking terms k also means 1000.
 
-
 <P>
-
 We will now create a database where we can keep all these interesting
 numbers. The method used to start the program may differ slightly from OS
 to OS but I assume you can figure it out if it works different on your OS.
 Make sure you do not overwrite any file on your system when executing the
-following command (so: first look if it's safe!) and type the whole line as
-one long line (I had to split it for readability) and skip all of the '\'
-characters.
-
+following command and type the whole line as one long line (I had to split
+it for readability) and skip all of the '\' characters.
 
 <P>
-
 <PRE>   rrdtool create test.rrd             \
             --start 920804400          \
             DS:speed:COUNTER:600:U:U   \
             RRA:AVERAGE:0.5:1:24       \
             RRA:AVERAGE:0.5:6:10
 </PRE>
-
 <P>
-
 (So enter: <CODE>rrdtool create test.rrd --start 920804400 DS ...</CODE>)
 
-
-<P>
-
 <P>
 <HR>
-<H2><A NAME="What_has_been_created_">What has been created ?
-
-</A></H2>
+<H2><A NAME="What_has_been_created_">What has been created ?</A></H2>
+<P>
 We created the round robin database called test (test.rrd) which starts at
 noon the day I started (7th of march, 1999) writing this document. It holds
 one data source (DS) named ``speed'' that gets built from a counter. This
 counter is read every five minutes (default) In the same database two round
 robin archives (RRAs) are kept, one averages the data every time it is read
-(so: there's nothing to average) and keeps 24 samples (24 times 5 minutes
-is 2 hours). The other averages 6 values (half hour) and contains 10 of
-such averages (so: 5 hours) The remaining options will be discussed later
-on. Chances are that you are not in the same part of the world as I am.
-This means your time zone is different. In all examples where I talk about
-time, the hours may be wrong for you. This has little effect on the results
-of the examples, just correct the hours while reading.
-
+(eg there's nothing to average) and keeps 24 samples (24 times 5 minutes is
+2 hours). The other averages 6 values (half hour) and contains 10 of such
+averages (eg 5 hours) The remaining options will be discussed later on.
+
+<P>
+RRDtool works with special time stamps coming from the UNIX world. This
+time stamp is the number of seconds that passed since January 1st 1970 UTC.
+This time stamp is translated into local time and it will therefore look
+different for the different time zones.
+
+<P>
+Chances are that you are not in the same part of the world as I am. This
+means your time zone is different. In all examples where I talk about time,
+the hours may be wrong for you. This has little effect on the results of
+the examples, just correct the hours while reading. As an example: where I
+will see ``12:05'' the UK folks will see ``11:05''.
 
 <P>
-
 We now have to fill our database with some numbers. We'll pretend to have
 read the following numbers:
 
-
 <P>
-
 <PRE> 12:05  12345 KM
  12:10  12357 KM
  12:15  12363 KM
@@ -416,71 +339,85 @@
  13:10  12422 KM
  13:15  12423 KM
 </PRE>
-
 <P>
-
 We fill the database as follows:
 
-
 <P>
-
 <PRE> rrdtool update test.rrd 920804700:12345 920805000:12357 920805300:12363
  rrdtool update test.rrd 920805600:12363 920805900:12363 920806200:12373
  rrdtool update test.rrd 920806500:12383 920806800:12393 920807100:12399
  rrdtool update test.rrd 920807400:12405 920807700:12411 920808000:12415
  rrdtool update test.rrd 920808300:12420 920808600:12422 920808900:12423
 </PRE>
-
 <P>
-
 This reads: update our test database with the following numbers
 
-
 <P>
-
 <PRE> time 920804700, value 12345
  time 920805000, value 12357
 </PRE>
-
 <P>
-
 etcetera.
 
-
 <P>
-
 As you can see, it is possible to feed more than one value into the
 database in one command. I had to stop at three for readability but the
-real maximum will be OS dependent.
-
+real maximum is OS dependent.
 
 <P>
+We can now retrieve the data from our database using ``rrdtool fetch'':
 
-The time value may look strange to you, it is written in seconds since the
-first of January, 1970, midnight. Don't worry about this yet, just notice
-that there is a difference of 300 in between all values.
+<P>
+<PRE> rrdtool fetch test.rrd AVERAGE --start 920804400 --end 920809200
+</PRE>
+<P>
+It should return the following output:
 
+<P>
+<PRE>                speed
+</PRE>
+<P>
+<PRE> 920804700:       NaN
+ 920805000:      0.04
+ 920805300:      0.02
+ 920805600:      0.00
+ 920805900:      0.00
+ 920806200:      0.03
+ 920806500:      0.03
+ 920806800:      0.03
+ 920807100:      0.02
+ 920807400:      0.02
+ 920807700:      0.02
+ 920808000:      0.01
+ 920808300:      0.02
+ 920808600:      0.01
+ 920808900:      0.00
+ 920809200:       NaN
+</PRE>
+<P>
+If it doesn't, something may be wrong. Perhaps your OS will print ``NaN''
+in a different form. It represents ``Not A Number''. If your OS writes
+``U'' or ``UNKN'' or something similar that's okay. If something else is
+wrong, it will probably be due to an error you made (assuming that my
+tutorial is correct of course :-). In that case: delete the database and
+try again.
 
 <P>
+What this output represents will become clear in the rest of the tutorial.
 
 <P>
 <HR>
-<H2><A NAME="It_is_time_to_create_some_graphi">It is time to create some graphics
-
-</A></H2>
+<H2><A NAME="It_is_time_to_create_some_graphi">It is time to create some graphics</A></H2>
+<P>
 Try the following command:
 
-
 <P>
-
 <PRE> rrdtool graph speed.gif                                 \
          --start 920804400 --end 920808000               \
          DEF:myspeed=test.rrd:speed:AVERAGE              \
          LINE2:myspeed#FF0000
 </PRE>
-
 <P>
-
 This will create speed.gif which starts at 12:00 and ends at 13:00. There
 is a definition of variable myspeed, it is the data from RRA ``speed'' out
 of database ``test.rrd''. The line drawn is 2 pixels high, and comes from
@@ -489,108 +426,88 @@
 data to tell the average before that time. This will only happen when you
 miss some samples, this will not happen a lot, hopefully.
 
-
 <P>
-
-If this has worked: Congratulations. If not, check what went wrong.
-
+If this has worked: congratulations! If not, check what went wrong.
 
 <P>
-
 The colors are built up from red, green and blue. For each of the
 components, you specify how much to use in hexadecimal where 00 means not
-included and FF means fully included. The color white is a mixture of red,
-green and blue: FFFFFF The color black is all colors off: 000000 (Please,
-no discussions if black and white can be called colors)
-
+included and FF means fully included. The ``color'' white is a mixture of
+red, green and blue: FFFFFF The ``color'' black is all colors off: 000000
 
 <P>
-
-<PRE>   red    #FF0000
-   green  #00FF00
-   blue   #0000FF
-   purple #FF00FF     (mixed red with blue)
-   gray   #555555     (one third of all components)
+<PRE>   red     #FF0000
+   green   #00FF00
+   blue    #0000FF
+   magenta #FF00FF     (mixed red with blue)
+   gray    #555555     (one third of all components)
 </PRE>
-
-<P>
-
-The GIF you just created can be displayed using a web browser or other
-software you like. I can not provide you with an example of that, because
-there are too many different setups, possibilities etc.
-
-
 <P>
+The GIF you just created can be displayed using your favorite image viewer.
+Web browsers will display the GIF via the URL
+``file://the/path/to/speed.gif''
 
 <P>
 <HR>
-<H2><A NAME="Graphics_with_some_math">Graphics with some math
-
-</A></H2>
-When looking at the image, you notice that the horizontal axis displays
+<H2><A NAME="Graphics_with_some_math">Graphics with some math</A></H2>
+<P>
+When looking at the image, you notice that the horizontal axis is labeled
 12:10, 12:20, 12:30, 12:40 and 12:50. The two remaining times (12:00 and
 13:00) would not be displayed nicely so they are skipped. The vertical axis
 displays the range we entered. We provided kilometers and when divided by
 300 seconds, we get very small numbers. To be exact, the first value was 12
-(12357-12345) and divided by 300 this makes 0.04 RRDtool displays this as
-40 m which means 40 milli (so: NOT meters). What we did wrong was that we
-should have measured in meters, this would have been
-(12357000-12345000)/300 = 12000/300 = 40.
-
+(12357-12345) and divided by 300 this makes 0.04, which is displayed by
+RRDtool as ``40 m'' meaning ``40/1000''. The ``m'' has nothing to do with
+meters, kilometers or millimeters! RRDtool doesn't know about all this, it
+just works with numbers and not with meters...
 
 <P>
+What we did wrong was that we should have measured in meters, this would
+have been (12357000-12345000)/300 = 12000/300 = 40.
 
+<P>
 Let's correct that. We could recreate our database and store the correct
-data but there is another way: do some calculations while creating the gif
+data but there is a better way: do some calculations while creating the gif
 file !
 
-
 <P>
-
 <PRE>   rrdtool graph speed2.gif                           \
       --start 920804400 --end 920808000               \
       --vertical-label m/s                            \
       DEF:myspeed=test.rrd:speed:AVERAGE              \
-      &quot;CDEF:realspeed=myspeed,1000,*&quot;                 \
+      CDEF:realspeed=myspeed,1000,*                   \
       LINE2:realspeed#FF0000
 </PRE>
-
 <P>
-
 After viewing this GIF, you notice the ``m'' has disappeared. This it what
 the correct result would be. Also, a label has been added to the image.
 Apart from the things mentioned above, the GIF should be the same.
 
-
 <P>
-
-The calculations are done with the CDEF part. What it says is: take the
-data source myspeed and the number 1000, multiply those. The calculations
-are done using Reverse Polish Notation. It is an easy way of performing
-calculations after you understand it. You will, eventually but for now
-assume it is correct what I write and just keep to the examples in this
-file. Read the documentation that came with RRDtool (look in rrdgraph.doc)
-when you're ready for it.
-
+The calculations are in the CDEF part and are in Reverse Polish Notation
+(``RPN''). What it says is: ``take the data source myspeed and the number
+1000; multiply those''. Don't bother with RPN yet, it will be explained
+later on in more detail. Also, you may want to read my tutorial on CDEFs
+and Steve Rader's tutorial on RPN. But first finish this tutorial.
 
 <P>
-
 Hang on! If we can multiply values with 1000, it should also be possible to
-display kilometers per hour from the same data ! What do we need to do ? If
-we have meters per second, we can make this meters per hour by multiplying
-the value with 3600 (there go 3600 seconds in one hour). To get kilometers
-per hour, we need to divide by 1000. We end up with: value * 3600 / 1000 =
-value * 3.6 . Remember we also have to correct our mistake, so it is value
-* 3600 for us.
+display kilometers per hour from the same data!
 
+<P>
+To change a value that is measured in meters per second: -*- Calculate
+meters per hour: value * 3600 -*- Calculate kilometers per hour: value /
+1000 -*- Together this makes: value * (3600/1000) == value * 3.6
 
 <P>
+In our example database we made a mistake and we need to compensate for
+this by multiplying with 1000. Applying that correction: -*- value * 3.6
+<CODE>*1000</CODE> == value * 3600
 
+<P>
 Now let's create this GIF, and add some more magic ...
 
-
 <P>
-
 <PRE>   rrdtool graph speed3.gif                           \
       --start 920804400 --end 920808000               \
       --vertical-label km/h                           \
@@ -602,65 +519,34 @@
       AREA:good#00FF00:&quot;Good speed&quot;                   \
       AREA:fast#FF0000:&quot;Too fast&quot;
 </PRE>
-
 <P>
-
 This looks much better. Speed in KM/H and even an extra line with the
 maximum allowed speed (on the road I travel at). I also changed the colors
 used to display speed and changed it from a line into an area.
 
-
 <P>
-
 The calculations are more complex now. For the ``good'' speed they are:
 
-
-<P>
-
-<UL>
-<LI><STRONG></STRONG>
-Check if kmh is greater than 100 ( kmh,100 ) GT
-
-
 <P>
-
-<LI><STRONG></STRONG>
-If so, return 0, else kmh ((( kmh,100 ) GT ), 0, kmh) IF
-
-
+<PRE>   Check if kmh is greater than 100    ( kmh,100 ) GT
+   If so, return 0, else kmh           ((( kmh,100 ) GT ), 0, kmh) IF
+</PRE>
 <P>
-
-</UL>
 For the other speed:
 
-
 <P>
-
-<UL>
-<LI><STRONG></STRONG>
-Check if kmh is greater than 100 ( kmh,100 ) GT
-
-
-<P>
-
-<LI><STRONG></STRONG>
-If so, return kmh, else return 0 ((( kmh,100) GT ), kmh, 0) IF
-
-
-<P>
-
-</UL>
+<PRE>   Check if kmh is greater than 100    ( kmh,100 ) GT
+   If so, return kmh, else return 0    ((( kmh,100) GT ), kmh, 0) IF
+</PRE>
 <P>
 <HR>
-<H2><A NAME="Graphics_Magic">Graphics Magic
-
-</A></H2>
-I like to believe there are virtually no limits about what RRDtool can do.
-I will not explain how it works, but look at the following GIF:
-
-
+<H2><A NAME="Graphics_Magic">Graphics Magic</A></H2>
 <P>
+I like to believe there are virtually no limits to how RRDtool graph can
+manipulate data. I will not explain how it works, but look at the following
+GIF:
 
+<P>
 <PRE>   rrdtool graph speed4.gif                           \
       --start 920804400 --end 920808000               \
       --vertical-label km/h                           \
@@ -674,14 +560,10 @@
       AREA:fast#550000:&quot;Too fast&quot;                     \
       STACK:over#FF0000:&quot;Over speed&quot;
 </PRE>
-
 <P>
-
 Let's create a quick and dirty HTML page to view three GIFs:
 
-
 <P>
-
 <PRE>   &lt;HTML&gt;&lt;HEAD&gt;&lt;TITLE&gt;Speed&lt;/TITLE&gt;&lt;/HEAD&gt;&lt;BODY&gt;
    &lt;IMG src=&quot;speed2.gif&quot; alt=&quot;Speed in meters per second&quot;&gt;
    &lt;BR&gt;
@@ -690,251 +572,185 @@
    &lt;IMG src=&quot;speed4.gif&quot; alt=&quot;Traveled too fast?&quot;&gt;
    &lt;/BODY&gt;&lt;/HTML&gt;
 </PRE>
-
 <P>
-
 Name the file ``speed.html'' or similar, and view it.
 
-
 <P>
-
 Now, all you have to do is measure the values regularly and update the
-database. Every time you create these three GIFs and reload the page and
-the GIFs (better reread these last three words!) you know how fast you
-traveled.
-
-
-<P>
+database. When you want to view the data, recreate the GIFs and make sure
+to refresh them in your browser. (Note: just clicking reload may not be
+enough; Netscape in particular has a problem doing so and you'll need to
+click reload while pressing the shift key).
 
 <P>
 <HR>
-<H2><A NAME="Updates_in_Reality">Updates in Reality
-
-</A></H2>
-You already looked at the ``update'' tool. It took one or more parameters
+<H2><A NAME="Updates_in_Reality">Updates in Reality</A></H2>
+<P>
+We've already used the ``update'' command: it took one or more parameters
 in the form of ``&lt;time&gt;:&lt;value&gt;''. You'll be glad to know that
 you can get the current time by filling in a ``N'' as the time. If you
 wish, you can also use the ``time'' function in perl. The shortest example
 in this doc :)
 
-
 <P>
-
 <PRE>   perl -e 'print time, &quot;\n&quot; '
 </PRE>
-
 <P>
-
-How you can run a program on regular intervals is OS specific, so I just
-give you an example script in a sort of pseudo code: (Do not try this with
-our test database, it is used in further examples)
-
+How you can run a program on regular intervals is OS specific. But here's
+an example in pseudo code:
 
 <P>
-
 <PRE>   Get the value, put it in variable &quot;$speed&quot;
    rrdtool update speed.rrd N:$speed
 </PRE>
-
 <P>
+(Do not try this with our test database, it is used in further examples)
 
+<P>
 This is all. Run this script every five minutes. When you need to know what
 the graphics look like, run the examples above. You could put them in a
 script. After running that script, view index.html
 
-
-<P>
-
 <P>
 <HR>
-<H2><A NAME="Some_words_on_SNMP">Some words on SNMP
-
-</A></H2>
+<H2><A NAME="Some_words_on_SNMP">Some words on SNMP</A></H2>
+<P>
 I can imagine very few people will be able to get real data from their car
 every five minutes, all other people will have to settle for some other
-kind of counter. You could measure the number of pages printed by the
-laser-jet printer, the coffee made by the coffee machine, a device that
-counts the electricity used, whatever. Just as long as it is an
-incrementing counter that you can measure regularly, you can graph it
-against time as we did. Most people will use the counter that keeps track
-of octets (bytes) transfered by a routing device so we have to do just
-that. We will start with a description of how to collect data. Some people
-will make a remark that there are tools who can do this data collection for
-you. They are right! However, I feel it is important that you understand
-they are not necessary. If you have to look why things went wrong, you need
-to know how the stuff works.
-
+kind of counter. You could measure the number of pages printed by a
+printer, the coffee made by the coffee machine, a device that counts the
+electricity used, whatever. Any incrementing counter can be monitored and
+graphed using the stuff you learned until now. Later on we will also be
+able to monitor other types of values like temperature. Most people will
+use the counter that keeps track of octets (bytes) transfered by a network
+device so we have to do just that. We will start with a description of how
+to collect data. Some people will make a remark that there are tools who
+can do this data collection for you. They are right! However, I feel it is
+important that you understand they are not necessary. When you have to
+determine why things went wrong you need to know how they work.
 
 <P>
-
 One tool used in the example has been talked about very briefly in the
 beginning of this document, it is called SNMP. It is a way of talking to
 equipment. The tool I use below is called ``snmpget'' and this is how it
 works:
 
-
 <P>
-
 <PRE>   snmpget device password OID
 </PRE>
-
-<P>
-
-For device you substitute the name of your device, for password you use the
-``community'' as it is called. For most devices ``public'' will do but this
-can be disabled, altered or protected for privacy and security reasons. You
-will need to find this out as there is no way I can tell what you ( ...your
-device... ) are keeping a secret from me.
-
-
 <P>
-
-Then there is this third parameter, called OID. When you start to learn
-about SNMP it looks very confusing. It isn't all that difficult when you
-look at the Management Information Base or in short: the MIB. It is an
-upside-down tree, with a single node as the root and from there a number of
-branches. These branches end up in another node, they branch out, etc. All
-the branches have a name and they form the path that we follow all the way
-down. The branches that we follow are named: iso, org, dod, internet, mgmt
-and mib-2. These names can also be written down as numbers and are 1 3 6 1
-2 1.
-
+For device you substitute the name, or the IP address, of your device. For
+password you use the ``community read string'' as it is called in the SNMP
+world. For some devices the default of ``public'' might work, however this
+can be disabled, altered or protected for privacy and security reasons.
+Read the documentation that comes with your device or program.
+
+<P>
+Then there is this third parameter, called OID, which means ``object
+identifier''.
+
+<P>
+When you start to learn about SNMP it looks very confusing. It isn't all
+that difficult when you look at the Management Information Base (``MIB'').
+It is an upside-down tree that describes data, with a single node as the
+root and from there a number of branches. These branches end up in another
+node, they branch out, etc. All the branches have a name and they form the
+path that we follow all the way down. The branches that we follow are
+named: iso, org, dod, internet, mgmt and mib-2. These names can also be
+written down as numbers and are 1 3 6 1 2 1.
 
 <P>
-
 <PRE>   iso.org.dod.internet.mgmt.mib-2 (1.3.6.1.2.1)
 </PRE>
-
-<P>
-
-From there, we are especially interested in the branch ``interfaces'' which
-has number 2 (so: 1.3.6.1.2.1.2 or 1.3.6.1.2.1.interfaces).
-
-
 <P>
-
-The SNMP programs that I know can take above path as a default, so I could
-walk to interfaces without writing it in full. To do that, the path has to
-be written as interfaces, without a leading dot. I could also use the long
-form, then I need to start with a dot.
-
+There is a lot of confusion about the leading dot that some programs use.
+There is *no* leading dot in an OID. However, some programs can use above
+part of OIDs as a default. To indicate the difference between abbreviated
+OIDs and full OIDs they need a leading dot when you specify the complete
+OID. Often those programs will leave out the default portion when returning
+the data to you. To make things worse, they have several default prefixes
+...
 
 <P>
-
-I can intermix numbers and names as I like. 1.3.6.1.2.1 is the same as
-iso.org.dod.1.2.1 and 1.3.6.internet.2.mib-2 For interfaces I could write
-``interfaces'', 2, or a long version by prefixing it with
-``.1.3.6.1.2.1.''. Just try what works for you and do read the manual for
-the version of snmpget you are using.
-
+Right, lets continue to the start of our OID: we had 1.3.6.1.2.1 From
+there, we are especially interested in the branch ``interfaces'' which has
+number 2 (eg 1.3.6.1.2.1.2 or 1.3.6.1.2.1.interfaces).
 
 <P>
-
 First, we have to get some SNMP program. First look if there is a
 pre-compiled package available for your OS. This is the preferred way. If
 not, you will have to get yourself the sources and compile those. The
 Internet is full of sources, programs etc. Find information using a search
-engine or whatever you prefer. You are on your own here, sorry.
-
+engine or whatever you prefer. As a suggestion: look for CMU-SNMP. It is
+commonly used.
 
 <P>
-
 Assume you got the program. First try to collect some data that is
 available on most systems. Remember: there is a short name for the part of
-the tree that interests us most in the world we live in ! I will use the
-short version as I think this document is large enough as it is. If that
-doesn't work for you, prefix with .1.3.6.1.2.1 and try again. Also, Read
-The Fine Manual. Skip the parts you cannot understand yet, you should be
-able to find out how to start the program and use it.
-
+the tree that interests us most in the world we live in!
 
 <P>
+I will use the short version as I think this document is large enough as it
+is. If that doesn't work for you, prefix with .1.3.6.1.2.1 and try again.
+Also, Read The Fine Manual. Skip the parts you cannot understand yet, you
+should be able to find out how to start the program and use it.
 
+<P>
 <PRE>   snmpget myrouter public system.sysdescr.0
 </PRE>
-
 <P>
-
 The device should answer with a description of itself, perhaps empty. Until
 you got a valid answer from a device, perhaps using a different
 ``password'', or a different device, there is no point in continuing.
 
-
 <P>
-
 <PRE>   snmpget myrouter public interfaces.ifnumber.0
 </PRE>
-
 <P>
-
 Hopefully you get a number as a result, the number of interfaces. If so,
 you can carry on and try a different program called ``snmpwalk''.
 
-
 <P>
-
 <PRE>   snmpwalk myrouter public interfaces.iftable.ifentry.ifdescr
 </PRE>
-
 <P>
-
 If it returns with a list of interfaces, you're almost there. Here's an
 example: [user at host /home/alex]$ snmpwalk cisco public 2.2.1.2
 
-
 <P>
-
 <PRE>   interfaces.ifTable.ifEntry.ifDescr.1 = &quot;BRI0: B-Channel 1&quot;
    interfaces.ifTable.ifEntry.ifDescr.2 = &quot;BRI0: B-Channel 2&quot;
    interfaces.ifTable.ifEntry.ifDescr.3 = &quot;BRI0&quot; Hex: 42 52 49 30
    interfaces.ifTable.ifEntry.ifDescr.4 = &quot;Ethernet0&quot;
    interfaces.ifTable.ifEntry.ifDescr.5 = &quot;Loopback0&quot;
 </PRE>
-
 <P>
-
 On this cisco equipment, I would like to monitor the ``Ethernet0''
 interface and see that it is number four. I try:
 
-
 <P>
-
 <PRE>   [user at host /home/alex]$ snmpget cisco public 2.2.1.10.4 2.2.1.16.4
 </PRE>
-
 <P>
-
 <PRE>   interfaces.ifTable.ifEntry.ifInOctets.4 = 2290729126
    interfaces.ifTable.ifEntry.ifOutOctets.4 = 1256486519
 </PRE>
-
 <P>
-
 So now I have two OIDs to monitor and they are (in full, this time):
 
-
 <P>
-
 <PRE>   1.3.6.1.2.1.2.2.1.10
 </PRE>
-
 <P>
-
 and
 
-
 <P>
-
 <PRE>   1.3.6.1.2.1.2.2.1.16
 </PRE>
-
 <P>
-
 both with an interface number of 4.
 
-
 <P>
-
 Don't get fooled, this wasn't my first try. It took some time for me too to
 understand what all these numbers mean, it does help a lot when they get
 translated into descriptive text... At least, when people are talking about
@@ -942,20 +758,14 @@
 number (0 if it is not interface dependent) and try snmpwalk if you don't
 get an answer from snmpget.
 
-
-<P>
-
-If you understand above part, and get numbers from your device, it is time
-to continue with the following. If not, then go back.
-
-
 <P>
+If you understand above part, and get numbers from your device, continue on
+with this tutorial. If not, then go back and re-read this part.
 
 <P>
 <HR>
-<H2><A NAME="A_Real_World_Example">A Real World Example
-
-</A></H2>
+<H2><A NAME="A_Real_World_Example">A Real World Example</A></H2>
+<P>
 Let the fun begin. First, create a new database. It contains data from two
 counters, called input and output. The data is put into archives that
 average it. They take 1, 6, 24 or 288 samples at a time. They also go into
@@ -963,53 +773,57 @@
 The time in-between samples is 300 seconds, a good starting point, which is
 the same as five minutes.
 
-
 <P>
-
-<PRE> 1 sample averaged stays 1 period of 5 minutes
+<PRE> 1 sample &quot;averaged&quot; stays 1 period of 5 minutes
  6 samples averaged become one average on 30 minutes
  24 samples averaged become one average on 2 hours
  288 samples averaged become one average on 1 day
 </PRE>
-
 <P>
+Lets try to be compatible with MRTG: MRTG stores about the following amount
+of data:
 
-<PRE> There are 600 samples of five minutes, together just over two days
- There are 600 samples of 30 minutes, almost two weeks
- There are 600 samples of 2 hours, 50 hour or almost two months
- There are 732 samples of 1 day, just over two years
+<P>
+<PRE> 600 5-minute samples:    2   days and 2 hours
+ 600 30-minute samples:  12.5 days
+ 600 2-hour samples:     50   days
+ 600 1-day samples:     732   days
 </PRE>
-
 <P>
-
-For people used to MRTG that even have read the manuals, these numbers
-should look familiar...
-
+These ranges are appended so the total amount of data kept is approximately
+797 days. RRDtool stores the data differently, it doesn't start the
+``weekly'' archive where the ``daily'' archive stopped. For both archives
+the most recent data will be near ``now'' and therefore we will need to
+keep more data than MRTG does!
 
 <P>
+We will need:
 
+<P>
+<PRE> 600 samples of 5 minutes  (2 days and 2 hours)
+ 700 samples of 30 minutes (2 days and 2 hours, plus 12.5 days)
+ 775 samples of 2 hours    (above + 50 days)
+ 797 samples of 1 day      (above + 732 days, rounded up to 797)
+</PRE>
+<P>
 <PRE>   rrdtool create myrouter.rrd         \
             DS:input:COUNTER:600:U:U   \
             DS:output:COUNTER:600:U:U  \
             RRA:AVERAGE:0.5:1:600      \
-            RRA:AVERAGE:0.5:6:600      \
-            RRA:AVERAGE:0.5:24:600     \
-            RRA:AVERAGE:0.5:288:732    \
+            RRA:AVERAGE:0.5:6:700      \
+            RRA:AVERAGE:0.5:24:775     \
+            RRA:AVERAGE:0.5:288:797    \
             RRA:MAX:0.5:1:600          \
-            RRA:MAX:0.5:6:600          \
-            RRA:MAX:0.5:24:600         \
-            RRA:MAX:0.5:288:732
+            RRA:MAX:0.5:6:700          \
+            RRA:MAX:0.5:24:775         \
+            RRA:MAX:0.5:288:797
 </PRE>
-
 <P>
-
 Next thing to do is collect data and store it. Here is an example. It is
 written partially in pseudo code so you will have to find out what to do
 exactly on your OS to make it work.
 
-
 <P>
-
 <PRE>   while not the end of the universe
    do
       get result of
@@ -1019,72 +833,50 @@
          snmpget router community 2.2.1.16.4
       into variable $out
 </PRE>
-
 <P>
-
 <PRE>      rrdtool update myrouter.rrd N:$in:$out
 </PRE>
-
 <P>
-
 <PRE>      wait for 5 minutes
    done
 </PRE>
-
 <P>
-
 Then, after collecting data for a day, try to create an image using:
 
-
 <P>
-
 <PRE>   rrdtool graph myrouter-day.gif --start -86400 \
             DEF:inoctets=myrouter.rrd:input:AVERAGE \
             DEF:outoctets=myrouter.rrd:output:AVERAGE \
             AREA:inoctets#00FF00:&quot;In traffic&quot; \
             LINE1:outoctets#0000FF:&quot;Out traffic&quot;
 </PRE>
-
 <P>
-
 This should produce a picture with one day worth of traffic. One day is 24
 hours of 60 minutes of 60 seconds: 24*60*60=86400, we start at now minus
-86400 seconds. We DEFine inoctets and outoctets as the average values from
-the database myrouter.rrd and draw an area for the ``in'' traffic and a
-line for the ``out'' traffic.
-
+86400 seconds. We define (with DEFs) inoctets and outoctets as the average
+values from the database myrouter.rrd and draw an area for the ``in''
+traffic and a line for the ``out'' traffic.
 
 <P>
-
-View the image and keep logging for a few more days. If you like, you could
-try the examples from the test database and see if you can play around with
-the options and calculations.
-
+View the image and keep logging data for a few more days. If you like, you
+could try the examples from the test database and see if you can get
+various options and calculations working.
 
 <P>
-
 Suggestion:
 
-
 <P>
-
 Display in bytes per second and in bits per second. Make the Ethernet
 graphics go red if they are over four megabits per second.
 
-
-<P>
-
 <P>
 <HR>
-<H2><A NAME="Consolidation_Functions">Consolidation Functions
-
-</A></H2>
+<H2><A NAME="Consolidation_Functions">Consolidation Functions</A></H2>
+<P>
 A few paragraphs back I mentioned the possibility of keeping the maximum
 values instead of the average values. Let's go into this a bit more.
 
-
 <P>
-
 Recall all the stuff about the speed of the car. Suppose we drove at 144
 KM/H during 5 minutes and then were stopped by the police for 25 minutes.
 At the end of the lecture we would take our laptop and create+view the
@@ -1094,18 +886,14 @@
 translated into KM/H, with a result of 24 KM/H. I would still get a ticket
 but not for speeding anymore :)
 
-
 <P>
-
 Obviously, in this case, we shouldn't look at the averages. In some cases
 they are handy. If you want to know how much KM you had traveled, the
 picture would be the right one to look at. On the other hand, for the speed
 that we traveled at, the maximum number seen is much more valuable. (later
 we will see more types)
 
-
 <P>
-
 It is the same for data. If you want to know the amount, look at the
 averages. If you want to know the rate, look at the maximum. Over time,
 they will grow apart more and more. In the last database we have created,
@@ -1115,66 +903,52 @@
 96/24=4 KM/H (as I travel about 94 kilometers on a day) during week days,
 and maximum of 120 KM/H on weekdays (my top speed that I reach every day).
 
-
 <P>
-
 Big difference. Do not look at the second graph to estimate the distances
 that I travel and do not look at the first graph to estimate my speed. This
 will work if the samples are close together, as they are in five minutes,
 but not if you average.
 
-
 <P>
-
 On some days, I go for a long ride. If I go across Europe and travel for
 over 12 hours, the first graph will rise to about 60 KM/H. The second one
 will show 180 KM/H. This means that I traveled a distance of 60 KM/H times
 24 H = 1440 KM. I did this with a higher speed and a maximum around 180
 KM/H. This doesn't mean that I traveled for 8 hours at a constant speed of
-180 KM/H ! This is a real example: go with the flow through Germany and
-stop a few times for gas and coffee. Drive slowly through Austria and the
-Netherlands. Be careful in the mountains and villages. If you would look at
-the graphs created from the five-minute averages you would get a totally
-different picture. You would see the same values on the average and maximum
-graphs (provided I measured every 300 seconds). You would be able to see
-when I stopped, when I was in top gear, when I drove over fast motor-ways
-etc. The granularity of the data is much higher, so you can see more.
-However, this takes 12 samples per hour, or 288 values per day, so it would
-be too much to keep for a long period of time. Therefore we average it,
-eventually to one value per day. From this one value, we cannot see much
-detail.
-
+180 KM/H ! This is a real example: go with the flow through Germany (fast!)
+and stop a few times for gas and coffee. Drive slowly through Austria and
+the Netherlands. Be careful in the mountains and villages. If you would
+look at the graphs created from the five-minute averages you would get a
+totally different picture. You would see the same values on the average and
+maximum graphs (provided I measured every 300 seconds). You would be able
+to see when I stopped, when I was in top gear, when I drove over fast
+hiways etc. The granularity of the data is much higher, so you can see
+more. However, this takes 12 samples per hour, or 288 values per day, so it
+would be too much to keep for a long period of time. Therefore we average
+it, eventually to one value per day. From this one value, we cannot see
+much detail.
 
 <P>
-
 Make sure you understand the last few paragraphs. There is no value in only
 a line and a few axis, you need to know what they mean and interpret the
 data in a good way. This is true for all data.
 
-
 <P>
-
 The biggest mistake you can make is to use the collected data for something
 that it is not suitable for. You would be better off if you would not have
 the graphics at all in that case.
 
-
-<P>
-
 <P>
 <HR>
-<H2><A NAME="Let_s_review_what_you_now_should">Let's review what you now should know.
-
-</A></H2>
+<H2><A NAME="Let_s_review_what_you_now_should">Let's review what you now should know.</A></H2>
+<P>
 You now know how to create a database. You can put the numbers in it, get
 them out again by creating an image, do math on the data from the database
 and view the outcome instead of the raw data. You know about the difference
 between averages and maxima, and when to use which (or at least you have an
 idea).
 
-
 <P>
-
 RRDtool can do more than what we have learned up to now. Before you
 continue with the rest of this doc, I recommend that you reread from the
 start and try some modifications on the examples. Make sure you fully
@@ -1182,56 +956,42 @@
 with the rest of this doc but also in your day to day monitoring long after
 you read this introduction.
 
-
-<P>
-
 <P>
 <HR>
-<H2><A NAME="Data_Source_Types">Data Source Types
-
-</A></H2>
+<H2><A NAME="Data_Source_Types">Data Source Types</A></H2>
+<P>
 All right, you feel like continuing. Welcome back and get ready for an
 increased speed in the examples and explanation.
 
-
 <P>
-
 You know that in order to view a counter over time, you have to take two
 numbers and divide the difference of them between the time lapsed. This
 makes sense for the examples I gave you but there are other possibilities.
 For instance, I'm able to retrieve the temperature from my router in three
-places namely the inlet, the so called hot-spot and the exhaust. If I take
-the difference of the two samples and divide that by 300 (seconds) there
-would not be very much to display ... If there would be anything to display
-it would be the fluctuations in the temperature and if they produce
-noticeable results when divided by 300, I'd better look for a new computer
-room.
-
-
-<P>
-
-So, what can we do ? RRDtool can also store the values you measure directly
-as they are (this is not entirely true but close enough). The graphs we
-make look much better, they will show a rather constant value. I know when
-the router is busy (it works -&gt; it uses more electricity -&gt; it
-generates more heat -&gt; the temperature rises). I know when the doors are
-left open (the room is cooled -&gt; the warm air from the rest of the
-building flows into the computer room -&gt; the inlet temperature rises)
-etc. The data type we use when creating the database before was counter, we
-now have a different data type and thus a different name for it. It is
-called GAUGE. There are more such data types:
-
+places namely the inlet, the so called hot-spot and the exhaust. These
+values are not counters. If I take the difference of the two samples and
+divide that by 300 seconds I would be asking for the temperature change per
+second. Hopefully this is zero! If not, the computerroom is on fire :)
+
+<P>
+So, what can we do ? We can tell RRDtool to store the values we measure
+directly as they are (this is not entirely true but close enough). The
+graphs we make will look much better, they will show a rather constant
+value. I know when the router is busy (it works -&gt; it uses more
+electricity -&gt; it generates more heat -&gt; the temperature rises). I
+know when the doors are left open (the room is cooled -&gt; the warm air
+from the rest of the building flows into the computer room -&gt; the inlet
+temperature rises) etc. The data type we use when creating the database
+before was counter, we now have a different data type and thus a different
+name for it. It is called GAUGE. There are more such data types:
 
 <P>
-
 <PRE> - COUNTER   we already know this one
  - GAUGE     we just learned this one
  - DERIVE
  - ABSOLUTE
 </PRE>
-
 <P>
-
 The two new types are DERIVE and ABSOLUTE. Absolute can be used like
 counter with one difference: RRDtool assumes the counter is reset when it's
 read. That is: its delta is known without calculation by RRDtool whereas
@@ -1241,14 +1001,10 @@
 counter. Unlike counter, it can also decrease so it can have a negative
 delta. Again, the rest of the calculations stay the same.
 
-
 <P>
-
 Let's try them all:
 
-
 <P>
-
 <PRE>   rrdtool create all.rrd --start 978300900 \
             DS:a:COUNTER:600:U:U \
             DS:b:GAUGE:600:U:U \
@@ -1272,76 +1028,56 @@
             DEF:linec=all.rrd:c:AVERAGE LINE3:linec#0000FF:&quot;Line C&quot; \
             DEF:lined=all.rrd:d:AVERAGE LINE3:lined#000000:&quot;Line D&quot;
 </PRE>
-
-<P>
-
 <P>
 <HR>
-<H2><A NAME="RRDtool_under_the_Microscope">RRDtool under the Microscope
-
-</A></H2>
+<H2><A NAME="RRDtool_under_the_Microscope">RRDtool under the Microscope</A></H2>
 <UL>
-<LI><STRONG></STRONG>
+<LI>
+<P>
 Line A is a counter so it should continuously increment and RRDtool should
 calculate the differences. Also, RRDtool needs to divide the difference by
 the amount of time lapsed. This should end up as a straight line at 1 (the
 deltas are 300, the time is 300).
 
-
+<LI>
 <P>
-
-<LI><STRONG></STRONG>
 Line B is of type gauge. These are ``real'' values so they should match
 what we put in: a sort of a wave.
 
-
+<LI>
 <P>
-
-<LI><STRONG></STRONG>
 Line C is derive. It should be a counter that can decrease. It does so
 between 2400 and 0, with 1800 in-between.
 
-
+<LI>
 <P>
-
-<LI><STRONG></STRONG>
 Line D is of type absolute. This is like counter but it works on values
 without calculating the difference. The numbers are the same and as you can
 see (hopefully) this has a different result.
 
-
-<P>
-
 </UL>
+<P>
 This translates in the following values, starting at 23:10 and ending at
 00:10 the next day (where U means unknown/unplotted):
 
-
 <P>
-
 <PRE> - Line A:  u  u  1  1  1  1  1  1  1  1  1  u
  - Line B:  u  1  3  5  3  1  2  4  6  4  2  u
- - Line C:  u  u  2  2  2  0 -2 -6 -2  0  2  u
+ - Line C:  u  u  2  2  2  0 -2 -6  2  0  2  u
  - Line D:  u  1  2  3  4  5  6  7  8  9 10  u
 </PRE>
-
 <P>
-
 If your GIF shows all this, you know you have typed the data correct, the
 RRDtool executable is working properly, your viewer doesn't fool you and
 you successfully entered the year 2000 :) You could try the same example
 four times, each time with only one of the lines.
 
-
 <P>
-
 Let's go over the data again:
 
-
-<P>
-
 <UL>
-<LI><STRONG></STRONG>
+<LI>
+<P>
 Line A: 300,600,900 and so on. The counter delta is a constant 300 and so
 it the time delta. A number divided by itself is always 1 (except when
 dividing by zero which is undefined/illegal). Why is it that the first
@@ -1349,26 +1085,20 @@
 didn't have a value to calculate the delta from so we don't know where we
 started. It would be wrong to assume we started at zero so we don't !
 
-
+<LI>
 <P>
-
-<LI><STRONG></STRONG>
 Line B: There is nothing to calculate. The numbers are as is.
 
-
+<LI>
 <P>
-
-<LI><STRONG></STRONG>
 Line C: Again, the start-out value is unknown. The same story is valid like
 for line A. In this case the deltas are not constant so the line is not. If
 we would put the same numbers in the database as we did for line A, we
 would have gotten the same line. Unlike type counter, this type can
 decrease and I hope to show you later on why there is a difference.
 
-
+<LI>
 <P>
-
-<LI><STRONG></STRONG>
 Line D: Here the device calculates the deltas. Therefore we DO know the
 first delta and it is plotted. We had the same input as with line A but the
 meaning of this input is different. Therefore the line is different. In
@@ -1376,15 +1106,11 @@
 constant 300 and therefore the division of the two gives increasing
 results.
 
-
-<P>
-
 </UL>
 <P>
 <HR>
-<H2><A NAME="Counter_Wraps">Counter Wraps
-
-</A></H2>
+<H2><A NAME="Counter_Wraps">Counter Wraps</A></H2>
+<P>
 There are a few more basics to show. Some important options are still to be
 covered and we haven't look at counter wraps yet. First the counter wrap:
 In our car we notice that our counter shows 999987. We travel 20 KM and the
@@ -1398,44 +1124,30 @@
 is negative, this can be compensated for by adding the maximum value of the
 counter + 1. For our car this would be:
 
-
 <P>
-
 <PRE> Delta = 7 - 999987 = -999980    (instead of 1000007-999987=20)
 </PRE>
-
 <P>
-
 <PRE> Real delta = -999980 + 999999 + 1 = 20
 </PRE>
-
 <P>
-
-At the moment of writing this document, RRDtool knows of counters that are
+At the time of writing this document, RRDtool knows of counters that are
 either 32 bits or 64 bits of size. These counters can handle the following
 different values:
 
-
 <P>
-
 <PRE> - 32 bits: 0 ..           4294967295
  - 64 bits: 0 .. 18446744073709551615
 </PRE>
-
 <P>
-
 If these numbers look strange to you, you would like to view them in their
 hexadecimal form:
 
-
 <P>
-
 <PRE> - 32 bits: 0 ..         FFFFFFFF
  - 64 bits: 0 .. FFFFFFFFFFFFFFFF
 </PRE>
-
 <P>
-
 RRDtool handles both counters the same. If an overflow occurs and the delta
 would be negative, RRDtool first adds the maximum of a small counter + 1 to
 the delta. If the delta is still negative, it had to be the large counter
@@ -1449,27 +1161,19 @@
 problem would not even be worth thinking about. Even though I did include
 an example of it so you can judge that for yourself.
 
-
 <P>
-
 The next section gives you some numerical examples for counter-wraps. Try
 to do the calculations yourself or just believe me if your calculator can't
 handle the numbers :)
 
-
 <P>
-
 Correction numbers:
 
-
 <P>
-
 <PRE> - 32 bits: (4294967295+1) =                                 4294967296
  - 64 bits: (18446744073709551615+1)-correction1 = 18446744069414584320
 </PRE>
-
 <P>
-
 <PRE> Before:        4294967200
  Increase:             100
  Should become: 4294967300
@@ -1477,9 +1181,7 @@
  Delta:        -4294967196
  Correction1:  -4294967196 +4294967296 = 100
 </PRE>
-
 <P>
-
 <PRE> Before:        18446744073709551000
  Increase:                       800
  Should become: 18446744073709551800
@@ -1488,9 +1190,7 @@
  Correction1:  -18446744073709550816 +4294967296 = -18446744069414583520
  Correction2:  -18446744069414583520 +18446744069414584320 = 800
 </PRE>
-
 <P>
-
 <PRE> Before:        18446744073709551615 ( maximum value )
  Increase:      18446744069414584320 ( absurd increase, minimum for
  Should become: 36893488143124135935             this example to work )
@@ -1499,9 +1199,7 @@
  Correction1:  -4294967296 + 4294967296 = 0
  (not negative -&gt; no correction2)
 </PRE>
-
 <P>
-
 <PRE> Before:        18446744073709551615 ( maximum value )
  Increase:      18446744069414584319 ( one less increase )
  Should become: 36893488143124135934
@@ -1510,45 +1208,36 @@
  Correction1:  -4294967297 +4294967296 = -1
  Correction2:  -1 +18446744069414584320 = 18446744069414584319
 </PRE>
-
 <P>
-
 As you can see from the last two examples, you need strange numbers for
 RRDtool to fail (provided it's bug free of course) so this should not
 happen. However, SNMP or whatever method you choose to collect the data
-might also fail and it is not uncommon to get wrong numbers occasionally.
-We can't prevent all errors but there are some things we could do. RRDtool
-create takes two special parameters for this. They define the minimum and
-maximum allowed value. Until now, we made them ``U'' for Unknown. You may
-(not: must) provide values for one or both of them and if RRDtool receives
-values that are outside these limits, it will ignore them. For a
-thermometer in degrees Celsius, the absolute minimum is just under -273.
-For my router, I can assume this minimum is much higher so I would say it
-is 10. The maximum temperature for my router I would state as 80. Any
-higher and the device would be out of order. For my car, I would never
-expect negative numbers and also I would not expect numbers to be higher
-than 230. Anything else, and there must have been an error. Remember: the
-opposite is not true, if the numbers pass this check it doesn't mean that
-they are correct. Always judge the graph with a healthy dose of paranoia if
-it looks weird.
-
-
-<P>
+might also report wrong numbers occasionally. We can't prevent all errors
+but there are some things we can do. The RRDtool ``create'' command takes
+two special parameters for this. They define the minimum and maximum
+allowed value. Until now, we used ``U'', meaning ``unknown''. If you
+provide values for one or both of them and if RRDtool receives values that
+are outside these limits, it will ignore those values. For a thermometer in
+degrees Celsius, the absolute minimum is just under -273. For my router, I
+can assume this minimum is much higher so I would say it is 10. The maximum
+temperature for my router I would state as 80. Any higher and the device
+would be out of order. For my car, I would never expect negative numbers
+and also I would not expect numbers to be higher than 230. Anything else,
+and there must have been an error. Remember: the opposite is not true, if
+the numbers pass this check it doesn't mean that they are correct. Always
+judge the graph with a healthy dose of paranoia if it looks weird.
 
 <P>
 <HR>
-<H2><A NAME="Data_Resampling">Data Resampling
-
-</A></H2>
+<H2><A NAME="Data_Resampling">Data Resampling</A></H2>
+<P>
 One important feature of RRDtool has not been explained yet: It is
 virtually impossible to collect the data and feed it into RRDtool on exact
 intervals. RRDtool therefore interpolates the data so it is on exact
 intervals. If you do not know what this means or how it works, then here's
 the help you seek:
 
-
 <P>
-
 Suppose a counter increases with exactly one for every second. You want to
 measure it in 300 seconds intervals. You should retrieve values that are
 exactly 300 apart. However, due to various circumstances you are a few
@@ -1561,51 +1250,37 @@
 and also the counter increased with 297. Again RRDtool alters the value and
 stores 300 as it should be.
 
-
 <P>
-
-<PRE>      in the RDD                 in real
+<PRE>      in the RDD                 in reality
 </PRE>
-
 <P>
-
 <PRE> time+000:   0 delta=&quot;U&quot;   time+000:    0 delta=&quot;U&quot;
  time+300: 300 delta=300   time+300:  300 delta=300
  time+600: 600 delta=300   time+603:  603 delta=303
  time+900: 900 delta=300   time+900:  900 delta=297
 </PRE>
-
 <P>
-
 Let's create two identical databases. I've chosen the time range 920805000
 to 920805900 as this goes very well with the example numbers.
 
-
 <P>
-
 <PRE>   rrdtool create seconds1.rrd   \
       --start 920804700          \
       DS:seconds:COUNTER:600:U:U \
       RRA:AVERAGE:0.5:1:24
 </PRE>
-
 <P>
-
 <PRE>   for Unix: cp seconds1.rrd seconds2.rrd
    for Dos:  copy seconds1.rrd seconds2.rrd
    for vms:  how would I know :)
 </PRE>
-
 <P>
-
 <PRE>   rrdtool update seconds1.rrd \
       920805000:000 920805300:300 920805600:600 920805900:900
    rrdtool update seconds2.rrd \
       920805000:000 920805300:300 920805603:603 920805900:900
 </PRE>
-
 <P>
-
 <PRE>   rrdtool graph seconds1.gif                       \
       --start 920804700 --end 920806200             \
       --height 200                                  \
@@ -1623,78 +1298,54 @@
       LINE2:seconds#0000FF                          \
       AREA:unknown#FF0000
 </PRE>
-
 <P>
-
 Both graphs should show the same.
 
-
-<P>
-
 <P>
 <HR>
-<H1><A NAME="WRAPUP">WRAPUP
-
-</A></H1>
+<H1><A NAME="WRAPUP">WRAPUP</A></H1>
+<P>
 It's time to wrap up this document. You now know all the basics to be able
 to work with RRDtool and to read the documentation available. There is
 plenty more to discover about RRDtool and you will find more and more uses
-for the program. You could create easy graphics using just the examples
+for the package. You could create easy graphics using just the examples
 provided and using only RRDtool. You could also use the front ends that are
 available.
 
-
-<P>
-
 <P>
 <HR>
-<H1><A NAME="MAILINGLIST">MAILINGLIST
-
-</A></H1>
+<H1><A NAME="MAILINGLIST">MAILINGLIST</A></H1>
+<P>
 Remember to subscribe to the mailing-list. Even if you are not answering
 the mails that come by, it helps both you and the rest. A lot of the stuff
 that I know about MRTG (and therefore about RRDtool) I've learned while
 just reading the list without posting to it. I did not need to ask the
-basic questions as they are answered in the FAQ (so: read that too) and in
-various mails by other users. With thousands of users all over the world,
-there will always be people who ask questions that you can answer because
-you read this and other documentation and they didn't.
-
-
-<P>
+basic questions as they are answered in the FAQ (read it!) and in various
+mails by other users. With thousands of users all over the world, there
+will always be people who ask questions that you can answer because you
+read this and other documentation and they didn't.
 
 <P>
 <HR>
-<H1><A NAME="SEE_ALSO">SEE ALSO
-
-</A></H1>
-The RRDtool manpages
-
-
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
 <P>
+The RRDtool manpages
 
 <P>
 <HR>
-<H1><A NAME="AUTHOR">AUTHOR
-
-</A></H1>
+<H1><A NAME="AUTHOR">AUTHOR</A></H1>
+<P>
 I hope you enjoyed the examples and their descriptions. If you do, help
 other people by pointing them to this document when they are asking basic
 questions. They will not only get their answer but at the same time learn a
 whole lot more.
 
-
 <P>
-
 Alex van den Bogaerdt
-&lt;<A HREF="MAILTO:alex at ergens.op.het.net">alex at ergens.op.het.net</A>&gt;
+&lt;<A HREF="mailto:alex at ergens.op.het.net">alex at ergens.op.het.net</A>&gt;
 
 
 
+</BODY>
 
-<P>
-
-</DL>
-    </BODY>
-
-    </HTML>
+</HTML>

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/rrdlast.html
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/rrdlast.html	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/rrdlast.html	Sat Jul 13 21:08:10 2002
@@ -1,11 +1,10 @@
-    <HTML> 
-	<HEAD> 
-	    <TITLE>last - Return the date of the last data sample in an B<RRD>
+<HTML>
+<HEAD>
+<TITLE>rrdlast</TITLE>
+<LINK REV="made" HREF="mailto:karrer at zinal.ee.ethz.ch">
+</HEAD>
 
-</TITLE> 
-	</HEAD>
-
-	<BODY>
+<BODY>
 
 <!-- INDEX BEGIN -->
 <!--
@@ -21,59 +20,39 @@
 <!-- INDEX END -->
 
 <P>
-<H1><A NAME="NAME">NAME
-
-</A></H1>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
 rrdtool last - Return the date of the last data sample in an <STRONG>RRD</STRONG>
 
 
 
-
-<P>
-
 <P>
 <HR>
-<H1><A NAME="SYNOPSIS">SYNOPSIS
-
-</A></H1>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
 <STRONG>rrdtool</STRONG>  <STRONG>last</STRONG>  <EM>filename</EM>
 
 
 
-
-<P>
-
 <P>
 <HR>
-<H1><A NAME="DESCRIPTION">DESCRIPTION
-
-</A></H1>
-The <STRONG>last</STRONG> function returns the UNIX timestamp when the RRD was last updated.
-
-
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
 <P>
+The <STRONG>last</STRONG> function returns the UNIX timestamp when the RRD was last updated.
 
 <DL>
-<DT><STRONG><A NAME="item_filename">filename
-
-</A></STRONG><DD>
-The name of the <STRONG>RRD</STRONG> that contains the data.
-
-
+<DT><STRONG><A NAME="item_filename">filename</A></STRONG><DD>
 <P>
+The name of the <STRONG>RRD</STRONG> that contains the data.
 
 </DL>
 <P>
 <HR>
-<H1><A NAME="AUTHOR">AUTHOR
-
-</A></H1>
-Russ Wright <A HREF="MAILTO:<rwwright at home.com>"><rwwright at home.com></A>
-
-
+<H1><A NAME="AUTHOR">AUTHOR</A></H1>
 <P>
+Russ Wright &lt;<A
+HREF="mailto:rwwright at home.com">rwwright at home.com</A>&gt;
 
-</DL>
-    </BODY>
+</BODY>
 
-    </HTML>
+</HTML>

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/rrdfetch.txt
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/rrdfetch.txt	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/rrdfetch.txt	Sat Jul 13 21:08:10 2002
@@ -1,239 +1,239 @@
 
 
 
-RRDFETCH(1)                  rrdtool                  RRDFETCH(1)
+rrdtool                                               RRDFETCH(1)
+
 
 
 NNNNAAAAMMMMEEEE
-       rrdtool fetch - fetch data from an rrd.
+     rrdtool fetch - fetch data from an rrd.
 
 SSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS
-       rrrrrrrrddddttttoooooooollll ffffeeeettttcccchhhh _f_i_l_e_n_a_m_e _C_F [--------rrrreeeessssoooolllluuuuttttiiiioooonnnn|----rrrr _r_e_s_o_l_u_t_i_o_n]
-       [--------ssssttttaaaarrrrtttt|----ssss _s_t_a_r_t] [--------eeeennnndddd|----eeee _e_n_d]
+     rrrrrrrrddddttttoooooooollll ffffeeeettttcccchhhh _f_i_l_e_n_a_m_e _C_F [--------rrrreeeessssoooolllluuuuttttiiiioooonnnn|----rrrr _r_e_s_o_l_u_t_i_o_n] [--------
+     ssssttttaaaarrrrtttt|----ssss _s_t_a_r_t] [--------eeeennnndddd|----eeee _e_n_d]
 
 DDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
-       The ffffeeeettttcccchhhh function is normally used internally by the
-       graph function, to get data from RRRRRRRRDDDDs. ffffeeeettttcccchhhh will analyze
-       the RRRRRRRRDDDD and will try to retrieve the data in the
-       resolution requested.  The data fetched is printed to
-       stdout. _*_U_N_K_N_O_W_N_* data is often represented by the string
-       "NaN" depending on your OSs printf function.
+     The ffffeeeettttcccchhhh function is normally used internally by the graph
+     function, to get data from RRRRRRRRDDDDs. ffffeeeettttcccchhhh will analyze the RRRRRRRRDDDD
+     and will try to retrieve the data in the resolution
+     requested.  The data fetched is printed to stdout. *_U_N_K_N_O_W_N*
+     data is often represented by the string "NaN" depending on
+     your OSs printf function.
 
-       _f_i_l_e_n_a_m_e
-               the name of the RRRRRRRRDDDD you want to fetch the data
-               from.
+     _f_i_l_e_n_a_m_e
+             the name of the RRRRRRRRDDDD you want to fetch the data from.
 
-       _C_F      which consolidation function should have been
-               applied to the data you want to fetch?
-               (AVERAGE,MIN,MAX,LAST)
+     _C_F      which consolidation function should have been
+             applied to the data you want to fetch?
+             (AVERAGE,MIN,MAX,LAST)
 
-       --------rrrreeeessssoooolllluuuuttttiiiioooonnnn|----rrrr _r_e_s_o_l_u_t_i_o_n (default is the highest
-               resolution)
-               what interval should the values have (seconds per
-               value). rrrrrrrrddddffffeeeettttcccchhhh will try to match your request,
-               but it will return data even if no absolute match
-               is possible.
+     --------
+             rrrreeeessssoooolllluuuuttttiiiioooonnnn|-rrrr _r_e_s_o_l_u_t_i_o_n (default is the highest resolution)
+             what interval should the values have (seconds per
+             value). rrrrrrrrddddffffeeeettttcccchhhh will try to match your request, but
+             it will return data even if no absolute match is
+             possible.
 
-       --------ssssttttaaaarrrrtttt|----ssss _s_t_a_r_t (default end-1day)
-               when should the data begin. A time in seconds
-               since epoch (1970-01-01) is required. Negative
-               numbers are relative to the current time. By
-               default one day worth of data will be fetched. See
-               also AT-STYLE TIME SPECIFICATION section for a
-               detailed explanation on  ways to specify start
-               time.
+     --------ssssttttaaaarrrrtttt|-ssss _s_t_a_r_t (default end-1day)
+             when should the data begin. A time in seconds since
+             epoch (1970-01-01) is required. Negative numbers are
+             relative to the current time. By default one day
+             worth of data will be fetched. See also AT-STYLE
+             TIME SPECIFICATION section for a detailed
+             explanation on  ways to specify start time.
 
-       --------eeeennnndddd|----eeee _e_n_d (default now)
-               when should the data end. Time in seconds since
-               epoch. See also AT-STYLE TIME SPECIFICATION
-               section for a detailed explanation of how to
-               specify end time.
+     --------eeeennnndddd|-eeee _e_n_d (default now)
+             when should the data end. Time in seconds since
+             epoch. See also AT-STYLE TIME SPECIFICATION section
+             for a detailed explanation of how to specify end
+             time.
 
-       AAAATTTT----SSSSTTTTYYYYLLLLEEEE TTTTIIIIMMMMEEEE SSSSPPPPEEEECCCCIIIIFFFFIIIICCCCAAAATTTTIIIIOOOONNNN
+     AAAATTTT-SSSSTTTTYYYYLLLLEEEE TTTTIIIIMMMMEEEE SSSSPPPPEEEECCCCIIIIFFFFIIIICCCCAAAATTTTIIIIOOOONNNN
 
-       Apart from the traditional _S_e_c_o_n_d_s _s_i_n_c_e _e_p_o_c_h, rrdtool
-       does also understand at-style time specification.  The
-       specification is called "at-style" after Unix command
-       _a_t(1) that has moderately complex ways to specify time to
-       run your job at.  The at-style specification consists of
-       two parts: TTTTIIIIMMMMEEEE RRRREEEEFFFFEEEERRRREEEENNNNCCCCEEEE specification and TTTTIIIIMMMMEEEE OOOOFFFFFFFFSSSSEEEETTTT
-       specification.
+     Apart from the traditional _S_e_c_o_n_d_s _s_i_n_c_e _e_p_o_c_h, rrdtool does
+     also understand at-style time specification.  The
+     specification is called "at-style" after Unix command _a_t(1)
+     that has moderately complex ways to specify time to run your
+     job at.  The at-style specification consists of two parts:
+     TTTTIIIIMMMMEEEE RRRREEEEFFFFEEEERRRREEEENNNNCCCCEEEE specification and TTTTIIIIMMMMEEEE OOOOFFFFFFFFSSSSEEEETTTT specification.
 
 
 
-17/Aug/99                     1.0.7                             1
 
+24/Oct/1999            Last change: 1.0.13                      1
 
 
 
 
-RRDFETCH(1)                  rrdtool                  RRDFETCH(1)
 
 
-       TTTTIIIIMMMMEEEE RRRREEEEFFFFEEEERRRREEEENNNNCCCCEEEE SSSSPPPPEEEECCCCIIIIFFFFIIIICCCCAAAATTTTIIIIOOOONNNN
+rrdtool                                               RRDFETCH(1)
 
-       Time reference specification is used, well,... to
-       establish a reference moment in time (for time offset to
-       be applied to). When present, it should come first, when
-       omitted, it defaults to nnnnoooowwww. On its own part, time
-       reference consists of _t_i_m_e_-_o_f_-_d_a_y reference (which should
-       come first, if present) and _d_a_y reference.
 
-       _T_i_m_e_-_o_f_-_d_a_y can be specified as HHHHHHHH::::MMMMMMMM, HHHHHHHH....MMMMMMMM, or just HHHHHHHH,
-       you can suffix it with aaaammmm or ppppmmmm or use 24-hours clock. The
-       few special times of day are understood as well, these
-       include mmmmiiiiddddnnnniiiigggghhhhtttt (00:00), nnnnoooooooonnnn (12:00) and British tttteeeeaaaattttiiiimmmmeeee
-       (16:00).
 
-       The _d_a_y can be specified as _m_o_n_t_h_-_n_a_m_e _d_a_y_-_o_f_-_t_h_e_-_m_o_n_t_h
-       and optional 2- or 4-digit _y_e_a_r number (e.g. March 8
-       1999).  Alternatively, you can use _d_a_y_-_o_f_-_w_e_e_k_-_n_a_m_e (e.g.
-       Monday), or one of the words: yyyyeeeesssstttteeeerrrrddddaaaayyyy, ttttooooddddaaaayyyy, ttttoooommmmoooorrrrrrrroooowwww.
-       You can also specify _d_a_y as a full date in several
-       numerical formats; these include: MMMMMMMM////DDDDDDDD////[[[[YYYYYYYY]]]]YYYYYYYY,
-       DDDDDDDD....MMMMMMMM....[[[[YYYYYYYY]]]]YYYYYYYY, YYYYYYYYYYYYYYYYMMMMMMMMDDDDDDDD (_N_O_T_E_1: this is different from the
-       original _a_t(1) behavior, which interprets a single-number
-       date as MMDD[YY]YY) _N_O_T_E_2: if you specify _d_a_y this way,
-       the _t_i_m_e_-_o_f_-_d_a_y is REQUIRED to be present.
+     TTTTIIIIMMMMEEEE RRRREEEEFFFFEEEERRRREEEENNNNCCCCEEEE SSSSPPPPEEEECCCCIIIIFFFFIIIICCCCAAAATTTTIIIIOOOONNNN
 
-       Finally, you can use words nnnnoooowwww, ssssttttaaaarrrrtttt, or eeeennnndddd as your time
-       reference. NNNNoooowwww refers to the current moment (and is also a
-       default time reference). SSSSttttaaaarrrrtttt (eeeennnndddd) can be used to
-       specify time relative to the start (end) time for those
-       tools that use these categories (rrdfetch, rrdgraph).
+     Time reference specification is used, well,... to establish
+     a reference moment in time (for time offset to be applied
+     to). When present, it should come first, when omitted, it
+     defaults to nnnnoooowwww. On its own part, time reference consists of
+     _t_i_m_e-_o_f-_d_a_y reference (which should come first, if present)
+     and _d_a_y reference.
 
-       Month and weekday names can be used in their naturally
-       abbreviated form (e.g., Dec for December, Sun for Sunday,
-       etc.). The words nnnnoooowwww, ssssttttaaaarrrrtttt, eeeennnndddd can be abbreviated to nnnn,
-       ssss, eeee.
+     _T_i_m_e-_o_f-_d_a_y can be specified as HHHHHHHH::::MMMMMMMM, HHHHHHHH....MMMMMMMM, or just HHHHHHHH,
+     you can suffix it with aaaammmm or ppppmmmm or use 24-hours clock. The
+     few special times of day are understood as well, these
+     include mmmmiiiiddddnnnniiiigggghhhhtttt (00:00), nnnnoooooooonnnn (12:00) and British tttteeeeaaaattttiiiimmmmeeee
+     (16:00).
 
-       TTTTIIIIMMMMEEEE OOOOFFFFFFFFSSSSEEEETTTT SSSSPPPPEEEECCCCIIIIFFFFIIIICCCCAAAATTTTIIIIOOOONNNN
+     The _d_a_y can be specified as _m_o_n_t_h-_n_a_m_e _d_a_y-_o_f-_t_h_e-_m_o_n_t_h and
+     optional 2- or 4-digit _y_e_a_r number (e.g. March 8 1999).
+     Alternatively, you can use _d_a_y-_o_f-_w_e_e_k-_n_a_m_e (e.g. Monday),
+     or one of the words: yyyyeeeesssstttteeeerrrrddddaaaayyyy, ttttooooddddaaaayyyy, ttttoooommmmoooorrrrrrrroooowwww.  You can
+     also specify _d_a_y as a full date in several numerical
+     formats; these include: MMMMMMMM////DDDDDDDD////[[[[YYYYYYYY]]]]YYYYYYYY, DDDDDDDD....MMMMMMMM....[[[[YYYYYYYY]]]]YYYYYYYY, YYYYYYYYYYYYYYYYMMMMMMMMDDDDDDDD
+     (_N_O_T_E_1: this is different from the original _a_t(1) behavior,
+     which interprets a single-number date as MMDD[YY]YY) _N_O_T_E_2:
+     if you specify _d_a_y this way, the _t_i_m_e-_o_f-_d_a_y is REQUIRED to
+     be present.
 
-       Time offset specification is used to add (or subtract)
-       certain time interval to (from) the time reference moment.
-       It consists of _s_i_g_n (++++ or ----) and _a_m_o_u_n_t. The following
-       time units can be used to specify the _a_m_o_u_n_t: yyyyeeeeaaaarrrrssss,
-       mmmmoooonnnntttthhhhssss, wwwweeeeeeeekkkkssss, ddddaaaayyyyssss, hhhhoooouuuurrrrssss, mmmmiiiinnnnuuuutttteeeessss, sssseeeeccccoooonnnnddddssss, these can be
-       used in singular or plural form, and abbreviated naturally
-       or to a single letter (e.g. +3days, -1wk, -3y). Several
-       time units can be combined together (e.g., -5mon1w2d), as
-       well as several time offsets can be concatenated (e.g.,
-       -5h45min = -5h-45min = -6h+15min = -7h+1h30m-15min, etc.)
+     Finally, you can use words nnnnoooowwww, ssssttttaaaarrrrtttt, or eeeennnndddd as your time
+     reference. NNNNoooowwww refers to the current moment (and is also a
+     default time reference). SSSSttttaaaarrrrtttt (eeeennnndddd) can be used to specify
+     time relative to the start (end) time for those tools that
+     use these categories (rrdfetch, rrdgraph).
 
-       _N_O_T_E_3: If you specify time offset in days, weeks, months,
-       or years, you will end with the time offset that may vary
-       depending on you time reference, because all those time
-       units have no single well defined time interval value
+     Month and weekday names can be used in their naturally
+     abbreviated form (e.g., Dec for December, Sun for Sunday,
+     etc.). The words nnnnoooowwww, ssssttttaaaarrrrtttt, eeeennnndddd can be abbreviated to nnnn, ssss,
+     eeee.
 
+     TTTTIIIIMMMMEEEE OOOOFFFFFFFFSSSSEEEETTTT SSSSPPPPEEEECCCCIIIIFFFFIIIICCCCAAAATTTTIIIIOOOONNNN
 
+     Time offset specification is used to add (or subtract)
+     certain time interval to (from) the time reference moment.
+     It consists of _s_i_g_n (++++ or ----) and _a_m_o_u_n_t. The following time
+     units can be used to specify the _a_m_o_u_n_t: yyyyeeeeaaaarrrrssss, mmmmoooonnnntttthhhhssss,
+     wwwweeeeeeeekkkkssss, ddddaaaayyyyssss, hhhhoooouuuurrrrssss, mmmmiiiinnnnuuuutttteeeessss, sssseeeeccccoooonnnnddddssss, these can be used in
+     singular or plural form, and abbreviated naturally or to a
+     single letter (e.g. +3days, -1wk, -3y). Several time units
+     can be combined together (e.g., -5mon1w2d), as well as
+     several time offsets can be concatenated (e.g., -5h45min =
+     -5h-45min = -6h+15min = -7h+1h30m-15min, etc.)
 
-17/Aug/99                     1.0.7                             2
+     _N_O_T_E_3: If you specify time offset in days, weeks, months, or
+     years, you will end with the time offset that may vary
 
 
 
+24/Oct/1999            Last change: 1.0.13                      2
 
 
-RRDFETCH(1)                  rrdtool                  RRDFETCH(1)
 
 
-       (1 year contains either 365 or 366 days, 1 month is 28 to
-       31 days long, and even 1 day may be not equal to 24 hours
-       twice a year, when DST-related clock adjustments take
-       place).  To cope with this, when you use days, weeks,
-       months, or years as your time offset units your time
-       reference date is adjusted accordingly without taking too
-       much further effort to ensure anything about it (in the
-       hope that _m_k_t_i_m_e(3) will take care of this later).  This
-       may lead to some surprising (or even invalid!) results,
-       e.g. 'May 31 -1month' = 'Apr 31' (meaningless) = 'May 1'
-       (after _m_k_t_i_m_e(3) normalization); in the EET timezone
-       '3:30am Mar 29 1999 -1 day' yields '3:30am Mar 28 1999'
-       (Sunday) which is invalid time/date combination (because
-       of 3am -> 4am DST forward clock adjustment, see the below
-       example).  On the other hand, hours, minutes, and seconds
-       are well defined time intervals, and these are guaranteed
-       to always produce time offsets exactly as specified (e.g.
-       for EET timezone, '8:00 Mar 27 1999 +2 days' =
-       '8:00 Mar 29 1999', but since there is 1-hour DST forward
-       clock adjustment takes place around 3:00 Mar 28 1999, the
-       actual time interval between 8:00 Mar 27 1999 and
-       8:00 Mar 29 1999 equals 47 hours; on the other hand,
-       '8:00 Mar 27 1999 +48 hours' = '9:00 Mar 29 1999', as
-       expected)
 
-       _N_O_T_E_4: The single-letter abbreviation for both mmmmoooonnnntttthhhhssss and
-       mmmmiiiinnnnuuuutttteeeessss is mmmm. To disambiguate, the parser tries to read
-       your mind :) by applying the following two heuristics:
 
-       1  If mmmm is used in context of (i.e. right after the)
-          years, months, weeks, or days it is assumed to mean
-          mmmmoooonnnntttthhhhssss, while in the context of hours, minutes, and
-          seconds it means minutes.  (e.g., in -1y6m or +3w1m mmmm
-          means mmmmoooonnnntttthhhhssss, while in -3h20m or +5s2m mmmm means mmmmiiiinnnnuuuutttteeeessss)
+rrdtool                                               RRDFETCH(1)
 
-       2  Out of context (i.e. right after the ++++ or ---- sign) the
-          meaning of mmmm is guessed from the number it directly
-          follows.  Currently, if the number absolute value is
-          below 25 it is assumed that mmmm means mmmmoooonnnntttthhhhssss, otherwise
-          it is treated as mmmmiiiinnnnuuuutttteeeessss.  (e.g., -25m == -25 minutes,
-          while +24m == +24 months)
 
-       _F_i_n_a_l _N_O_T_E_S: Time specification is case-insensitive.
-       Whitespace can be inserted freely or omitted altogether,
-       there are, however, cases when whitespace is required
-       (e.g., 'midnight Thu'). In this case you should either
-       quote the whole phrase to prevent it from being taken
-       apart by your shell or use '_' (underscore) or ',' (comma)
-       which also count as whitespace (e.g., midnight_Thu or
-       midnight,Thu)
 
+     depending on you time reference, because all those time
+     units have no single well defined time interval value
+     (1 year contains either 365 or 366 days, 1 month is 28 to 31
+     days long, and even 1 day may be not equal to 24 hours twice
+     a year, when DST-related clock adjustments take place).  To
+     cope with this, when you use days, weeks, months, or years
+     as your time offset units your time reference date is
+     adjusted accordingly without taking too much further effort
+     to ensure anything about it (in the hope that _m_k_t_i_m_e(3) will
+     take care of this later).  This may lead to some surprising
+     (or even invalid!) results, e.g. 'May 31 -1month' = 'Apr 31'
+     (meaningless) = 'May 1' (after _m_k_t_i_m_e(3) normalization); in
+     the EET timezone '3:30am Mar 29 1999 -1 day' yields '3:30am
+     Mar 28 1999' (Sunday) which is invalid time/date combination
+     (because of 3am -> 4am DST forward clock adjustment, see the
+     below example).  On the other hand, hours, minutes, and
+     seconds are well defined time intervals, and these are
+     guaranteed to always produce time offsets exactly as
+     specified (e.g. for EET timezone, '8:00 Mar 27 1999 +2 days'
+     = '8:00 Mar 29 1999', but since there is 1-hour DST forward
+     clock adjustment takes place around 3:00 Mar 28 1999, the
+     actual time interval between 8:00 Mar 27 1999 and
+     8:00 Mar 29 1999 equals 47 hours; on the other hand,
+     '8:00 Mar 27 1999 +48 hours' = '9:00 Mar 29 1999', as
+     expected)
 
+     _N_O_T_E_4: The single-letter abbreviation for both mmmmoooonnnntttthhhhssss and
+     mmmmiiiinnnnuuuutttteeeessss is mmmm. To disambiguate, the parser tries to read your
+     mind :)  by applying the following two heuristics:
 
+     1  If mmmm is used in context of (i.e. right after the) years,
+        months, weeks, or days it is assumed to mean mmmmoooonnnntttthhhhssss,
+        while in the context of hours, minutes, and seconds it
+        means minutes.  (e.g., in -1y6m or +3w1m mmmm means mmmmoooonnnntttthhhhssss,
+        while in -3h20m or +5s2m mmmm means mmmmiiiinnnnuuuutttteeeessss)
 
+     2  Out of context (i.e. right after the ++++ or ---- sign) the
+        meaning of mmmm is guessed from the number it directly
+        follows.  Currently, if the number absolute value is
+        below 25 it is assumed that mmmm means mmmmoooonnnntttthhhhssss, otherwise it
+        is treated as mmmmiiiinnnnuuuutttteeeessss.  (e.g., -25m == -25 minutes, while
+        +24m == +24 months)
 
+     _F_i_n_a_l _N_O_T_E_S: Time specification is case-insensitive.
+     Whitespace can be inserted freely or omitted altogether,
+     there are, however, cases when whitespace is required (e.g.,
+     'midnight Thu'). In this case you should either quote the
+     whole phrase to prevent it from being taken apart by your
+     shell or use '_' (underscore) or ',' (comma) which also
+     count as whitespace (e.g., midnight_Thu or midnight,Thu)
 
 
-17/Aug/99                     1.0.7                             3
 
 
 
+24/Oct/1999            Last change: 1.0.13                      3
 
 
-RRDFETCH(1)                  rrdtool                  RRDFETCH(1)
 
 
-       TTTTIIIIMMMMEEEE SSSSPPPPEEEECCCCIIIIFFFFIIIICCCCAAAATTTTIIIIOOOONNNN EEEEXXXXAAAAMMMMPPPPLLLLEEEESSSS
 
-       _O_c_t _1_2 -- October 12 this year
 
-       _-_1_m_o_n_t_h or _-_1_m -- current time of day, only a month before
-       (may yield surprises, see the NOTE3 above)
+rrdtool                                               RRDFETCH(1)
 
-       _n_o_o_n _y_e_s_t_e_r_d_a_y _-_3_h_o_u_r_s -- yesterday morning; can be put
-       also as _9_a_m_-_1_d_a_y
 
-       _2_3_:_5_9 _3_1_._1_2_._1_9_9_9 -- 1 minute to the year 2000
 
-       _1_2_/_3_1_/_9_9 _1_1_:_5_9_p_m -- 1 minute to the year 2000 for
-       imperialists
+     TTTTIIIIMMMMEEEE SSSSPPPPEEEECCCCIIIIFFFFIIIICCCCAAAATTTTIIIIOOOONNNN EEEEXXXXAAAAMMMMPPPPLLLLEEEESSSS
 
-       _1_2_a_m _0_1_/_0_1_/_0_1 -- start of the new millennium
+     _O_c_t _1_2 -- October 12 this year
 
-       _e_n_d_-_3_w_e_e_k_s or _e_-_3_w -- 3 weeks before end time (may be used
-       as start time specification)
+     -_1_m_o_n_t_h or -_1_m -- current time of day, only a month before
+     (may yield surprises, see the NOTE3 above)
 
-       _s_t_a_r_t_+_6_h_o_u_r_s or _s_+_6_h -- 6 hours after start time (may be
-       used as end time specification)
+     _n_o_o_n _y_e_s_t_e_r_d_a_y -_3_h_o_u_r_s -- yesterday morning; can be put also
+     as _9_a_m-_1_d_a_y
 
-       _9_3_1_2_2_5_5_3_7 -- 18:45  July 5th, 1999 (yes, seconds since
-       1970 are valid as well)
+     _2_3:_5_9 _3_1._1_2._1_9_9_9 -- 1 minute to the year 2000
 
-       _1_9_9_7_0_7_0_3 _1_2_:_4_5 -- 12:45  July 3th, 1997 (not quote
-       standard, but I love this ...)
+     _1_2/_3_1/_9_9 _1_1:_5_9_p_m -- 1 minute to the year 2000 for
+     imperialists
 
-AAAAUUUUTTTTHHHHOOOORRRR
-       Tobias Oetiker <oetiker at ee.ethz.ch>
+     _1_2_a_m _0_1/_0_1/_0_1 -- start of the new millennium
+
+     _e_n_d-_3_w_e_e_k_s or _e-_3_w -- 3 weeks before end time (may be used
+     as start time specification)
+
+     _s_t_a_r_t+_6_h_o_u_r_s or _s+_6_h -- 6 hours after start time (may be
+     used as end time specification)
 
+     _9_3_1_2_2_5_5_3_7 -- 18:45  July 5th, 1999 (yes, seconds since 1970
+     are valid as well)
+
+     _1_9_9_7_0_7_0_3 _1_2:_4_5 -- 12:45  July 3th, 1997 (not quote standard,
+     but I love this ...)
+
+AAAAUUUUTTTTHHHHOOOORRRR
+     Tobias Oetiker <oetiker at ee.ethz.ch>
 
 
 
@@ -258,7 +258,7 @@
 
 
 
+24/Oct/1999            Last change: 1.0.13                      4
 
-17/Aug/99                     1.0.7                             4
 
 

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/rrddump.html
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/rrddump.html	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/rrddump.html	Sat Jul 13 21:08:10 2002
@@ -1,11 +1,10 @@
-    <HTML> 
-	<HEAD> 
-	    <TITLE>dump - dump the contents of an B<RRD> to XML format
+<HTML>
+<HEAD>
+<TITLE>rrddump</TITLE>
+<LINK REV="made" HREF="mailto:karrer at zinal.ee.ethz.ch">
+</HEAD>
 
-</TITLE> 
-	</HEAD>
-
-	<BODY>
+<BODY>
 
 <!-- INDEX BEGIN -->
 <!--
@@ -21,61 +20,40 @@
 <!-- INDEX END -->
 
 <P>
-<H1><A NAME="NAME">NAME
-
-</A></H1>
-rrdtool dump - dump the contents of an <STRONG>RRD</STRONG> to XML format
-
-
+<H1><A NAME="NAME">NAME</A></H1>
 <P>
+rrdtool dump - dump the contents of an <STRONG>RRD</STRONG> to XML format
 
 <P>
 <HR>
-<H1><A NAME="SYNOPSIS">SYNOPSIS
-
-</A></H1>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
 <STRONG>rrdtool</STRONG>  <STRONG>dump</STRONG>  <EM>filename.rrd</EM>  &gt;  <EM>filename.xml</EM> 
 
  
 
-
-<P>
-
 <P>
 <HR>
-<H1><A NAME="DESCRIPTION">DESCRIPTION
-
-</A></H1>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
 The <STRONG>dump</STRONG> function prints the contents of an <STRONG>RRD</STRONG> in human readable (?) XML format. This format can be read by rrdrestore.
 Together they allow you to transfer your files from one architecture to
 another as well as manipulating the contents of an <STRONG>RRD</STRONG> file in a somewhat more convenient manner.
 
-
-<P>
-
 <DL>
-<DT><STRONG><A NAME="item_filename">filename.rrd
-
-</A></STRONG><DD>
-The name of the <STRONG>RRD</STRONG> you want to dump.
-
-
+<DT><STRONG><A NAME="item_filename">filename.rrd</A></STRONG><DD>
 <P>
+The name of the <STRONG>RRD</STRONG> you want to dump.
 
 </DL>
 <P>
 <HR>
-<H1><A NAME="AUTHOR">AUTHOR
-
-</A></H1>
-Tobias Oetiker &lt;<A HREF="MAILTO:oetiker at ee.ethz.ch">oetiker at ee.ethz.ch</A>&gt;
-
-
+<H1><A NAME="AUTHOR">AUTHOR</A></H1>
+<P>
+Tobias Oetiker &lt;<A HREF="mailto:oetiker at ee.ethz.ch">oetiker at ee.ethz.ch</A>&gt;
 
 
-<P>
 
-</DL>
-    </BODY>
+</BODY>
 
-    </HTML>
+</HTML>

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/RRDp.txt
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/RRDp.txt	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/RRDp.txt	Sat Jul 13 21:08:11 2002
@@ -1,107 +1,107 @@
 
 
 
-RRDp(3pm)                    rrdtool                    RRDp(3pm)
+rrdtool                                                   RRDp(3)
+
 
 
 NNNNAAAAMMMMEEEE
-       RRDp - Attach rrdtool from within a perl script via a set
-       of pipes;
+     RRDp - Attach rrdtool from within a perl script via a set of
+     pipes;
 
 SSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS
-       use RRRRRRRRDDDDpppp
+     use RRRRRRRRDDDDpppp
 
-       RRRRRRRRDDDDpppp::::::::ssssttttaaaarrrrtttt _p_a_t_h _t_o _r_r_d_t_o_o_l _e_x_e_c_u_t_a_b_l_e
+     RRRRRRRRDDDDpppp::::::::ssssttttaaaarrrrtttt _p_a_t_h _t_o _r_r_d_t_o_o_l _e_x_e_c_u_t_a_b_l_e
 
-       RRRRRRRRDDDDpppp::::::::ccccmmmmdddd  _r_r_d_t_o_o_l _c_o_m_m_a_n_d_l_i_n_e
+     RRRRRRRRDDDDpppp::::::::ccccmmmmdddd  _r_r_d_t_o_o_l _c_o_m_m_a_n_d_l_i_n_e
 
-       $answer = RRRRRRRRDDDD::::::::rrrreeeeaaaadddd
+     $answer = RRRRRRRRDDDD::::::::rrrreeeeaaaadddd
 
-       $status = RRRRRRRRDDDD::::::::eeeennnndddd
+     $status = RRRRRRRRDDDD::::::::eeeennnndddd
 
-       $$$$RRRRRRRRDDDDpppp::::::::uuuusssseeeerrrr,  $$$$RRRRRRRRDDDDpppp::::::::ssssyyyyssss, $$$$RRRRRRRRDDDDpppp::::::::rrrreeeeaaaallll
+     $$$$RRRRRRRRDDDDpppp::::::::uuuusssseeeerrrr,  $$$$RRRRRRRRDDDDpppp::::::::ssssyyyyssss, $$$$RRRRRRRRDDDDpppp::::::::rrrreeeeaaaallll
 
 DDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
-       With this module you can safely communicate with the
-       rrdtool.
+     With this module you can safely communicate with the
+     rrdtool.
+
+     After every RRRRRRRRDDDDpppp::::::::ccccmmmmdddd you have to issue an RRRRRRRRDDDDpppp::::::::rrrreeeeaaaadddd
+     command to get rrrrrrrrddddttttoooooooolllls 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, RRRRRRRRDDDDpppp::::::::rrrreeeeaaaadddd will
+     return an undefined variable.
+
+     If you import the PERFORMANCE variables into your namespace,
+     you can access rrdtools internal performance measurements.
 
-       After every RRRRRRRRDDDDpppp::::::::ccccmmmmdddd you have to issue an RRRRRRRRDDDDpppp::::::::rrrreeeeaaaadddd
-       command to get rrrrrrrrddddttttoooooooolllls 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, RRRRRRRRDDDDpppp::::::::rrrreeeeaaaadddd will
-       return an undefined variable.
+     use RRRRRRRRDDDDpppp
+             Load the RRDp::pipe module.
 
-       If you import the PERFORMANCE variables into your
-       namespace, you can access rrdtools internal performance
-       measurements.
+     RRRRRRRRDDDDpppp::::::::ssssttttaaaarrrrtttt _p_a_t_h _t_o _r_r_d_t_o_o_l _e_x_e_c_u_t_a_b_l_e
+             start rrdtool. The argument must be the path to the
+             rrdtool executable
 
-       use RRRRRRRRDDDDpppp
-               Load the RRDp::pipe module.
+     RRRRRRRRDDDDpppp::::::::ccccmmmmdddd _r_r_d_t_o_o_l _c_o_m_m_a_n_d_l_i_n_e
+             pass commands on to rrdtool. check the rrdtool
+             documentation for more info on the rrdtool commands.
 
-       RRRRRRRRDDDDpppp::::::::ssssttttaaaarrrrtttt _p_a_t_h _t_o _r_r_d_t_o_o_l _e_x_e_c_u_t_a_b_l_e
-               start rrdtool. The argument must be the path to
-               the rrdtool executable
+     $answer = RRRRRRRRDDDDpppp::::::::rrrreeeeaaaadddd
+             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.
 
-       RRRRRRRRDDDDpppp::::::::ccccmmmmdddd _r_r_d_t_o_o_l _c_o_m_m_a_n_d_l_i_n_e
-               pass commands on to rrdtool. check the rrdtool
-               documentation for more info on the rrdtool
-               commands.
 
-       $answer = RRRRRRRRDDDDpppp::::::::rrrreeeeaaaadddd
-               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.
 
 
 
+13/Feb/2000            Last change: 1.0.13                      1
 
 
-27/Aug/99                     1.0.7                             1
 
 
 
 
+rrdtool                                                   RRDp(3)
 
-RRDp(3pm)                    rrdtool                    RRDp(3pm)
 
 
-       $status = RRRRRRRRDDDDpppp::::::::eeeennnndddd
-               terminates rrdtool and returns rrdtools status ...
+     $status = RRRRRRRRDDDDpppp::::::::eeeennnndddd
+             terminates rrdtool and returns rrdtools status ...
 
-       $$$$RRRRRRRRDDDDpppp::::::::uuuusssseeeerrrr,  $$$$RRRRRRRRDDDDpppp::::::::ssssyyyyssss, $$$$RRRRRRRRDDDDpppp::::::::rrrreeeeaaaallll
-               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.
+     $$$$RRRRRRRRDDDDpppp::::::::uuuusssseeeerrrr,  $$$$RRRRRRRRDDDDpppp::::::::ssssyyyyssss, $$$$RRRRRRRRDDDDpppp::::::::rrrreeeeaaaallll
+             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.
+             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.
 
 EEEEXXXXAAAAMMMMPPPPLLLLEEEE
-        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);
+      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);
 
 
 SSSSEEEEEEEE AAAALLLLSSSSOOOO
-       For more information on how to use rrdtool, check the
-       manpages.
+     For more information on how to use rrdtool, check the
+     manpages.
 
 AAAAUUUUTTTTHHHHOOOORRRR
-       Tobias Oetiker <oetiker at ee.ethz.ch>
+     Tobias Oetiker <oetiker at ee.ethz.ch>
 
 
 
@@ -126,7 +126,7 @@
 
 
 
+13/Feb/2000            Last change: 1.0.13                      2
 
-27/Aug/99                     1.0.7                             2
 
 

Added: trunk/orca/packages/rrdtool-1.0.13/doc/rpntutorial.html
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/rpntutorial.html	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/rpntutorial.html	Sat Jul 13 21:08:11 2002
@@ -0,0 +1,271 @@
+<HTML>
+<HEAD>
+<TITLE>rpntutorial</TITLE>
+<LINK REV="made" HREF="mailto:karrer at zinal.ee.ethz.ch">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+<!--
+
+<UL>
+
+	<LI><A HREF="#NAME">NAME</A>
+	<LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+	<LI><A HREF="#Reading_Comparison_Operators">Reading Comparison Operators</A>
+	<LI><A HREF="#Reading_the_IF_Operator">Reading the IF Operator</A>
+	<LI><A HREF="#Some_Examples">Some Examples</A>
+	<LI><A HREF="#Exercises">Exercises</A>
+	<LI><A HREF="#AUTHOR">AUTHOR</A>
+</UL>
+-->
+<!-- INDEX END -->
+
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+rpntutorial - Reading RRDTtool RPN Expressions by Steve Rader
+
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+This tutorial should help you get to grips with rrdtool RPN expressions as
+seen in CDEF arguments of rrdtool graph.
+
+<P>
+<HR>
+<H1><A NAME="Reading_Comparison_Operators">Reading Comparison Operators</A></H1>
+<P>
+The LT, LE, GT, GE and EQ RPN logic operators are not as tricky as they
+appear. These operators act on the two values on the stack preceding them
+(to the left). Read these two values on the stack from left to right
+inserting the operator in the middle. If the resulting statement is true,
+the replace the three values from the stack with ``1''. If the statement if
+false, replace the three values with ``0''.
+
+<P>
+For example think about ``2,1,GT''. This RPN expression could be read as
+``is two greater than one?'' The answer to that question is ``true''. So
+the three values should be replaced with ``1''. Thus the RPN expression
+2,1,GT evaluates to 1.
+
+<P>
+Now also consider ``2,1,LE''. This RPN expression could be read as ``is two
+less than or equal to one?''. The natural response is ``no'' and thus the
+RPN expression 2,1,LE evaluates to 0. 
+
+<P>
+<HR>
+<H1><A NAME="Reading_the_IF_Operator">Reading the IF Operator</A></H1>
+<P>
+The IF RPN logic operator can be straightforward also. The key to reading
+IF operators is to understand that the condition part of the traditional
+``if X than Y else Z'' notation has *already* been evaluated. So the IF
+operator acts on only one value on the stack: the third value to the left
+of the IF value. The second value to the left of the IF corresponds to the
+true (``Y'') branch. And the first value to the left of the IF corresponds
+to the false (``Z'') branch. Read the RPN expression ``X,Y,Z,IF'' from left
+to right like so: ``if X then Y else Z''.
+
+<P>
+For example, consider ``1,10,100,IF''. It looks bizzare to me. But when I
+read ``if 1 then 10 else 100'' it's crystal clear: 1 is true so the answer
+is 10. Note that only zero is false; all other values are true.
+``2,20,200,IF'' (``if 2 then 20 else 200'') evaluates to 20. And
+``0,1,2,IF'' (``if 0 then 1 else 2) evaluates to 2.
+
+<P>
+Notice that none of the above examples really simulate the whole ``if X
+then Y else Z'' statement. This is because computer programmers read this
+statement as ``if Some Condition then Y else Z''. So it's important to be
+able to read IF operators along with the LT, LE, GT, GE and EQ operators.
+
+<P>
+<HR>
+<H1><A NAME="Some_Examples">Some Examples</A></H1>
+<P>
+While compound expressions can look overly complex, they can be considered
+elegantly simple. To quickly comprehend RPN expressions, you must know the
+the algorithm for evaluating RPN expressions: iterate searches from the
+left to the right looking for an operator, when it's found, apply that
+operator by popping the operator and some number of values (and by
+definition, not operators) off the stack.
+
+<P>
+For example, the stack ``1,2,3,+,+'' gets ``2,3,+'' evaluated (as ``2+3'')
+during the first iteration which is replaced by 5. This results in the
+stack ``1,5,+''. Finally, ``1,5,+'' is evaluated resulting in the answer 6.
+For convenience sake, it's useful to write this set of operations as:
+
+<P>
+<PRE> 1) 1,2,3,+,+    eval is 2,3,+ = 5    result is 1,5,+
+ 2) 1,5,+        eval is 1,5,+ = 6    result is 6
+ 3) 6
+</PRE>
+<P>
+Let's use that notation to conviently solve some complex RPN expressions
+with multiple logic operators:
+
+<P>
+<PRE> 1) 20,10,GT,10,20,IF  eval is 20,10,GT = 1     result is 1,10,20,IF
+</PRE>
+<P>
+read the eval as pop ``20 is greater than 10'' so push 1 2) 1,10,20,IF eval
+is 1,10,20,IF = 10 result is 10
+
+<P>
+read pop ``if 1 then 10 else 20'' so push 10. Only 10 is left so 10 is the
+answer.
+
+<P>
+Let's read a complex RPN expression that also has the traditional
+multiplication operator:
+
+<P>
+<PRE> 1) 128,8,*,7000,GT,7000,128,8,*,IF  eval 128,8,*       result is 1024
+ 2) 1024,7000,GT,7000,128,8,*,IF     eval 1024,7000,GT  result is 0
+ 3) 0,128,8,*,IF                     eval 128,8,*       result is 1024
+ 4) 0,7000,1024,IF                                      result is 1024
+</PRE>
+<P>
+Now let's go back to the first example of multiple logic operators but
+replace the value 20 with the variable ``input'':
+
+<P>
+<PRE> 1) input,10,GT,10,input,IF  eval is input,10,GT  result is A
+</PRE>
+<P>
+Read eval as ``if input &gt; 10 then true'' and replace ``input,10,GT''
+with ``A: 2) A,10,input,IF eval is A,10,input,IF
+
+<P>
+read ``if A then 10 else input''. Now replace A it's verbose description
+and--voila!--you have a easily readable description of the expression:
+
+<P>
+<PRE> if input &gt; 10 then 10 else input
+</PRE>
+<P>
+Lastly, let's to back the first most complex example and replace the value
+128 with ``input'':
+
+<P>
+<PRE> 1) input,8,*,7000,GT,7000,input,8,*,IF  eval input,8,*     result is A
+</PRE>
+<P>
+where A is ``input * 8''
+
+<P>
+<PRE> 2) A,7000,GT,7000,input,8,*,IF          eval is A,7000,GT  result is B
+</PRE>
+<P>
+where B is ``if ((input * 8) &gt; 7000) then true''
+
+<P>
+<PRE> 3) B,7000,input,8,*,IF                  eval is input,8,*  result is C
+</PRE>
+<P>
+where C is ``input * 8''
+
+<P>
+<PRE> 4) B,7000,C,IF
+</PRE>
+<P>
+At last we have a readable decoding of the complex RPN expression with a
+variable:
+
+<P>
+<PRE> if ((input * 8) &gt; 7000) then 7000 else (input * 8)
+</PRE>
+<P>
+<HR>
+<H1><A NAME="Exercises">Exercises</A></H1>
+<P>
+Exercise 1:
+
+<P>
+Compute ``3,2,*,1,+ and ''3,2,1,+,*`` by hand. Rewrite them in traditional
+notation. Explain why they have different answers.
+
+<P>
+Answer 1:
+
+<P>
+<PRE>    3*2+1 = 7 and 3*(2+1) = 9.  These expressions have
+    different answers because the altering of the plus and 
+    times operators alter the order of their evaluation.
+</PRE>
+<P>
+Exercise 2:
+
+<P>
+One may be tempted to shorten the expression
+
+<P>
+<PRE> input,8,*,56000,GT,56000,input,*,8,IF
+</PRE>
+<P>
+by removing the redundant use of ``input,8,*'' like so:
+
+<P>
+<PRE> input,56000,GT,56000,input,IF,8,*
+</PRE>
+<P>
+Use tradition notation to show these expressions are not the same. Write an
+expression that's equivalent to the first expression but uses the LE and
+DIV operators.
+
+<P>
+Answer 2:
+
+<P>
+<PRE>    if (input &lt;= 56000/8 ) { input*8 } else { 56000 }
+    input,56000,8,DIV,LT,input,8,*,56000,IF
+</PRE>
+<P>
+Exercise 3:
+
+<P>
+Briefly explain why traditional mathematic notation requires the use of
+parentheses. Explain why RPN notation does not require the use of
+parentheses.
+
+<P>
+Answer 3:
+
+<P>
+<PRE>    Traditional mathematic expressions are evaluated by
+    doing multiplication and division first, then addition and
+    subtraction.  Perentences are used to force the evaluation of
+    addition before multiplication (etc).  RPN does not require
+    parentheses because the ordering of objects on the stack
+    can force the evaluation of addition before multiplication.
+</PRE>
+<P>
+Exercise 4:
+
+<P>
+Explain why it is desirable for the RRDtool developers to implement RPN
+notation instead of traditional mathematical notation.
+
+<P>
+Answer 4:
+
+<P>
+<PRE>    The algorithm that implements traditional mathematical
+    notation is more complex then algorithm used for RPN.
+    So implementing RPN allowed Tobias Oetiker to write less
+    code!  (The code is also less complex and therefore less
+    likely to have bugs.)
+</PRE>
+<P>
+<HR>
+<H1><A NAME="AUTHOR">AUTHOR</A></H1>
+<P>
+steve rader &lt;<A HREF="mailto:rader at wiscnet.net">rader at wiscnet.net</A>&gt;
+
+</BODY>
+
+</HTML>

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/rrdgraph.txt
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/rrdgraph.txt	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/rrdgraph.txt	Sat Jul 13 21:08:11 2002
@@ -1,652 +1,652 @@
 
 
 
-RRDGRAPH(1)                  rrdtool                  RRDGRAPH(1)
+rrdtool                                               RRDGRAPH(1)
+
 
 
 NNNNAAAAMMMMEEEE
-       rrdtool graph - Create a graph based on data from one or
-       several RRD
+     rrdtool graph - Create a graph based on data from one or
+     several RRD
 
 SSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS
-       rrrrrrrrddddttttoooooooollll ggggrrrraaaapppphhhh _f_i_l_e_n_a_m_e [----ssss|--------ssssttttaaaarrrrtttt _s_e_c_o_n_d_s]
-       [----eeee|--------eeeennnndddd _s_e_c_o_n_d_s] [----xxxx|--------xxxx----ggggrrrriiiidddd _x_-_a_x_i_s _g_r_i_d _a_n_d _l_a_b_e_l]
-       [----yyyy|--------yyyy----ggggrrrriiiidddd _y_-_a_x_i_s _g_r_i_d _a_n_d _l_a_b_e_l] [--------aaaalllltttt----yyyy----ggggrrrriiiidddd] [--------aaaalllltttt----
-       aaaauuuuttttoooossssccccaaaalllleeee] [----vvvv|--------vvvveeeerrrrttttiiiiccccaaaallll----llllaaaabbbbeeeellll _t_e_x_t] [----wwww|--------wwwwiiiiddddtttthhhh _p_i_x_e_l_s]
-       [----hhhh|--------hhhheeeeiiiigggghhhhtttt _p_i_x_e_l_s] [----iiii|--------iiiinnnntttteeeerrrrllllaaaacccceeeedddd]
-       [----ffff|--------iiiimmmmggggiiiinnnnffffoooo _f_o_r_m_a_t_s_t_r_i_n_g] [----aaaa|--------iiiimmmmggggffffoooorrrrmmmmaaaatttt GGGGIIIIFFFF|PPPPNNNNGGGG]
-       [----zzzz|--------llllaaaazzzzyyyy] [----oooo|--------llllooooggggaaaarrrriiiitttthhhhmmmmiiiicccc] [----uuuu|--------uuuuppppppppeeeerrrr----lllliiiimmmmiiiitttt _v_a_l_u_e]
-       [----llll|--------lllloooowwwweeeerrrr----lllliiiimmmmiiiitttt _v_a_l_u_e] [----rrrr|--------rrrriiiiggggiiiidddd] [----bbbb|--------bbbbaaaasssseeee _v_a_l_u_e]
-       [----cccc|--------ccccoooolllloooorrrr _C_O_L_O_R_T_A_G####_r_r_g_g_b_b]
-
-       [----tttt|--------ttttiiiittttlllleeee _t_i_t_l_e] [DDDDEEEEFFFF::::_v_n_a_m_e====_r_r_d::::_d_s_-_n_a_m_e::::_C_F]
-       [CCCCDDDDEEEEFFFF::::_v_n_a_m_e====_r_p_n_-_e_x_p_r_e_s_s_i_o_n] [PPPPRRRRIIIINNNNTTTT::::_v_n_a_m_e::::_C_F::::_f_o_r_m_a_t]
-       [GGGGPPPPRRRRIIIINNNNTTTT::::_v_n_a_m_e::::_C_F::::_f_o_r_m_a_t] [CCCCOOOOMMMMMMMMEEEENNNNTTTT::::_t_e_x_t]
-       [HHHHRRRRUUUULLLLEEEE::::_v_a_l_u_e####_r_r_g_g_b_b[::::_l_e_g_e_n_d]] [VVVVRRRRUUUULLLLEEEE::::_t_i_m_e####_r_r_g_g_b_b[::::_l_e_g_e_n_d]]
-       [LLLLIIIINNNNEEEE{1111|2222|3333}::::_v_n_a_m_e[####_r_r_g_g_b_b[::::_l_e_g_e_n_d]]]
-       [AAAARRRREEEEAAAA::::_v_n_a_m_e[####_r_r_g_g_b_b[::::_l_e_g_e_n_d]]]
-       [SSSSTTTTAAAACCCCKKKK::::_v_n_a_m_e[####_r_r_g_g_b_b[::::_l_e_g_e_n_d]]]
+     rrrrrrrrddddttttoooooooollll ggggrrrraaaapppphhhh _f_i_l_e_n_a_m_e [----ssss|--------ssssttttaaaarrrrtttt _s_e_c_o_n_d_s] [----eeee|--------
+     eeeennnndddd _s_e_c_o_n_d_s] [----xxxx|--------xxxx----ggggrrrriiiidddd _x-_a_x_i_s _g_r_i_d _a_n_d _l_a_b_e_l] [----yyyy|--------yyyy----
+     ggggrrrriiiidddd _y-_a_x_i_s _g_r_i_d _a_n_d _l_a_b_e_l] [--------aaaalllltttt----yyyy----ggggrrrriiiidddd] [--------aaaalllltttt----aaaauuuuttttoooossssccccaaaalllleeee]
+     [----vvvv|--------vvvveeeerrrrttttiiiiccccaaaallll----llllaaaabbbbeeeellll _t_e_x_t] [----wwww|--------wwwwiiiiddddtttthhhh _p_i_x_e_l_s] [----hhhh|--------
+     hhhheeeeiiiigggghhhhtttt _p_i_x_e_l_s] [----iiii|--------iiiinnnntttteeeerrrrllllaaaacccceeeedddd] [----ffff|--------iiiimmmmggggiiiinnnnffffoooo _f_o_r_m_a_t_s_t_r_i_n_g]
+     [----aaaa|--------iiiimmmmggggffffoooorrrrmmmmaaaatttt GGGGIIIIFFFF|PPPPNNNNGGGG] [----zzzz|--------llllaaaazzzzyyyy] [----oooo|--------llllooooggggaaaarrrriiiitttthhhhmmmmiiiicccc]
+     [----uuuu|--------uuuuppppppppeeeerrrr----lllliiiimmmmiiiitttt _v_a_l_u_e] [----llll|--------lllloooowwwweeeerrrr----lllliiiimmmmiiiitttt _v_a_l_u_e] [----rrrr|--------
+     rrrriiiiggggiiiidddd] [----bbbb|--------bbbbaaaasssseeee _v_a_l_u_e] [----cccc|--------ccccoooolllloooorrrr _C_O_L_O_R_T_A_G####_r_r_g_g_b_b]
+
+     [----tttt|--------ttttiiiittttlllleeee _t_i_t_l_e] [DDDDEEEEFFFF::::_v_n_a_m_e====_r_r_d::::_d_s-_n_a_m_e::::_C_F]
+     [CCCCDDDDEEEEFFFF::::_v_n_a_m_e====_r_p_n-_e_x_p_r_e_s_s_i_o_n] [PPPPRRRRIIIINNNNTTTT::::_v_n_a_m_e::::_C_F::::_f_o_r_m_a_t]
+     [GGGGPPPPRRRRIIIINNNNTTTT::::_v_n_a_m_e::::_C_F::::_f_o_r_m_a_t] [CCCCOOOOMMMMMMMMEEEENNNNTTTT::::_t_e_x_t]
+     [HHHHRRRRUUUULLLLEEEE::::_v_a_l_u_e####_r_r_g_g_b_b[::::_l_e_g_e_n_d]] [VVVVRRRRUUUULLLLEEEE::::_t_i_m_e####_r_r_g_g_b_b[::::_l_e_g_e_n_d]]
+     [LLLLIIIINNNNEEEE{1111|2222|3333}::::_v_n_a_m_e[####_r_r_g_g_b_b[::::_l_e_g_e_n_d]]]
+     [AAAARRRREEEEAAAA::::_v_n_a_m_e[####_r_r_g_g_b_b[::::_l_e_g_e_n_d]]]
+     [SSSSTTTTAAAACCCCKKKK::::_v_n_a_m_e[####_r_r_g_g_b_b[::::_l_e_g_e_n_d]]]
 
 DDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
-       The ggggrrrraaaapppphhhh functions main purpose is to create graphical
-       representations of the data stored in one or several RRRRRRRRDDDDs.
-       Apart from generating graphs, it can also extract
-       numerical reports.
-
-       _f_i_l_e_n_a_m_e
-               The name of the graph to generate. Since rrrrrrrrddddttttoooooooollll
-               outputs GIFs and PNGs, it's recommended that the
-               filename end in either _._g_i_f or _._p_n_g.  rrrrrrrrddddttttoooooooollll does
-               not enforce this, however.  If the  _f_i_l_e_n_a_m_e is
-               set to '-' the image file will be written to
-               standard out.  All other output will get
-               suppressed.
-
-               PNG output is recommended, since it takes up to
-               40% less disk space and 20-30% less time to
-               generate than a GIF file.
-
-               If no graph functions are called, the graph will
-               not be created.
-
-       ----ssss|--------ssssttttaaaarrrrtttt _s_e_c_o_n_d_s (default end-1day)
-               The time when the graph should begin. Time in
-               seconds since epoch (1970-01-01) is required.
-               Negative numbers are relative to the current time.
-               By default one day worth of data will be graphed.
-               See also AT-STYLE TIME SPECIFICATION section in
-               the _r_r_d_f_e_t_c_h documentation for a detailed
-               explanation on how to specify time.
-
+     The ggggrrrraaaapppphhhh functions main purpose is to create graphical
+     representations of the data stored in one or several RRRRRRRRDDDDs.
+     Apart from generating graphs, it can also extract numerical
+     reports.
 
+     _f_i_l_e_n_a_m_e
+             The name of the graph to generate. Since rrrrrrrrddddttttoooooooollll
+             outputs GIFs and PNGs, it's recommended that the
+             filename end in either ._g_i_f or ._p_n_g.  rrrrrrrrddddttttoooooooollll does
+             not enforce this, however.  If the  _f_i_l_e_n_a_m_e is set
+             to '-' the image file will be written to standard
+             out.  All other output will get suppressed.
 
+             PNG output is recommended, since it takes up to 40%
+             less disk space and 20-30% less time to generate
+             than a GIF file.
 
-14/Aug/99                     1.0.7                             1
+             If no graph functions are called, the graph will not
+             be created.
 
+     -ssss|--------ssssttttaaaarrrrtttt _s_e_c_o_n_d_s (default end-1day)
+             The time when the graph should begin. Time in
+             seconds since epoch (1970-01-01) is required.
+             Negative numbers are relative to the current time.
+             By default one day worth of data will be graphed.
+             See also AT-STYLE TIME SPECIFICATION section in the
+             _r_r_d_f_e_t_c_h documentation for a detailed explanation on
+             how to specify time.
 
 
 
 
-RRDGRAPH(1)                  rrdtool                  RRDGRAPH(1)
+12/Feb/2000            Last change: 1.0.13                      1
 
 
-       ----eeee|--------eeeennnndddd _s_e_c_o_n_d_s (default now)
-               The time when the graph should end. Time in
-               seconds since epoch.  See also AT-STYLE TIME
-               SPECIFICATION section in the _r_r_d_f_e_t_c_h
-               documentation for a detailed explanation of ways
-               to specify time.
 
-       ----xxxx|--------xxxx----ggggrrrriiiidddd _x_-_a_x_i_s _g_r_i_d _a_n_d _l_a_b_e_l (default autoconfigure)
-               The x-axis label is quite complex to configure. So
-               if you don't have very special needs, you can rely
-               on the autoconfiguration to get this right.
 
-               The x-axis label is configured, using the
-               following format:
 
-               _G_T_M::::_G_S_T::::_M_T_M::::_M_S_T::::_L_T_M:_L_S_T::::_L_P_R::::_L_F_M
 
-               You have to configure three elements making up the
-               x-axis labels and grid. The base grid (_G_?_?), the
-               major grid (_M_?_?) and the labels (_L_?_?). The
-               configuration is based on the idea that you first
-               specify a well known amount of time (_?_T_M) and then
-               say how many times it has to pass between each
-               grid line or label (_?_S_T). For the label you have
-               to define two additional items: The precision of
-               the label in seconds (_L_P_R) and the strftime format
-               used to generate the text of the label (_L_F_M).
+rrdtool                                               RRDGRAPH(1)
 
-               The _?_T_M elements must be one of the following
-               keywords: SSSSEEEECCCCOOOONNNNDDDD, MMMMIIIINNNNUUUUTTTTEEEE, HHHHOOOOUUUURRRR, DDDDAAAAYYYY, WWWWEEEEEEEEKKKK, MMMMOOOONNNNTTTTHHHH
-               or YYYYEEEEAAAARRRR.
 
-               If you wanted a graph with a base grid every 10
-               minutes and a major one every hour, with labels
-               every hour you would use the following x-axis
-               definition.
 
-               MINUTE:10:HOUR:1:HOUR:1:0:%X
+     -eeee|--------eeeennnndddd _s_e_c_o_n_d_s (default now)
+             The time when the graph should end. Time in seconds
+             since epoch.  See also AT-STYLE TIME SPECIFICATION
+             section in the _r_r_d_f_e_t_c_h documentation for a detailed
+             explanation of ways to specify time.
 
-               The precision in this example is 0 because the %X
-               format is exact. If the label was the name of the
-               day, we would have had a precision of 24 hours,
-               because when you say something like 'Monday' you
-               mean the whole day and not Monday morning 00:00.
-               Thus the label should be positioned at noon. By
-               defining a precision of 24 hours or rather 86400
-               seconds, you make sure that this happens.
+     -xxxx|--------xxxx----ggggrrrriiiidddd _x-_a_x_i_s _g_r_i_d _a_n_d _l_a_b_e_l (default autoconfigure)
+             The x-axis label is quite complex to configure. So
+             if you don't have very special needs, you can rely
+             on the autoconfiguration to get this right.
 
-       ----yyyy--------yyyy----ggggrrrriiiidddd _g_r_i_d _s_t_e_p:_l_a_b_e_l _f_a_c_t_o_r (default autoconfigure)
-               Makes vertical grid lines appear at _g_r_i_d _s_t_e_p
-               interval. Every _l_a_b_e_l _f_a_c_t_o_r gridstep, a major
-               grid line is printed, along with label showing the
-               value of the grid line.
+             The x-axis label is configured, using the following
+             format:
 
+             _G_T_M::::_G_S_T::::_M_T_M::::_M_S_T::::_L_T_M:_L_S_T::::_L_P_R::::_L_F_M
 
+             You have to configure three elements making up the
+             x-axis labels and grid. The base grid (_G??), the
+             major grid (_M??) and the labels (_L??). The
+             configuration is based on the idea that you first
+             specify a well known amount of time (?_T_M) and then
+             say how many times it has to pass between each grid
+             line or label (?_S_T). For the label you have to
+             define two additional items: The precision of the
+             label in seconds (_L_P_R) and the strftime format used
+             to generate the text of the label (_L_F_M).
 
+             The ?_T_M elements must be one of the following
+             keywords: SSSSEEEECCCCOOOONNNNDDDD, MMMMIIIINNNNUUUUTTTTEEEE, HHHHOOOOUUUURRRR, DDDDAAAAYYYY, WWWWEEEEEEEEKKKK, MMMMOOOONNNNTTTTHHHH or
+             YYYYEEEEAAAARRRR.
 
-14/Aug/99                     1.0.7                             2
+             If you wanted a graph with a base grid every 10
+             minutes and a major one every hour, with labels
+             every hour you would use the following x-axis
+             definition.
 
+             MINUTE:10:HOUR:1:HOUR:1:0:%X
 
+             The precision in this example is 0 because the %X
+             format is exact. If the label was the name of the
+             day, we would have had a precision of 24 hours,
+             because when you say something like 'Monday' you
+             mean the whole day and not Monday morning 00:00.
+             Thus the label should be positioned at noon. By
+             defining a precision of 24 hours or rather 86400
+             seconds, you make sure that this happens.
 
+     -yyyy|--------yyyy----ggggrrrriiiidddd _g_r_i_d _s_t_e_p:_l_a_b_e_l _f_a_c_t_o_r (default autoconfigure)
+             Makes vertical grid lines appear at _g_r_i_d _s_t_e_p
+             interval. Every _l_a_b_e_l _f_a_c_t_o_r gridstep, a major grid
+             line is printed, along with label showing the value
+             of the grid line.
 
 
-RRDGRAPH(1)                  rrdtool                  RRDGRAPH(1)
 
+12/Feb/2000            Last change: 1.0.13                      2
 
-       --------aaaalllltttt----yyyy----ggggrrrriiiidddd
-               Place Y grid dynamically based on graph Y range.
-               Algorithm ensures that you always have grid, that
-               there are enough but not too many grid lines and
-               the grid is metric. That is grid lines are placed
-               every 1, 2, 5 or 10 units.  (contributed by Sasha
-               Mikheev)
 
-       --------aaaalllltttt----aaaauuuuttttoooossssccccaaaalllleeee
-               Compute Y range  based on function absolute
-               minimum and maximum values. Default algorithm uses
-               predefined set of ranges.  This is good in many
-               cases but it fails miserably when you need to
-               graph something like 260 + 0.001 * _s_i_n(x). Default
-               algorithm will use Y range from 250 to 300 and on
-               the graph you will see almost straight line. With
-               --alt-autoscale Y range will be from slightly less
-               the 260 - 0.001 to slightly more then 260 + 0.001
-               and periodic behavior will be seen.   (contributed
-               by Sasha Mikheev)
 
-       ----vvvv|--------vvvveeeerrrrttttiiiiccccaaaallll----llllaaaabbbbeeeellll _t_e_x_t
-               vertical label on the left side of the graph. This
-               is normally used to specify the units used.
 
-       ----wwww|--------wwwwiiiiddddtttthhhh _p_i_x_e_l_s (default 400 pixel)
-               Width of the drawing area within the graph. This
-               affects the size of the gif.
 
-       ----hhhh|--------hhhheeeeiiiigggghhhhtttt _p_i_x_e_l_s (default 100 pixel)
-               Width of the drawing area within the graph. This
-               affects the size of the gif.
 
-       ----iiii|--------iiiinnnntttteeeerrrrllllaaaacccceeeedddd (default: false)
-               If you set this option, then the resulting GIF
-               will be interlaced.  Most web browsers display
-               these incrementally as they load. If you do not
-               use this option, the GIFs default to being
-               progressive scanned. The only effect of this
-               option is to control the format of the GIF on
-               disk. It makes no changes to the layout or
-               contents of the graph.
+rrdtool                                               RRDGRAPH(1)
 
-       ----ffff|--------iiiimmmmggggiiiinnnnffffoooo _f_o_r_m_a_t_s_t_r_i_n_g
-               After the image has been created, the graph
-               function uses printf together with this format
-               string to create output similar to the PRINT
-               function, only that the printf is supplied with
-               the parameters _f_i_l_e_n_a_m_e, _x_s_i_z_e and _y_s_i_z_e. In order
-               to generate an IIIIMMMMGGGG tag suitable for including the
-               graph into a web page, the command line would look
-               like this:
 
-                --imginfo '<IMG SRC="/img/%s" WIDTH="%lu" HEIGHT="%lu" ALT="Demo">'
 
+     --------aaaalllltttt----yyyy----ggggrrrriiiidddd
+             Place Y grid dynamically based on graph Y range.
+             Algorithm ensures that you always have grid, that
+             there are enough but not too many grid lines and the
+             grid is metric. That is grid lines are placed every
+             1, 2, 5 or 10 units.  (contributed by Sasha Mikheev)
 
+     --------aaaalllltttt----aaaauuuuttttoooossssccccaaaalllleeee
+             Compute Y range  based on function absolute minimum
+             and maximum values. Default algorithm uses
+             predefined set of ranges. This is good in many cases
+             but it fails miserably when you need to graph
+             something like 260 + 0.001 * _s_i_n(x). Default
+             algorithm will use Y range from 250 to 300 and on
+             the graph you will see almost straight line. With
+             --alt-autoscale Y range will be from slightly less
+             the 260 - 0.001 to slightly more then 260 + 0.001
+             and periodic behavior will be seen.   (contributed
+             by Sasha Mikheev)
 
-14/Aug/99                     1.0.7                             3
+     -vvvv|--------vvvveeeerrrrttttiiiiccccaaaallll----llllaaaabbbbeeeellll _t_e_x_t
+             vertical label on the left side of the graph. This
+             is normally used to specify the units used.
 
+     -wwww|--------wwwwiiiiddddtttthhhh _p_i_x_e_l_s (default 400 pixel)
+             Width of the drawing area within the graph. This
+             affects the size of the gif.
 
+     -hhhh|--------hhhheeeeiiiigggghhhhtttt _p_i_x_e_l_s (default 100 pixel)
+             Width of the drawing area within the graph. This
+             affects the size of the gif.
 
+     -iiii|--------iiiinnnntttteeeerrrrllllaaaacccceeeedddd (default: false)
+             If you set this option, then the resulting GIF will
+             be interlaced.  Most web browsers display these
+             incrementally as they load. If you do not use this
+             option, the GIFs default to being progressive
+             scanned. The only effect of this option is to
+             control the format of the GIF on disk. It makes no
+             changes to the layout or contents of the graph.
 
+     -ffff|--------iiiimmmmggggiiiinnnnffffoooo _f_o_r_m_a_t_s_t_r_i_n_g
+             After the image has been created, the graph function
+             uses printf together with this format string to
+             create output similar to the PRINT function, only
+             that the printf is supplied with the parameters
+             _f_i_l_e_n_a_m_e, _x_s_i_z_e and _y_s_i_z_e. In order to generate an
+             IIIIMMMMGGGG tag suitable for including the graph into a web
+             page, the command line would look like this:
 
-RRDGRAPH(1)                  rrdtool                  RRDGRAPH(1)
+              --imginfo '<IMG SRC="/img/%s" WIDTH="%lu" HEIGHT="%lu" ALT="Demo">'
 
 
-       ----aaaa|--------iiiimmmmggggffffoooorrrrmmmmaaaatttt GGGGIIIIFFFF|PPPPNNNNGGGG (default: GIF)
-               Allows you to produce PNG output from rrdtool.
 
-       ----zzzz|--------llllaaaazzzzyyyy (default: false)
-               Only generate the graph, if the current gif is out
-               of date or not existent.
 
-       ----uuuu|--------uuuuppppppppeeeerrrr----lllliiiimmmmiiiitttt _v_a_l_u_e (default autoconfigure)
-               The maximum value to be graphed. By default This
-               will be autoconfigured from the data you select
-               with the graphing functions.
+12/Feb/2000            Last change: 1.0.13                      3
 
-       ----llll|--------lllloooowwwweeeerrrr----lllliiiimmmmiiiitttt _v_a_l_u_e (default autoconfigure)
-               The minimum value to be graphed. By default This
-               will be autoconfigured from the data you select
-               with the graphing functions.
 
-       ----rrrr|--------rrrriiiiggggiiiidddd
-               rigid boundaries mode.  Normally rrdgraph will
-               automatically expand the lower and upper limit if
-               the graph contains a value outside the valid
-               range. With the r option you can disable this
-               behavior
 
-       ----bbbb|--------bbbbaaaasssseeee _v_a_l_u_e
-               if you are graphing memory (and NOT network
-               traffic) this switch should be set to 1024 so that
-               one Kb is 1024 byte. For traffic measurement, 1
-               kb/s is 1000 b/s.
 
-       ----oooo|--------llllooooggggaaaarrrriiiitttthhhhmmmmiiiicccc
-               logarithmic y-axis scaling
 
-       ----cccc|--------ccccoooolllloooorrrr _C_O_L_O_R_T_A_G####_r_r_g_g_b_b (default colors)
-               override the colors for the standard elements of
-               the graph. The _C_O_L_O_R_T_A_G must be one of the
-               following symbolic names: BBBBAAAACCCCKKKK ground, CCCCAAAANNNNVVVVAAAASSSS,
-               SSSSHHHHAAAADDDDEEEEAAAA left/top border, SSSSHHHHAAAADDDDEEEEBBBB right/bottom
-               border, GGGGRRRRIIIIDDDD, MMMMGGGGRRRRIIIIDDDD major grid, FFFFOOOONNNNTTTT, FFFFRRRRAAAAMMMMEEEE and
-               axis of the graph or AAAARRRRRRRROOOOWWWW. This option can be
-               called multiple times to set several colors.
 
-       ----tttt|--------ttttiiiittttlllleeee _t_e_x_t (default no title)
-               Define a title to be written into the graph
+rrdtool                                               RRDGRAPH(1)
 
-       DDDDEEEEFFFF::::_v_n_a_m_e====_r_r_d::::_d_s_-_n_a_m_e::::_C_F
-               Define virtual name for a data source. This name
-               can then be used in the functions explained below.
-               The DEF call automatically chooses an RRRRRRRRAAAA which
-               provides data in a resolution appropriate for the
-               size of the graph to be drawn.  Ideally this means
-               that one data point from the RRRRRRRRAAAA should be
-               represented by one pixel in the graph.  If the
-               resolution of the RRRRRRRRAAAA is higher than the
 
 
+     -aaaa|--------iiiimmmmggggffffoooorrrrmmmmaaaatttt GGGGIIIIFFFF|PPPPNNNNGGGG (default: GIF)
+             Allows you to produce PNG output from rrdtool.
 
-14/Aug/99                     1.0.7                             4
+     -zzzz|--------llllaaaazzzzyyyy (default: false)
+             Only generate the graph, if the current gif is out
+             of date or not existent.
 
+     -uuuu|--------uuuuppppppppeeeerrrr----lllliiiimmmmiiiitttt _v_a_l_u_e (default autoconfigure)
+             This is not the upper limit of a graph!  But rather,
+             this is the minimum upper bound of a graph.  Use
+             this to expand graphs up.  For example, the value
+             100 will result in graphs that have a upper bound of
+             100 or more.  Setting the upper limit to the maximum
+             value for some DS will result in disabling RRDtool's
+             autoscaling down (ie it will "expand" graphs up.)
+             To disable RRDtool's autoscaling up (to the max
+             value for the DSs graphed), use a nifty CDEF like
+             so:  CDEF:mcpu=cpu,100,GT,100,cpu,IF.  If this CDEF
+             is applied to all DSs in a graph, then the graph
+             will have an upper limit of 100.
 
+     -llll|--------lllloooowwwweeeerrrr----lllliiiimmmmiiiitttt _v_a_l_u_e (default autoconfigure)
+             This is not the lower limit of a graph.  But rather,
+             this is the maximum lower bound of a graph.  For
+             example, the value -100 will result in a graph that
+             has a lower limit of -100 or less.  Use this keyword
+             to expand graphs down.
 
+     -rrrr|--------rrrriiiiggggiiiidddd
+             rigid boundaries mode.  Normally rrdgraph will
+             automatically expand the lower and upper limit if
+             the graph contains a value outside the valid range.
+             With the r option you can disable this behavior
 
+     -bbbb|--------bbbbaaaasssseeee _v_a_l_u_e
+             if you are graphing memory (and NOT network traffic)
+             this switch should be set to 1024 so that one Kb is
+             1024 byte. For traffic measurement, 1 kb/s is 1000
+             b/s.
 
-RRDGRAPH(1)                  rrdtool                  RRDGRAPH(1)
+     -oooo|--------llllooooggggaaaarrrriiiitttthhhhmmmmiiiicccc
+             logarithmic y-axis scaling
 
+     -cccc|--------ccccoooolllloooorrrr _C_O_L_O_R_T_A_G####_r_r_g_g_b_b (default colors)
+             override the colors for the standard elements of the
+             graph. The _C_O_L_O_R_T_A_G must be one of the following
+             symbolic names: BBBBAAAACCCCKKKK ground, CCCCAAAANNNNVVVVAAAASSSS, SSSSHHHHAAAADDDDEEEEAAAA left/top
+             border, SSSSHHHHAAAADDDDEEEEBBBB right/bottom border, GGGGRRRRIIIIDDDD, MMMMGGGGRRRRIIIIDDDD
+             major grid, FFFFOOOONNNNTTTT, FFFFRRRRAAAAMMMMEEEE and axis of the graph or
+             AAAARRRRRRRROOOOWWWW. This option can be called multiple times to
+             set several colors.
 
-               resolution of the graph, the data in the RRA will
-               be consolidated according to the consolidation
-               function (_C_F) chosen.
 
-       CCCCDDDDEEEEFFFF::::_v_n_a_m_e====_r_p_n_-_e_x_p_r_e_s_s_i_o_n
-               Create a new virtual data source by evaluating a
-               mathematical expression, specified in Reverse
-               Polish Notation (RPN). If you have ever used a
-               traditional HP calculator you already know RPN.
-               The idea behind RPN notation is, that you have a
-               stack and push your data onto this stack. When
-               ever you execute an operation, it takes as many
-               data values from the stack as needed. The pushing
-               of data is implicit, so when ever you specify a
-               number or a variable, it gets pushed
-               automatically.
 
-               If this is all a big load of incomprehensible
-               words for you, maybe an example helps (a more
-               complete explanation is given in [1]): The
-               expression _v_n_a_m_e_+_3_/_2 becomes vname,3,2,/,+ in RPN.
-               First the three values get pushed onto the stack
-               (which now contains (the current value of) vname,
-               a 3 and a 2).  Then the / operator pops two values
-               from the stack (3 and 2), divides the first
-               argument by the second (3/2) and pushes the result
-               (1.5) back onto the stack. Then the + operator
-               pops two values (vname and 1.5) from the stack;
-               both values are added up and the result gets
-               pushes back onto the stack. In the end there is
-               only one value left on the stack: The result of
-               the expression.
 
-               The _r_p_n_-_e_x_p_r_e_s_s_i_o_n in the CCCCDDDDEEEEFFFF function takes
-               both, constant values as well as _v_n_a_m_e variables.
-               The following operators can be used on these
-               values:
+12/Feb/2000            Last change: 1.0.13                      4
 
-       +, -, *, /, %   pops two values from the stack applies the
-                       selected operator and pushes the result
-                       back onto the stack. The % operator stands
-                       for the modulo operation.
 
-       SIN, COS, LOG, EXP
-                       pops one value from the stack, applies the
-                       selected function and pushes the result
-                       back onto the stack.
 
-       LT, LE, GT, GE, EQ
-                       pops two values from the stack, compares
-                       them according to the selected condition
-                       and pushes either 1 back onto the stack if
-                       the condition is true and 0 if the
-                       condition was not true.
 
 
 
-14/Aug/99                     1.0.7                             5
+rrdtool                                               RRDGRAPH(1)
 
 
 
+     -tttt|--------ttttiiiittttlllleeee _t_e_x_t (default no title)
+             Define a title to be written into the graph
 
+     DDDDEEEEFFFF::::_v_n_a_m_e====_r_r_d::::_d_s-_n_a_m_e::::_C_F
+             Define virtual name for a data source. This name can
+             then be used in the functions explained below. The
+             DEF call automatically chooses an RRRRRRRRAAAA which contains
+             _C_F consolidated data in a resolution appropriate for
+             the size of the graph to be drawn.  Ideally this
+             means that one data point from the RRRRRRRRAAAA should be
+             represented by one pixel in the graph.  If the
+             resolution of the RRRRRRRRAAAA is higher than the resolution
+             of the graph, the data in the RRA will be further
+             consolidated according to the consolidation function
+             (_C_F) chosen.
 
-RRDGRAPH(1)                  rrdtool                  RRDGRAPH(1)
+     CCCCDDDDEEEEFFFF::::_v_n_a_m_e====_r_p_n-_e_x_p_r_e_s_s_i_o_n
+             Create a new virtual data source by evaluating a
+             mathematical expression, specified in Reverse Polish
+             Notation (RPN). If you have ever used a traditional
+             HP calculator you already know RPN. The idea behind
+             RPN notation is, that you have a stack and push your
+             data onto this stack. When ever you execute an
+             operation, it takes as many data values from the
+             stack as needed. The pushing of data is implicit, so
+             when ever you specify a number or a variable, it
+             gets pushed automatically.
 
+             If this is all a big load of incomprehensible words
+             for you, maybe an example helps (a more complete
+             explanation is given in [1]): The expression
+             _v_n_a_m_e+_3/_2 becomes vname,3,2,/,+ in RPN. First the
+             three values get pushed onto the stack (which now
+             contains (the current value of) vname, a 3 and a 2).
+             Then the / operator pops two values from the stack
+             (3 and 2), divides the first argument by the second
+             (3/2) and pushes the result (1.5) back onto the
+             stack. Then the + operator pops two values (vname
+             and 1.5) from the stack; both values are added up
+             and the result gets pushes back onto the stack. In
+             the end there is only one value left on the stack:
+             The result of the expression.
 
-       IF              pops three values from the stack. If the
-                       last value is not 0, the second value will
-                       be pushed back onto the stack, otherwise
-                       the first value is pushed back.
+             The _r_p_n-_e_x_p_r_e_s_s_i_o_n in the CCCCDDDDEEEEFFFF function takes both,
+             constant values as well as _v_n_a_m_e variables. The
+             following operators can be used on these values:
 
-                       If the stack contains the values A, B, C,
-                       D, E are presently on the stack, the IF
-                       operator will pop the values E D and C of
-                       the stack. It will look at C and if it is
-                       not 0 it will push D back onto the stack,
-                       otherwise E will be sent back to the
-                       stack.
+     +, -, *, /, %   pops two values from the stack applies the
+                     selected operator and pushes the result back
+                     onto the stack. The % operator stands for
+                     the modulo operation.
 
-       DUP, EXC, POP   These manipulate the stack directly.  DUP
-                       will duplicate the top of the stack,
-                       pushing the result back onto the stack.
-                       EXC will exchange the top two elements of
-                       the stack, and POP will pop off the top
-                       element of the stack.  Having insufficient
-                       elements on the stack for these operations
-                       is an error.
 
-       UN              Pops one value off the stack, if it is
-                       _*_U_N_K_N_O_W_N_*, 1 will be pushed back otherwise
-                       0.
 
-       UNKN            Push an _*_U_N_K_N_O_W_N_* value onto the stack.
 
-       INF, NEGINF     Push a positive or negative infinite (oo)
-                       value onto the stack. When drawing an
-                       infinite number it appears right at the
-                       top or bottom edge of the graph, depending
-                       whether you have a positive or negative
-                       infinite number.
+12/Feb/2000            Last change: 1.0.13                      5
 
-       NOW             Push the current (real world) time onto
-                       the stack.
 
-       TIME            Push the time the current sample was taken
-                       onto the stack.
 
-                       Please note that you may only use _v_n_a_m_e
-                       variables that you previously defined by
-                       either DDDDEEEEFFFF or CCCCDDDDEEEEFFFF. Furthermore, as of
-                       this writing (version 0.99.25), you must
-                       use at least one _v_n_a_m_e per expression,
-                       that is "CDEF:fourtytwo=2,40,+" will yield
-                       an error message but not a _v_n_a_m_e fourtytwo
-                       that's always equal to 42.
 
-       PPPPRRRRIIIINNNNTTTT::::_v_n_a_m_e::::_C_F::::_f_o_r_m_a_t
-               Calculate the chosen consolidation function _C_F
-               over the data-source variable _v_n_a_m_e and printf the
-               result to stdout using _f_o_r_m_a_t.  In the _f_o_r_m_a_t
 
 
+rrdtool                                               RRDGRAPH(1)
 
-14/Aug/99                     1.0.7                             6
 
 
+     SIN, COS, LOG, EXP
+                     pops one value from the stack, applies the
+                     selected function and pushes the result back
+                     onto the stack.
 
+     LT, LE, GT, GE, EQ
+                     pops two values from the stack, compares
+                     them according to the selected condition and
+                     pushes either 1 back onto the stack if the
+                     condition is true and 0 if the condition was
+                     not true.
 
+     IF              pops three values from the stack. If the
+                     last value is not 0, the second value will
+                     be pushed back onto the stack, otherwise the
+                     first value is pushed back.
 
-RRDGRAPH(1)                  rrdtool                  RRDGRAPH(1)
+                     If the stack contains the values A, B, C, D,
+                     E are presently on the stack, the IF
+                     operator will pop the values E D and C of
+                     the stack. It will look at C and if it is
+                     not 0 it will push D back onto the stack,
+                     otherwise E will be sent back to the stack.
 
+     DUP, EXC, POP   These manipulate the stack directly.  DUP
+                     will duplicate the top of the stack, pushing
+                     the result back onto the stack.  EXC will
+                     exchange the top two elements of the stack,
+                     and POP will pop off the top element of the
+                     stack.  Having insufficient elements on the
+                     stack for these operations is an error.
 
-               string there should be a '%lf' or '%le' marker in
-               the place where the number should be printed.
+     UN              Pops one value off the stack, if it is
+                     *_U_N_K_N_O_W_N*, 1 will be pushed back otherwise
+                     0.
 
-               If an additional '%s' is found AFTER the marker,
-               the value will be scaled and an appropriate SI
-               magnitude unit will be printed in place of the
-               '%s' marker. The scaling will take the '--base'
-               argument into consideration!
+     UNKN            Push an *_U_N_K_N_O_W_N* value onto the stack.
 
-               If a '%S' is used instead of a '%s', then instead
-               of calculating the appropriate SI magnitude unit
-               for this value, the previously calculated SI
-               magnitude unit will be used.  This is useful if
-               you want all the values in a PRINT statement to
-               have the same SI magnitude unit.  If there was no
-               previous SI magnitude calculation made, then '%S'
-               behaves like a '%s', unless the value is 0, in
-               which case it does not remember a SI magnitude
-               unit and a SI magnitude unit will only be
-               calculated when the next '%s' is seen or the next
-               '%S' for a non-zero value.
+     PREV            Push *_U_N_K_N_O_W_N* if its at the first value of
+                     a data set or otherwise the value of this
+                     CDEF at the previous time step. This allows
+                     you to perform calculations across the data.
 
-       GGGGPPPPRRRRIIIINNNNTTTT::::_v_n_a_m_e::::_C_F::::_f_o_r_m_a_t
-               Same as PPPPRRRRIIIINNNNTTTT but the result is printed into the
-               graph below the legend.
+     INF, NEGINF     Push a positive or negative infinite (oo)
+                     value onto the stack. When drawing an
+                     infinite number it appears right at the top
+                     or bottom edge of the graph, depending
+                     whether you have a positive or negative
+                     infinite number.
 
-       CCCCOOOOMMMMMMMMEEEENNNNTTTT::::_t_e_x_t
-               Like GGGGPPPPRRRRIIIINNNNTTTT but the _t_e_x_t is simply printed into
-               the graph.
+     NOW             Push the current (real world) time onto the
+                     stack.
 
-       HHHHRRRRUUUULLLLEEEE::::_v_a_l_u_e####_r_r_g_g_b_b[::::_l_e_g_e_n_d]
-               Draw a horizontal rule into the graph and
-               optionally add a legend
 
-       VVVVRRRRUUUULLLLEEEE::::_t_i_m_e####_r_r_g_g_b_b[::::_l_e_g_e_n_d]
-               Draw a vertical rule into the graph and optionally
-               add a legend
 
-       LLLLIIIINNNNEEEE{1111|2222|3333}::::_v_n_a_m_e[####_r_r_g_g_b_b[::::_l_e_g_e_n_d]]
-               Plot for the requested data, using the color
-               specified. Write a legend into the graph. The 3
-               possible keywords LLLLIIIINNNNEEEE1111, LLLLIIIINNNNEEEE2222, and LLLLIIIINNNNEEEE3333 generate
-               increasingly wide lines. If no color is defined,
-               the drawing is done 'blind' this is useful in
-               connection with the SSSSTTTTAAAACCCCKKKK function when you want
-               to ADD the values of two data-sources without
-               showing it in the graph.
+12/Feb/2000            Last change: 1.0.13                      6
 
-       AAAARRRREEEEAAAA:_v_n_a_m_e[####_r_r_g_g_b_b[::::_l_e_g_e_n_d]]
-               Does the same as LLLLIIIINNNNEEEE????, but the area between 0 and
-               the graph will be filled with the color specified.
 
-       SSSSTTTTAAAACCCCKKKK:_v_n_a_m_e[####_r_r_g_g_b_b[::::_l_e_g_e_n_d]]
-               Does the same as LLLLIIIINNNNEEEE????, but the graph gets stacked
 
 
 
-14/Aug/99                     1.0.7                             7
 
+rrdtool                                               RRDGRAPH(1)
 
 
 
+     TIME            Push the time the current sample was taken
+                     onto the stack.
 
-RRDGRAPH(1)                  rrdtool                  RRDGRAPH(1)
+                     Please note that you may only use _v_n_a_m_e
+                     variables that you previously defined by
+                     either DDDDEEEEFFFF or CCCCDDDDEEEEFFFF. Furthermore, as of this
+                     writing (version 0.99.25), you must use at
+                     least one _v_n_a_m_e per expression, that is
+                     "CDEF:fourtytwo=2,40,+" will yield an error
+                     message but not a _v_n_a_m_e fourtytwo that's
+                     always equal to 42.
 
+     PPPPRRRRIIIINNNNTTTT::::_v_n_a_m_e::::_C_F::::_f_o_r_m_a_t
+             Calculate the chosen consolidation function _C_F over
+             the data-source variable _v_n_a_m_e and printf the result
+             to stdout using _f_o_r_m_a_t.  In the _f_o_r_m_a_t string there
+             should be a '%lf' or '%le' marker in the place where
+             the number should be printed.
 
-               on top of the previous LLLLIIIINNNNEEEE????, AAAARRRREEEEAAAA or SSSSTTTTAAAACCCCKKKK graph.
-               Depending on the type of the previous graph, the
-               SSSSTTTTAAAACCCCKKKK will be either a LLLLIIIINNNNEEEE???? or an AAAARRRREEEEAAAA.  This
-               obviously implies that the first SSSSTTTTAAAACCCCKKKK must be
-               preceded by an AAAARRRREEEEAAAA or LLLLIIIINNNNEEEE???? -- you need something
-               to stack something onto in the first place ;)
+             If an additional '%s' is found AFTER the marker, the
+             value will be scaled and an appropriate SI magnitude
+             unit will be printed in place of the '%s' marker.
+             The scaling will take the '--base' argument into
+             consideration!
 
-               Note, that when you STACK onto *UNKNOWN* data,
-               rrdtool will not draw any graphics ... *UNKNOWN*
-               is not zero ... if you want it to zero then you
-               might want to use a CDEF argument with IF and UN
-               functions to turn *UNKNOWN* into zero ...
+             If a '%S' is used instead of a '%s', then instead of
+             calculating the appropriate SI magnitude unit for
+             this value, the previously calculated SI magnitude
+             unit will be used.  This is useful if you want all
+             the values in a PRINT statement to have the same SI
+             magnitude unit.  If there was no previous SI
+             magnitude calculation made, then '%S' behaves like a
+             '%s', unless the value is 0, in which case it does
+             not remember a SI magnitude unit and a SI magnitude
+             unit will only be calculated when the next '%s' is
+             seen or the next '%S' for a non-zero value.
 
-               =back
+     GGGGPPPPRRRRIIIINNNNTTTT::::_v_n_a_m_e::::_C_F::::_f_o_r_m_a_t
+             Same as PPPPRRRRIIIINNNNTTTT but the result is printed into the
+             graph below the legend.
 
-NNNNOOOOTTTTEEEE
-       In a ':' in a _l_e_g_e_n_d argument will mark the end of the
-       legend. To enter a ':' into a legend, the colon must be
-       escaped with a backslash '\:'.  Beware, that many
-       environments look for backslashes themselves, so it may be
-       necessary to write two backslashes so that one is passed
-       onto rrd_graph.
+     CCCCOOOOMMMMMMMMEEEENNNNTTTT::::_t_e_x_t
+             Like GGGGPPPPRRRRIIIINNNNTTTT but the _t_e_x_t is simply printed into the
+             graph.
 
-NNNNOOOOTTTTEEEE 2222
-       The text printed below the actual graph can be formated by
-       appending special escaped characters at the end of a text.
-       When ever such a character occurs, all pending text is
-       pushed onto the graph according to the character
-       specified.
+     HHHHRRRRUUUULLLLEEEE::::_v_a_l_u_e####_r_r_g_g_b_b[::::_l_e_g_e_n_d]
+             Draw a horizontal rule into the graph and optionally
+             add a legend
 
-       Valid characters are: jjjj for justified, llll for left aligned,
-       rrrr for right aligned and cccc for centered. In the next
-       section there is an example showing how to use centered
-       formating.
+     VVVVRRRRUUUULLLLEEEE::::_t_i_m_e####_r_r_g_g_b_b[::::_l_e_g_e_n_d]
+             Draw a vertical rule into the graph and optionally
+             add a legend
 
-       A special case is COMMENT:\s this inserts some additional
-       vertical space before placing the next row of legends.
 
-NNNNOOOOTTTTEEEE 3333
-       Whenever rrd_graph gets called, it prints a line telling
-       the size of the gif it has just created to STDOUT. This
-       line looks like this: XSIZExYSIZE.
 
-EEEEXXXXAAAAMMMMPPPPLLLLEEEE
-         rrdtool graph demo.gif --title="Demo Graph" \
-                 DEF:cel=demo.rrd:exhaust:AVERAGE \
-                 "CDEF:far=cel,32,-,0.55555,*" \
-                 LINE2:cel#00a000:"D. Celsius" \
-                 LINE2:far#ff0000:"D. Fahrenheit\c"
+12/Feb/2000            Last change: 1.0.13                      7
 
 
-EEEEXXXXAAAAMMMMPPPPLLLLEEEE2222
-       This example demonstrates the syntax for using IF and UN
-       to set _*_U_N_K_N_O_W_N_* values to 0.  This technique is useful if
 
 
 
-14/Aug/99                     1.0.7                             8
 
+rrdtool                                               RRDGRAPH(1)
 
 
 
+     LLLLIIIINNNNEEEE{1111|2222|3333}::::_v_n_a_m_e[####_r_r_g_g_b_b[::::_l_e_g_e_n_d]]
+             Plot for the requested data, using the color
+             specified. Write a legend into the graph. The 3
+             possible keywords LLLLIIIINNNNEEEE1111, LLLLIIIINNNNEEEE2222, and LLLLIIIINNNNEEEE3333 generate
+             increasingly wide lines. If no color is defined, the
+             drawing is done 'blind' this is useful in connection
+             with the SSSSTTTTAAAACCCCKKKK function when you want to ADD the
+             values of two data-sources without showing it in the
+             graph.
 
-RRDGRAPH(1)                  rrdtool                  RRDGRAPH(1)
+     AAAARRRREEEEAAAA:_v_n_a_m_e[####_r_r_g_g_b_b[::::_l_e_g_e_n_d]]
+             Does the same as LLLLIIIINNNNEEEE????, but the area between 0 and
+             the graph will be filled with the color specified.
 
+     SSSSTTTTAAAACCCCKKKK:_v_n_a_m_e[####_r_r_g_g_b_b[::::_l_e_g_e_n_d]]
+             Does the same as LLLLIIIINNNNEEEE????, but the graph gets stacked
+             on top of the previous LLLLIIIINNNNEEEE????, AAAARRRREEEEAAAA or SSSSTTTTAAAACCCCKKKK graph.
+             Depending on the type of the previous graph, the
+             SSSSTTTTAAAACCCCKKKK will be either a LLLLIIIINNNNEEEE???? or an AAAARRRREEEEAAAA.  This
+             obviously implies that the first SSSSTTTTAAAACCCCKKKK must be
+             preceded by an AAAARRRREEEEAAAA or LLLLIIIINNNNEEEE???? -- you need something
+             to stack something onto in the first place ;)
 
-       you are aggregating interface data where the start dates
-       of the data sets doesn't match.
+             Note, that when you STACK onto *UNKNOWN* data,
+             rrdtool will not draw any graphics ... *UNKNOWN* is
+             not zero ... if you want it to zero then you might
+             want to use a CDEF argument with IF and UN functions
+             to turn *UNKNOWN* into zero ...
 
-         rrdtool graph demo.gif --title="Demo Graph" \
-                DEF:idat1=interface1.rrd:ds0:AVERAGE \
-                DEF:idat2=interface2.rrd:ds0:AVERAGE \
-                DEF:odat1=interface1.rrd:ds1:AVERAGE \
-                DEF:odat2=interface2.rrd:ds1:AVERAGE \
-                CDEF:agginput=idat1,UN,0,idat1,IF,idat2,UN,0,idat2,IF,+,8,* \
-                CDEF:aggoutput=odat1,UN,0,odat1,IF,odat2,UN,0,odat2,IF,+,8,* \
-                AREA:agginput#00cc00:Input Aggregate \
-                LINE1:agginput#0000FF:Output Aggregate
+             =back
 
-       Assuming that idat1 has a data value of I<*UNKNOWN*>, the CDEF expression
+NNNNOOOOTTTTEEEESSSS oooonnnn lllleeeeggggeeeennnndddd aaaarrrrgggguuuummmmeeeennnnttttssss
+     EEEEssssccccaaaappppiiiinnnngggg tttthhhheeee ccccoooolllloooonnnn
 
-        idat1,UN,0,idat1,IF
+     In a ':' in a _l_e_g_e_n_d argument will mark the end of the
+     legend. To enter a ':' into a legend, the colon must be
+     escaped with a backslash '\:'.  Beware, that many
+     environments look for backslashes themselves, so it may be
+     necessary to write two backslashes so that one is passed
+     onto rrd_graph.
 
-       leaves us with a stack with contents of 1,0,NaN and the IF
-       function will pop off the 3 values and replace them with
-       0.  If idat1 had a real value like 7942099, then the stack
-       would have 0,0,7942099 and the real value would be the
-       replacement.
+     SSSSttttrrrriiiinnnngggg FFFFoooorrrrmmmmaaaattttttttiiiinnnngggg
 
-EEEEXXXXAAAAMMMMPPPPLLLLEEEE3333
-       This example shows two ways to use the INF function. First
-       it makes the background change color during half of the
-       hours. Then, it uses AREA and STACK to draw a picture. If
-       one of the inputs was UNKNOWN, all inputs are overlaid
-       with another AREA.
+     The text printed below the actual graph can be formated by
+     appending special escaped characters at the end of a text.
+     When ever such a character occurs, all pending text is
+     pushed onto the graph according to the character specified.
 
-         rrdtool graph example.png --title="INF demo" \
-                DEF:val1=some.rrd:ds0:AVERAGE \
-                DEF:val2=some.rrd:ds1:AVERAGE \
-                DEF:val3=some.rrd:ds2:AVERAGE \
-                DEF:val4=other.rrd:ds0:AVERAGE \
-                CDEF:background=val4,POP,TIME,7200,%,3600,LE,INF,UNKN,IF \
-                CDEF:wipeout=val1,val2,val3,val4,+,+,+,UN,INF,UNKN,IF \
-                AREA:background#F0F0F0 \
-                AREA:val1#0000FF:Value1 \
-                STACK:val2#00C000:Value2 \
-                STACK:val3#FFFF00:Value3 \
-                STACK:val4#FFC000:Value4 \
-                AREA:whipeout#FF0000:Unknown
+     Valid markers are: \\\\jjjj for justified, \\\\llll for left aligned, \\\\rrrr
+     for right aligned and \\\\cccc for centered. In the next section
+     there is an example showing how to use centered formating.
 
-       The first CDEF uses val4 as a dummy value. It's value is
-       removed immediately from the stack. Then a decision is
-       made based on the time that a sample was taken. If it is
-       an even hour (UTC time !) then the area will be filled. If
-       it is not, the value is set to UNKN and is not plotted.
 
-       The second CDEF looks if any of val1,val2,val3,val4 is
-       unknown. It does so by checking the outcome of
-       _s_u_m(val1,val2,val3,val4). Again, INF is returned when the
-       condition is true, UNKN is used to not plot the data.
 
 
+12/Feb/2000            Last change: 1.0.13                      8
 
-14/Aug/99                     1.0.7                             9
 
 
 
 
 
-RRDGRAPH(1)                  rrdtool                  RRDGRAPH(1)
+rrdtool                                               RRDGRAPH(1)
 
 
-       The different items are plotted in a particular order.
-       First do the background,+then use a normal area to overlay
-       it with data. Stack the other data until they+are all
-       plotted. Last but not least, overlay everything with eye-
-       hurting red to signal any unknown data.
-
-       Note that this example assumesthat your data is in the
-       positive half of the y-axis otherwhise you would would
-       have to add NEGINF in order to extend the coverage of the
-       rea to whole graph.
-
-       =head1 AUTHOR
-
-       Tobias Oetiker <oetiker at ee.ethz.ch>
-
-RRRREEEEFFFFEEEERRRREEEENNNNCCCCEEEESSSS
-       [1] http://www.dotpoint.com/xnumber/rpn_or_adl.htm
 
+     Normally there are two space characters inserted between
+     every two items printed into the graph. The space following
+     a string can be suppressed by putting a \\\\gggg at the end of the
+     string. The \\\\gggg also squshes any space inside the string if
+     it is at the very end of the string. This can be used in
+     connection with %%%%ssss to supress empty unit strings.
 
+      GPRINT:a:MAX:%lf%s\g
 
+     A special case is COMMENT:B<\s> this inserts some additional vertical space
+     before placing the next row of legends.
 
 
+NNNNOOOOTTTTEEEE oooonnnn RRRReeeettttuuuurrrrnnnn VVVVaaaalllluuuueeeessss
+     Whenever rrd_graph gets called, it prints a line telling the
+     size of the gif it has just created to STDOUT. This line
+     looks like this: XSIZExYSIZE.
 
+EEEEXXXXAAAAMMMMPPPPLLLLEEEE 1111
+       rrdtool graph demo.gif --title="Demo Graph" \
+               DEF:cel=demo.rrd:exhaust:AVERAGE \
+               "CDEF:far=cel,32,-,0.55555,*" \
+               LINE2:cel#00a000:"D. Celsius" \
+               LINE2:far#ff0000:"D. Fahrenheit\c"
 
 
+EEEEXXXXAAAAMMMMPPPPLLLLEEEE 2222
+     This example demonstrates the syntax for using IF and UN to
+     set *_U_N_K_N_O_W_N* values to 0.  This technique is useful if you
+     are aggregating interface data where the start dates of the
+     data sets doesn't match.
 
+       rrdtool graph demo.gif --title="Demo Graph" \
+              DEF:idat1=interface1.rrd:ds0:AVERAGE \
+              DEF:idat2=interface2.rrd:ds0:AVERAGE \
+              DEF:odat1=interface1.rrd:ds1:AVERAGE \
+              DEF:odat2=interface2.rrd:ds1:AVERAGE \
+              CDEF:agginput=idat1,UN,0,idat1,IF,idat2,UN,0,idat2,IF,+,8,* \
+              CDEF:aggoutput=odat1,UN,0,odat1,IF,odat2,UN,0,odat2,IF,+,8,* \
+              AREA:agginput#00cc00:Input Aggregate \
+              LINE1:agginput#0000FF:Output Aggregate
 
+     Assuming that idat1 has a data value of I<*UNKNOWN*>, the CDEF expression
 
+      idat1,UN,0,idat1,IF
 
+     leaves us with a stack with contents of 1,0,NaN and the IF
+     function will pop off the 3 values and replace them with 0.
+     If idat1 had a real value like 7942099, then the stack would
+     have 0,0,7942099 and the real value would be the
+     replacement.
 
 
 
 
+12/Feb/2000            Last change: 1.0.13                      9
 
 
 
 
 
 
+rrdtool                                               RRDGRAPH(1)
 
 
 
+EEEEXXXXAAAAMMMMPPPPLLLLEEEE 3333
+     This example shows two ways to use the INF function. First
+     it makes the background change color during half of the
+     hours. Then, it uses AREA and STACK to draw a picture. If
+     one of the inputs was UNKNOWN, all inputs are overlaid with
+     another AREA.
 
+       rrdtool graph example.png --title="INF demo" \
+              DEF:val1=some.rrd:ds0:AVERAGE \
+              DEF:val2=some.rrd:ds1:AVERAGE \
+              DEF:val3=some.rrd:ds2:AVERAGE \
+              DEF:val4=other.rrd:ds0:AVERAGE \
+              CDEF:background=val4,POP,TIME,7200,%,3600,LE,INF,UNKN,IF \
+              CDEF:wipeout=val1,val2,val3,val4,+,+,+,UN,INF,UNKN,IF \
+              AREA:background#F0F0F0 \
+              AREA:val1#0000FF:Value1 \
+              STACK:val2#00C000:Value2 \
+              STACK:val3#FFFF00:Value3 \
+              STACK:val4#FFC000:Value4 \
+              AREA:whipeout#FF0000:Unknown
 
+     The first CDEF uses val4 as a dummy value. It's value is
+     removed immediately from the stack. Then a decision is made
+     based on the time that a sample was taken. If it is an even
+     hour (UTC time !) then the area will be filled. If it is
+     not, the value is set to UNKN and is not plotted.
 
+     The second CDEF looks if any of val1,val2,val3,val4 is
+     unknown. It does so by checking the outcome of
+     _s_u_m(val1,val2,val3,val4). Again, INF is returned when the
+     condition is true, UNKN is used to not plot the data.
 
+     The different items are plotted in a particular order. First
+     do the background, then use a normal area to overlay it with
+     data. Stack the other data until they are all plotted. Last
+     but not least, overlay everything with eye-hurting red to
+     signal any unknown data.
 
+     Note that this example assumesthat your data is in the
+     positive half of the y-axis otherwhise you would would have
+     to add NEGINF in order to extend the coverage of the rea to
+     whole graph.
 
+AAAAUUUUTTTTHHHHOOOORRRR
+     Tobias Oetiker <oetiker at ee.ethz.ch>
 
+RRRREEEEFFFFEEEERRRREEEENNNNCCCCEEEESSSS
+     [1] http://www.dotpoint.com/xnumber/rpn_or_adl.htm
 
 
 
@@ -654,14 +654,14 @@
 
 
 
+12/Feb/2000            Last change: 1.0.13                     10
 
-14/Aug/99                     1.0.7                            10
 
 
 
 
 
-RRDGRAPH(1)                  rrdtool                  RRDGRAPH(1)
+rrdtool                                               RRDGRAPH(1)
 
 
 
@@ -717,10 +717,10 @@
 
 
 
+12/Feb/2000            Last change: 1.0.13                     11
 
 
 
 
-14/Aug/99                     1.0.7                            11
 
 

Added: trunk/orca/packages/rrdtool-1.0.13/doc/cdeftutorial.html
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/cdeftutorial.html	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/cdeftutorial.html	Sat Jul 13 21:08:12 2002
@@ -0,0 +1,1032 @@
+<HTML>
+<HEAD>
+<TITLE>cdeftutorial</TITLE>
+<LINK REV="made" HREF="mailto:karrer at zinal.ee.ethz.ch">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+<!--
+
+<UL>
+
+	<LI><A HREF="#NAME">NAME</A>
+	<LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+	<UL>
+
+		<LI><A HREF="#Why_this_tutorial_">Why this tutorial ?</A>
+		<LI><A HREF="#More_reading">More reading</A>
+	</UL>
+
+	<LI><A HREF="#What_are_CDEFs_">What are CDEFs ?</A>
+	<LI><A HREF="#Syntax">Syntax</A>
+	<LI><A HREF="#RPN_expressions">RPN-expressions</A>
+	<LI><A HREF="#Converting_your_wishes_to_RPN">Converting your wishes to RPN</A>
+	<LI><A HREF="#Some_special_numbers">Some special numbers</A>
+	<UL>
+
+		<LI><A HREF="#The_unknown_value">The unknown value</A>
+		<LI><A HREF="#Working_with_unknown_data_in_you">Working with unknown data in your database</A>
+		<LI><A HREF="#Infinity">Infinity</A>
+		<LI><A HREF="#Working_with_unknown_data_and_in">Working with unknown data and infinity</A>
+	</UL>
+
+	<LI><A HREF="#Some_examples">Some examples</A>
+	<UL>
+
+		<LI><A HREF="#Example_using_a_recently_create">Example: using a recently created RRD</A>
+		<LI><A HREF="#Example_better_handling_of_unkn">Example: better handling of unknown data, by using time</A>
+		<LI><A HREF="#Example_Pretending_weird_data_i">Example: Pretending weird data isn't there</A>
+		<LI><A HREF="#Example_You_suspect_to_have_pro">Example: You suspect to have problems and want to see unknown data.</A>
+		<LI><A HREF="#Same_example_useful_with_STACKed">Same example useful with STACKed data:</A>
+	</UL>
+
+	<LI><A HREF="#The_examples_from_the_rrd_graph_">The examples from the rrd graph manual page</A>
+	<UL>
+
+		<LI><A HREF="#Degrees_Celcius_vs_Degrees_Fahr">Degrees Celcius vs. Degrees Fahrenheit</A>
+		<LI><A HREF="#Changing_unknown_into_zero">Changing unknown into zero</A>
+		<LI><A HREF="#Infinity_demo">Infinity demo</A>
+	</UL>
+
+	<LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+	<LI><A HREF="#AUTHOR">AUTHOR</A>
+</UL>
+-->
+<!-- INDEX END -->
+
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+cdeftutorial - Alex van den Bogaerdt's CDEF tutorial
+
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+<STRONG>You provide a question and I will try to provide an answer in the next
+release</STRONG>. <STRONG>No feedback equals no changes!</STRONG>
+
+
+
+<P>
+<EM>Additions to this document are also welcome.</EM>
+
+
+
+<P>
+Alex van den Bogaerdt &lt;<A HREF="mailto:alex at ergens.op.het.net">alex at ergens.op.het.net</A>&gt;
+
+
+
+<P>
+<HR>
+<H2><A NAME="Why_this_tutorial_">Why this tutorial ?</A></H2>
+<P>
+One of the powerful parts of RRDtool is its ability to do all sorts of
+calculations on the data retrieved from it's databases. However RRDtool's
+many options and syntax make it difficult for the average user to
+understand. The manuals are good at explaining what these options do;
+however they do not (and should not) explain in detail why they are useful.
+As with my RRDtool tutorial: if you want a simple document in simple
+language you should read this tutorial. If you are happy with the official
+documentation, you may find this document too simple or even boring. If you
+do choose to read this tutorial, I also expect you to have read and fully
+understand my other tutorial. 
+
+<P>
+<HR>
+<H2><A NAME="More_reading">More reading</A></H2>
+<P>
+If you have difficulties with the way I try to explain them please read
+Steve Rader's <A HREF="././rpntutorial.html#">the rpntutorial manpage</A>. It may help you understand how this all works.
+
+<P>
+<HR>
+<H1><A NAME="What_are_CDEFs_">What are CDEFs ?</A></H1>
+<P>
+When retrieving data from an RRD, you are using a ``DEF'' to work with that
+data. Think of it as a variable that changes over time (where time is the
+x-axis). The value of this variable is what is found in the database at
+that particular time and you can't do any modifications on it. This is what
+CDEFs are for: they takes values from DEFs and perform calculations on
+them.
+
+<P>
+<HR>
+<H1><A NAME="Syntax">Syntax</A></H1>
+<P>
+<PRE>   DEF:var_name_1=some.rrd:ds_name:CF
+   CDEF:var_name_2=RPN_expression
+</PRE>
+<P>
+You first define ``var_name_1'' to be data collected from data source
+``ds_name'' found in RRD ``some.rrd'' with consolidation function ``CF''.
+
+<P>
+Assume the ifInOctets SNMP counter is saved in mrtg.rrd as the DS ``in''.
+Then the following DEF defines a variable for the average of that data
+source:
+
+<P>
+<PRE>   DEF:inbytes=mrtg.rrd:in:AVERAGE
+</PRE>
+<P>
+Say you want to display bits per second (instead of bytes per second as
+stored in the database.) You have to define a calculation (hence ``CDEF'')
+on variable ``inbytes'' and use that variable (inbits) instead of the
+original:
+
+<P>
+<PRE>   CDEF:inbits=inbytes,8,*
+</PRE>
+<P>
+It tells to multiply inbytes by eight to get inbits. I'll explain later how
+this works. In the graphing or printing functions, you can now use inbits
+where you would use inbytes otherwise.
+
+<P>
+Note that variable in the CDEF (inbits) must not be the same as the
+variable (inbytes) in the DEF!
+
+<P>
+<HR>
+<H1><A NAME="RPN_expressions">RPN-expressions</A></H1>
+<P>
+RPN is short-hand for Reverse Polish Notation. It works as follows. You put
+the variables or numbers on a stack. You also put operations (things-to-do)
+on the stack and this stack is then processed. The result will be placed on
+the stack. At the end, there should be exactly one number left: the outcome
+of the series of operations. If there is not exactly one number left,
+rrdtool will complain loudly.
+
+<P>
+Above multiplication by eight will look like:
+
+<OL>
+<LI><STRONG><A NAME="item__">.</A></STRONG>
+<P>
+Start with an empty stack
+
+<LI><STRONG>.</STRONG>
+<P>
+Put the content of variable inbytes on the stack
+
+<LI><STRONG>.</STRONG>
+<P>
+Put the number eight on the stack
+
+<LI><STRONG>.</STRONG>
+<P>
+Put the operation multiply on the stack
+
+<LI><STRONG>.</STRONG>
+<P>
+Process the stack
+
+<LI><STRONG>.</STRONG>
+<P>
+Retrieve the value from the stack and put it in variable inbits
+
+</OL>
+<P>
+We will now do an example with real numbers. Suppose the variable inbytes
+would have value 10, the stack would be:
+
+<OL>
+<LI><STRONG>.</STRONG>
+<P>
+||
+
+<LI><STRONG>.</STRONG>
+<P>
+|10|
+
+<LI><STRONG>.</STRONG>
+<P>
+|10|8|
+
+<LI><STRONG>.</STRONG>
+<P>
+|10|8|*|
+
+<LI><STRONG>.</STRONG>
+<P>
+|80|
+
+<LI><STRONG>.</STRONG>
+<P>
+||
+
+</OL>
+<P>
+Processing the stack (step 5) will retrieve one value from the stack (from
+the right at step 4). This is the operation multiply and this takes two
+values off the stack as input. The result is put back on the stack (the
+value 80 in this case). For multiplication the order doesn't matter but for
+other operations like subtraction and division it does. Generally speaking
+you have the following order:
+
+<P>
+<PRE>   y = A - B  --&gt;  y=minus(A,B)  --&gt;  CDEF:y=A,B,-
+</PRE>
+<P>
+This is not very intuitive (at least most people don't think so). For the
+function <CODE>f(A,B)</CODE> you reverse the position of ``f'' but you do
+not reverse the order of the variables. 
+
+<P>
+<HR>
+<H1><A NAME="Converting_your_wishes_to_RPN">Converting your wishes to RPN</A></H1>
+<P>
+First, get a clear picture of what you want to do. Break down the problem
+in smaller portions until they cannot be split anymore. Then it is rather
+simple to convert your ideas into RPN.
+
+<P>
+Suppose you have several RRDs and would like to add up some counters in
+them. These could be, for instance, the counters for every WAN link you are
+monitoring.
+
+<P>
+You have:
+
+<P>
+<PRE>   router1.rrd with link1in link2in
+   router2.rrd with link1in link2in
+   router3.rrd with link1.in
+</PRE>
+<P>
+Suppose you would like to add up all these counters, except for link2in
+inside router2.rrd. You need to do:
+
+<P>
+(in this example, ``router1.rrd:link1in'' means the DS link1in inside the
+RRD router1.rrd)
+
+<P>
+<PRE>   router1.rrd:link1in
+   router1.rrd:link2in
+   router2.rrd:link1in
+   router3.rrd:link1in
+   router3.rrd:link2in 
+   --------------------   +
+   (outcome of the sum)
+</PRE>
+<P>
+As a mathmatical function, this could be written:
+
+<P>
+<CODE>add(router1.rrd:link1in , router1.rrd:link2in , router2.rrd:link1in , router3.rrd:link1in , router3.rrd:link2.in)</CODE>
+
+
+
+<P>
+With RRDtool and RPN, first, define the inputs:
+
+<P>
+<PRE>   DEF:a=router1.rrd:link1in:AVERAGE
+   DEF:b=router1.rrd:link2in:AVERAGE
+   DEF:c=router2.rrd:link1in:AVERAGE
+   DEF:d=router3.rrd:link1in:AVERAGE
+   DEF:e=router3.rrd:link2in:AVERAGE
+</PRE>
+<P>
+Now, the mathematical function becomes: <CODE>add(a,b,c,d,e)</CODE>
+
+
+
+<P>
+In RPN, there's no operator that sums more than two values so you need to
+do several additions. You add a and b, add c to the result, add d to the
+result and add e to the result.
+
+<P>
+<PRE>   push a:         a     stack contains the value of a
+   push b and add: b,+   stack contains the result of a+b
+   push c and add: c,+   stack contains the result of a+b+c
+   push d and add: d,+   stack contains the result of a+b+c+d
+   push e and add: e,+   stack contains the result of a+b+c+d+e
+</PRE>
+<P>
+What was calculated here would be written down as:
+
+<P>
+<PRE>   ( ( ( (a+b) + c) + d) + e) &gt;
+</PRE>
+<P>
+This is in RPN:  <CODE>CDEF:result=a,b,+,c,+,d,+,e,+</CODE>
+
+
+
+<P>
+This is correct but it can be made more clear to humans. It does not matter
+if you add a to b and then add c to the result or first add b to c and then
+add a to the result. This makes it possible to rewrite the RPN into <CODE>CDEF:result=a,b,c,d,e,+,+,+,+</CODE> which is evaluatated differently: 
+
+<P>
+<PRE>   push value of variable a on the stack: a
+   push value of variable b on the stack: a b
+   push value of variable c on the stack: a b c
+   push value of variable d on the stack: a b c d
+   push value of variable e on the stack: a b c d e
+   push operator + on the stack:          a b c d e +
+   and process it:                        a b c P   (where P == d+e)
+   push operator + on the stack:          a b c P +
+   and process it:                        a b Q     (where Q == c+P)
+   push operator + on the stack:          a b Q +
+   and process it:                        a R       (where R == b+Q)
+   push operator + on the stack:          a R +
+   and process it:                        S         (where S == a+R)
+</PRE>
+<P>
+As you can see the RPN expression <CODE>a,b,c,d,e,+,+,+,+,+</CODE> will evaluate in
+<CODE>((((d+e)+c)+b)+a)</CODE> and it has the same outcome as <CODE>a,b,+,c,+,d,+,e,+</CODE> 
+According to Steve Rader this is called the commutative law of addition but
+you may forget this right away, as long as you remember what it represents.
+
+<P>
+Now look at an expression that contains a multiplication:
+
+<P>
+First in normal math: <CODE>let result = a+b*c</CODE>. In this case you can't choose the order yourself, you have to start with
+the multiplication and then add a to it. You may alter the position of b
+and c, you may not alter the position of a and b. 
+
+<P>
+You have to take this in consideration when converting this expression into
+RPN. Read it as: ``Add the outcome of b*c to a'' and then it is easy to
+write the RPN expression: <CODE>result=a,b,c,*,+</CODE>
+Another expression that would return the same: <CODE>result=b,c,*,a,+</CODE>
+
+
+
+<P>
+In normal math, you may encounter something like ``a*(b+c)'' and this can
+also be converted into RPN. The parenthesis just tell you to first add b
+and c, and then multiply a with the result. Again, now it is easy to write
+it in RPN: <CODE>result=a,b,c,+,*</CODE>. Note that this is very similar to one of the expressions in the previous
+paragraph, only the multiplication and the addition changed places.
+
+<P>
+When you have problems with RPN or when rrdtool is complaining, it's
+usually a Good Thing to write down the stack on a piece of paper and see
+what happens. Have the manual ready and pretend to be rrdtool. Just do all
+the math by hand to see what happens, I'm sure this will solve most, if not
+all, problems you encounter.
+
+<P>
+<HR>
+<H1><A NAME="Some_special_numbers">Some special numbers</A></H1>
+<P>
+<HR>
+<H2><A NAME="The_unknown_value">The unknown value</A></H2>
+<P>
+Sometimes collecting your data will fail. This can be very common,
+especially when querying over busy links. RRDtool can be configured to
+allow for one (or even more) unknown value and calculate the missing
+update. You can, for instance, query your device every minute. This is
+creating one so called PDP or primary data point per minute. If you defined
+your RRD to contain an RRA that stores 5-minute values, you need five of
+those PDPs to create one CDP (consolidated data point). These PDPs can
+become unknown in two cases:
+
+<OL>
+<LI><STRONG>.</STRONG>
+<P>
+The updates are too far apart. This is tuned using the ``heartbeat''
+setting
+
+<LI><STRONG>.</STRONG>
+<P>
+The update was set to unknown on purpose by inserting no value (using the
+template option) or by using ``U'' as the value to insert.
+
+</OL>
+<P>
+When a CDP is calculated, another mechanism determines if this CDP is valid
+or not. If there are too many PDPs unknown, the CDP is unknown as well.
+This is determined by the xff factor. Please note that one unknown counter
+update can result in two unknown PDPs! If you only allow for one unknown
+PDP per CDP, this makes the CDP go unknown!
+
+<P>
+Suppose the counter increments with one per second and you retrieve it
+every minute:
+
+<P>
+<PRE>   counter value    resulting rate
+   10000
+   10060            1; (10060-10000)/60 == 1
+   10120            1; (10060-10000)/60 == 1
+   unknown          unknown; you don't know the last value
+   10240            unknown; you don't know the previous value
+   10300            1; (10300-10240)/60 == 1
+</PRE>
+<P>
+If the CDP was to be calculated from the last five updates, it would get
+two unknown PDPs and three known PDPs. If xff would have been set to 0.5
+which by the way is a commonly used factor, the CDP would have a known
+value of 1. If xff would have been set to 0.2 then the resulting CDP would
+be unknown.
+
+<P>
+You have to decide the proper values for heartbeat, number of PDPs per CDP
+and the xff factor. As you can see from the previous text they define the
+behavior of your RRA.
+
+<P>
+<HR>
+<H2><A NAME="Working_with_unknown_data_in_you">Working with unknown data in your database</A></H2>
+<P>
+As you have read in the previous chapter, entries in an RRA can be set to
+the unknown value. If you do calculations with this type of value, the
+result has to be unknown too. This means that an expression such as <CODE>result=a,b,+</CODE> will be unknown if either a or b is unknown. It would be wrong to just
+ignore the unknown value and return the value of the other parameter. By
+doing so, you would assume ``unknown'' means ``zero'' and this is not true.
+
+<P>
+There has been a case where somebody was collecting data for over a year. A
+new piece of equipment was installed, a new RRD was created and the scripts
+were changed to add a counter from the old database and a counter from the
+new database. The result was disappointing, a large part of the statistics
+seemed to have vanished mysteriously ... They of course didn't, values from
+the old database (known values) were added to values from the new database
+(unknown values) and the result was unknown.
+
+<P>
+In this case, it is fairly reasonable to use a CDEF that alters unknown
+data into zero. The counters of the device were unknown (after all, it
+wasn't installed yet!) but you know that the data rate through the device
+had to be zero (because of the same reason: it was not installed).
+
+<P>
+There are some examples further on that make this change.
+
+<P>
+<HR>
+<H2><A NAME="Infinity">Infinity</A></H2>
+<P>
+Infinite data is another form of a special number. It cannot be graphed
+because by definition you would never reach the infinite value. You could
+think of positive and negative infinity (I'm not sure if mathematicians
+will agree) depending on the position relative to zero.
+
+<P>
+RRDtool is capable of representing (-not- graphing!) infinity by stopping
+at its current maximum (for positive infinity) or minimum (for negative
+infinity) without knowing this maximum (minimum).
+
+<P>
+Infinity in rrdtool is mostly used to draw an AREA without knowing its
+vertical dimensions. You can think of it as drawing an AREA with an
+infinite height and displaying only the part that is visible in the current
+graph. This is probably a good way to approximate infinity and it sure
+allows for some neat tricks. See below for examples.
+
+<P>
+<HR>
+<H2><A NAME="Working_with_unknown_data_and_in">Working with unknown data and infinity</A></H2>
+<P>
+Sometimes you would like to discard unknown data and pretend it is zero (or
+any other value for that matter) and sometimes you would like to pretend
+that known data is unknown (to discard known-to-be-wrong data). This is why
+CDEFs have support for unknown data. There are also examples available that
+show unknown data by using infinity.
+
+<P>
+<HR>
+<H1><A NAME="Some_examples">Some examples</A></H1>
+<P>
+<HR>
+<H2><A NAME="Example_using_a_recently_create">Example: using a recently created RRD</A></H2>
+<P>
+You are keeping statistics on your router for over a year now. Recently you
+installed an extra router and you would like to show the combined
+throughput for these two devices.
+
+<P>
+If you just add up the counters from router.rrd and router2.rrd, you will
+add known data (from router.rrd) to unknown data (from router2.rrd) for the
+bigger part of your stats. You could solve this in a few ways:
+
+<UL>
+<LI>
+<P>
+While creating the new database, fill it with zeros from the start to now.
+You have to make the database start at or before the least recent time in
+the other database.
+
+<LI>
+<P>
+Alternately you could use CDEF and alter unknown data to zero.
+
+</UL>
+<P>
+Both methods have their pros and cons. The first method is troublesome and
+if you want to do that you have to figure it out yourself. It is not
+possible to create a database filled with zeros, you have to put them in on
+purpose. Implementing the second method is described next:
+
+<P>
+What we want is: ``if the value is unknown, replace it with zero''. This
+could be writte in pseudo-code as: if (value is unknown) then (zero) else
+(value). When reading the rrdgraph manual you notice the ``UN'' function
+that returns zero or one. You also notice the ``IF'' function that takes
+zero or one as input.
+
+<P>
+First look at the ``IF'' function. It takes three values from the stack,
+the first value is the decision point, the second value is returned to the
+stack if the evaluation is ``true'' and if not, the third value is returned
+to the stack. We want the ``UN'' function to decide what happens so we
+combine those two functions in one CDEF.
+
+<P>
+Lets write down the two possible paths for the ``IF'' function:
+
+<P>
+<PRE>   if true  return a
+   if false return b
+</PRE>
+<P>
+In RPN:  <CODE>result=x,a,b,IF</CODE> where ``x'' is either true or false.
+
+<P>
+Now we have to fill in ``x'', this should be the ``(value is unknown)''
+part and this is in RPN:  <CODE>result=value,UN</CODE>
+
+
+
+<P>
+We now combine them: <CODE>result=value,UN,a,b,IF</CODE> and when we fill in the appropriate things for ``a'' and ``b'' we're
+finished:
+
+<P>
+<CODE>CDEF:result=value,UN,0,value,IF</CODE>
+
+
+
+<P>
+You may want to read Steve Raders RPN guide if you have difficulties with
+the way I explained this last example.
+
+<P>
+If you want to check this RPN expression, just mimic rrdtools behavior:
+
+<P>
+<PRE>   For any known value, the expression evaluates as follows:
+   CDEF:result=value,UN,0,value,IF  (value,UN) is not true so it becomes 0
+   CDEF:result=0,0,value,IF         &quot;IF&quot; will return the 3rd value
+   CDEF:result=value                The known value is returned
+</PRE>
+<P>
+<PRE>   For the unknown value, this happens:
+   CDEF:result=value,UN,0,value,IF  (value,UN) is true so it becomes 1
+   CDEF:result=1,0,value,IF         &quot;IF&quot; sees 1 and returns the 2nd value
+   CDEF:result=0                    Zero is returned
+</PRE>
+<P>
+Of course, if you would like to see another value instead of zero, you can
+use that other value.
+
+<P>
+Eventually, when all unknown data is removed from the RRD, you may want to
+remove this rule so that unknown data is properly displayed.
+
+<P>
+<HR>
+<H2><A NAME="Example_better_handling_of_unkn">Example: better handling of unknown data, by using time</A></H2>
+<P>
+Above example has one drawback. If you do log unknown data in your database
+after installing your new equipment, it will also be translated into zero
+and therefore you won't see that there was a problem. This is not good and
+what you really want to do is:
+
+<UL>
+<LI>
+<P>
+If there is unknown data, look at the time that this sample was taken
+
+<LI>
+<P>
+If the unknown value is before time xxx, make it zero
+
+<LI>
+<P>
+If it is after time xxx, leave it as unknown data
+
+</UL>
+<P>
+This is doable: you can compare the time that the sample was taken to some
+known time. Assuming you started to monitor your device on Friday September
+17, 00:35:57 MET DST. Translate this time in seconds since 1970-01-01 and
+it becomes 937521357. If you process unknown values that were received
+after this time, you want to leave them unknown and if they were
+``received'' before this time, you want to translate them into zero (so you
+can effectively ignore them while adding them to your other routers
+counters).
+
+<P>
+Translating Friday September 17, 00:35:57 MET DST into 937521357 can be
+done by, for instance, using gnu date:
+
+<P>
+<PRE>   date -d &quot;19990917 00:35:57&quot; +%s
+</PRE>
+<P>
+You could also dump the database and see where the data starts to be known.
+There are several other ways of doing this, just pick one.
+
+<P>
+Now we have to create the magic that allows us to process unknown values
+different depending on the time that the sample was taken. This is a three
+step process:
+
+<OL>
+<LI><STRONG>.</STRONG>
+<P>
+If the timestamp of the value is after 937521357, leave it as is
+
+<LI><STRONG>.</STRONG>
+<P>
+If the value is a known value, leave it as is
+
+<LI><STRONG>.</STRONG>
+<P>
+Change the unknown value into zero.
+
+</OL>
+<P>
+Lets look at part one:
+
+<P>
+<PRE>    if (true) return the original value
+</PRE>
+<P>
+We rewrite this:
+
+<P>
+<PRE>    if (true) return &quot;a&quot;
+    if (false) return &quot;b&quot;
+</PRE>
+<P>
+We need to calculate true or false from step 1. There is a function
+available that returns the timestamp for the current sample. It is called,
+how surprisingly, ``TIME''. This time has to be compared to a constant
+number, we need ``GT''. The output of ``GT'' is true or false and this is
+good input to ``IF''. We want ``if (time &gt; 937521357) then (return a)
+else (return b)''.
+
+<P>
+This process was already described toroughly in the previous chapter so
+lets do it quick:
+
+<P>
+<PRE>   if (x) then a else b
+      where x represents &quot;time&gt;937521357&quot;
+      where a represents the original value
+      where b represents the outcome of the previous example
+      
+   time&gt;937521357       --&gt; TIME,937521357,GT
+</PRE>
+<P>
+<PRE>   if (x) then a else b --&gt; x,a,b,IF
+   substitute x         --&gt; TIME,937521357,GT,a,b,IF
+   substitute a         --&gt; TIME,937521357,GT,value,b,IF
+   substitute b         --&gt; TIME,937521357,GT,value,value,UN,0,value,IF,IF
+</PRE>
+<P>
+We end up with:
+<CODE>CDEF:result=TIME,937521357,GT,value,value,UN,0,value,IF,IF</CODE>
+
+
+
+<P>
+This looks very complex however as you can see it was not too hard to come
+up with.
+
+<P>
+<HR>
+<H2><A NAME="Example_Pretending_weird_data_i">Example: Pretending weird data isn't there</A></H2>
+<P>
+Suppose you have a problem that shows up as huge spikes in your graph. You
+know this happens and why so you decide to work around the problem. Perhaps
+you're using your network to do a backup at night and by doing so you get
+almost 10mb/s while the rest of your network activity does not produce
+numbers higher than 100kb/s.
+
+<P>
+There are two options:
+
+<OL>
+<LI><STRONG>.</STRONG>
+<P>
+If the number exceeds 100kb/s it is wrong and you want it masked out by
+changing it into unknown
+
+<LI><STRONG>.</STRONG>
+<P>
+You don't want the graph to show more than 100kb/s
+
+</OL>
+<P>
+Pseudo code: if (number &gt; 100) then unknown else number or Pseudo code:
+if (number &gt; 100) then 100 else number.
+
+<P>
+The second ``problem'' may also be solved by using the rigid option of
+rrdtool graph, however this has not the same result. In this example you
+can end up with a graph that does autoscaling. Also, if you use the numbers
+to display maxima they will be set to 100kb/s.
+
+<P>
+We use ``IF'' and ``GT'' again. ``if (x) then (y) else (z)'' is written
+down as ``CDEF:result=x,y,z,IF''; now fill in x, y and z. For x you fill in
+``number greater than 100kb/s'' becoming ``number,100000,GT'' (kilo is 1000
+and b/s is what we measure!). The ``z'' part is ``number'' in both cases
+and the ``y'' part is either ``UNKN'' for unknown or ``100000'' for
+100kb/s.
+
+<P>
+The two CDEF expressions would be:
+
+<P>
+<PRE>    CDEF:result=number,100000,GT,UNKN,number,IF
+    CDEF:result=number,100000,GT,100000,number,IF
+</PRE>
+<P>
+<HR>
+<H2><A NAME="Example_You_suspect_to_have_pro">Example: You suspect to have problems and want to see unknown data.</A></H2>
+<P>
+Suppose you add up the number of active users on several terminal servers.
+If one of them doesn't give an answer (or an incorrect one) you get ``NaN''
+in the database (``Not a Number'') and NaN is evaluated as Unknown.
+
+<P>
+In this case, you would like to be alerted to it and the sum of the
+remaining values is of no value to you.
+
+<P>
+It would be something like:
+
+<P>
+<PRE>    DEF:users1=location1.rrd:onlineTS1:LAST
+    DEF:users2=location1.rrd:onlineTS2:LAST
+    DEF:users3=location2.rrd:onlineTS1:LAST
+    DEF:users4=location2.rrd:onlineTS2:LAST
+    CDEF:allusers=users1,users2,users3,users4,+,+,+
+</PRE>
+<P>
+If you now plot allusers, unknown data in one of users1..users4 will show
+up as a gap in your graph. You want to modify this to show a bright red
+line, not a gap.
+
+<P>
+Define an extra CDEF that is unknown if all is okay and is infinite if
+there is an unknown value:
+
+<P>
+<PRE>    CDEF:wrongdata=allusers,UN,INF,UNKN,IF
+</PRE>
+<P>
+``allusers,UN'' will evaluate to either true or false, it is the (x) part
+of the ``IF'' function and it checks if allusers is unknown. The (y) part
+of the ``IF'' function is set to ``INF'' (which means infinity) and the (z)
+part of the function returns ``UNKN''.
+
+<P>
+The logic is: if (allusers == unknown) then return INF else return UNKN.
+
+<P>
+You can now use AREA to display this ``wrongdata'' in bright red. If it is
+unknown (because allusers is known) then the red AREA won't show up. If the
+value is INF (because allusers is unknown) then the red AREA will be filled
+in on the graph at that particular time.
+
+<P>
+<PRE>   AREA:allusers#0000FF:combined user count
+   AREA:wrongdata#FF0000:unknown data
+</PRE>
+<P>
+<HR>
+<H2><A NAME="Same_example_useful_with_STACKed">Same example useful with STACKed data:</A></H2>
+<P>
+If you use stack in the previous example (as I would do) then you don't add
+up the values. Therefore, there is no relationship between the four values
+and you don't get a single value to test. Suppose users3 would be unknown
+at one point in time: users1 is plotted, users2 is stacked on top of
+users1, users3 is unknown and therefore nothing happens, users4 is stacked
+on top of users2. Add the extra CDEFs anyway and use them to overlay the
+``normal'' graph:
+
+<P>
+<PRE>   DEF:users1=location1.rrd:onlineTS1:LAST
+   DEF:users2=location1.rrd:onlineTS2:LAST
+   DEF:users3=location2.rrd:onlineTS1:LAST
+   DEF:users4=location2.rrd:onlineTS2:LAST
+   CDEF:allusers=users1,users2,users3,users4,+,+,+
+   CDEF:wrongdata=allusers,UN,INF,UNKN,IF
+   AREA:users1#0000FF:users at ts1
+   STACK:users2#00FF00:users at ts2
+   STACK:users3#00FFFF:users at ts3
+   STACK:users4#FFFF00:users at ts4
+   AREA:wrongdata#FF0000:unknown data
+</PRE>
+<P>
+If there is unknown data in one of users1..users4, the ``wrongdata'' AREA
+will be drawn and because it starts at the X-axis and has infinite height
+it will effectively overwrite the STACKed parts.
+
+<P>
+You could combine the two CDEF lines into one (we don't use ``allusers'')
+if you like. But there are good reasons for writting two CDEFS:
+
+<UL>
+<LI>
+<P>
+It improves the readability of the script
+
+<LI>
+<P>
+It can be used inside GPRINT to display the total number of users
+
+</UL>
+<P>
+If you choose to combine them, you can substitute the ``allusers'' in the
+second CDEF with the part after the equal sign from the first line:
+
+<P>
+<PRE>   CDEF:wrongdata=users1,users2,users3,users4,+,+,+,UN,INF,UNKN,IF
+</PRE>
+<P>
+If you do so, you won't be able to use these next GPRINTs:
+
+<P>
+<PRE>   COMMENT:&quot;Total number of users seen&quot;
+   GPRINT:allusers:MAX:&quot;Maximum: %6.0lf&quot;
+   GPRINT:allusers:MIN:&quot;Minimum: %6.0lf&quot;
+   GPRINT:allusers:AVERAGE:&quot;Average: %6.0lf&quot;
+   GPRINT:allusers:LAST:&quot;Current: %6.0lf\n&quot;
+</PRE>
+<P>
+<HR>
+<H1><A NAME="The_examples_from_the_rrd_graph_">The examples from the rrd graph manual page</A></H1>
+<P>
+<HR>
+<H2><A NAME="Degrees_Celcius_vs_Degrees_Fahr">Degrees Celcius vs. Degrees Fahrenheit</A></H2>
+<P>
+<PRE>   rrdtool graph demo.gif --title=&quot;Demo Graph&quot; \
+      DEF:cel=demo.rrd:exhaust:AVERAGE \
+      CDEF:far=cel,32,-,0.55555,* \
+      LINE2:cel#00a000:&quot;D. Celsius&quot; \
+      LINE2:far#ff0000:&quot;D. Fahrenheit\c&quot;
+</PRE>
+<P>
+This example gets the DS called ``exhaust'' from database ``demo.rrd'' and
+puts the values in variable ``cel''. The CDEF used is evaluated as follows:
+
+<P>
+<PRE>   CDEF:far=cel,32,-,0.5555,*
+   1. push variable &quot;cel&quot;
+   2. push 32
+   3. push function &quot;minus&quot; and process it
+      The stack now contains values that are 32 less than &quot;cel&quot;
+   4. push 0.5555
+   5. push function &quot;multiply&quot; and process it
+   6. the resulting value is now &quot;(cel-32)*0.55555&quot;
+</PRE>
+<P>
+Note that if you take the celcius to fahrenheit function you should be
+doing ``5/9*(cel-32)'' so 0.55555 is not exactly correct. It is close
+enough for this purpose and it saves a calculation.
+
+<P>
+<HR>
+<H2><A NAME="Changing_unknown_into_zero">Changing unknown into zero</A></H2>
+<P>
+<PRE>   rrdtool graph demo.gif --title=&quot;Demo Graph&quot; \
+      DEF:idat1=interface1.rrd:ds0:AVERAGE \
+      DEF:idat2=interface2.rrd:ds0:AVERAGE \
+      DEF:odat1=interface1.rrd:ds1:AVERAGE \
+      DEF:odat2=interface2.rrd:ds1:AVERAGE \
+      CDEF:agginput=idat1,UN,0,idat1,IF,idat2,UN,0,idat2,IF,+,8,* \
+      CDEF:aggoutput=odat1,UN,0,odat1,IF,odat2,UN,0,odat2,IF,+,8,* \
+      AREA:agginput#00cc00:Input Aggregate \
+      LINE1:aggoutput#0000FF:Output Aggregate
+</PRE>
+<P>
+These two CDEFs are built from several functions. It helps to split them
+when viewing what they do. Starting with the first CDEF we would get:
+idat1,UN --&gt; a 0 --&gt; b idat1 --&gt; c if (a) then (b) else (c) The
+result is therefore ``0'' if it is true that ``idat1'' equals ``UN''. If
+not, the original value of ``idat1'' is put back on the stack. Lets call
+this answer ``d''. The process is repeated for the next five items on the
+stack, it is done the same and will return answer ``h''. The resulting
+stack is therefore ``d,h''. The expression has been simplified to
+``d,h,+,8,*'' and it will now be easy to see that we add ``d'' and ``h'',
+and multiply the result with eight.
+
+<P>
+The end result is that we have added ``idat1'' and ``idat2'' and in the
+process we effectively ignored unknown values. The result is multiplied by
+eight, most likely to convert bytes/s to bits/s.
+
+<P>
+<HR>
+<H2><A NAME="Infinity_demo">Infinity demo</A></H2>
+<P>
+<PRE>   rrdtool graph example.png --title=&quot;INF demo&quot; \
+      DEF:val1=some.rrd:ds0:AVERAGE \
+      DEF:val2=some.rrd:ds1:AVERAGE \
+      DEF:val3=some.rrd:ds2:AVERAGE \
+      DEF:val4=other.rrd:ds0:AVERAGE \
+      CDEF:background=val4,POP,TIME,7200,%,3600,LE,INF,UNKN,IF \
+      CDEF:wipeout=val1,val2,val3,val4,+,+,+,UN,INF,UNKN,IF \
+      AREA:background#F0F0F0 \
+      AREA:val1#0000FF:Value1 \
+      STACK:val2#00C000:Value2 \
+      STACK:val3#FFFF00:Value3 \
+      STACK:val4#FFC000:Value4 \
+      AREA:whipeout#FF0000:Unknown
+</PRE>
+<P>
+This demo demonstrates two ways to use infinity. It is a bit tricky to see
+what happens in the ``background'' CDEF.
+
+<P>
+<PRE>   &quot;val4,POP,TIME,7200,%,3600,LE,INF,UNKN,IF&quot;
+</PRE>
+<P>
+This RPN takes the value of ``val4'' as input and then immediately removes
+it from the stack using ``POP''. The stack is now empty but as a side
+result we now know the time that this sample was taken. This time is put on
+the stack by the ``TIME'' function.
+
+<P>
+``TIME,7200,%'' takes the modulo of time and 7200 (which is two hours). The
+resulting value on the stack will be a number in the range from 0 to 7199.
+
+<P>
+For people who don't know the modulo function: it is the remainder after an
+integer division. If you divide 16 by 3, the answer would be 5 and the
+remainder would be 1. So, ``16,3,%'' returns 1.
+
+<P>
+We have the result of ``TIME,7200,%'' on the stack, lets call this ``a''.
+The start of the RPN has become ``a,3600,LE'' and this checks if ``a'' is
+less or equal than ``3600''. It is true half of the time. We now have to
+process the rest of the RPN and this is only a simple ``IF'' function that
+returns either ``INF'' or ``UNKN'' depending on the time. This is returned
+to variable ``background''.
+
+<P>
+The second CDEF has been discussed earlyer in this document so we won't do
+that here.
+
+<P>
+Now you can draw the different layers. Start with the background that is
+either unknown (nothing to see) or infinite (the whole positive part of the
+graph gets filled). Next you draw the data on top of this background. It
+will overlay the background. Suppose one of val1..val4 would be unknown, in
+that case you end up with only three bars stacked on top of each other. You
+don't want to see this because the data is only valid when all four
+variables are valid. This is why you use the second CDEF, it will overlay
+the data with an AREA so the data cannot be seen anymore.
+
+<P>
+If your data can also have negative values you also need to overwrite the
+other half of your graph. This can be done in a relatively simple way: what
+you need is the ``wipeout'' variable and place a negative sign before it:
+``CDEF:wipeout2=wipeout,-1,*'' =head1 Out of ideas for now
+
+<P>
+This document was created from questions asked by either myself or by other
+people on the list. Please let me know if you find errors in it or if you
+have trouble understanding it. If you think there should be an addition,
+mail me: &lt;<A HREF="mailto:alex at ergens.op.het.net">alex at ergens.op.het.net</A>&gt;
+
+
+
+<P>
+Remember: <STRONG>No feedback equals no changes!</STRONG>
+
+
+
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+The RRDtool manpages
+
+<P>
+<HR>
+<H1><A NAME="AUTHOR">AUTHOR</A></H1>
+<P>
+Alex van den Bogaerdt
+&lt;<A HREF="mailto:alex at ergens.op.het.net">alex at ergens.op.het.net</A>&gt;
+
+</BODY>
+
+</HTML>

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/RRDs.txt
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/RRDs.txt	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/RRDs.txt	Sat Jul 13 21:08:12 2002
@@ -1,113 +1,113 @@
 
 
 
-RRDs(3pm)                    rrdtool                    RRDs(3pm)
+rrdtool                                                   RRDs(3)
+
 
 
 NNNNAAAAMMMMEEEE
-       RRDs - Access rrdtool as a shared module
+     RRDs - Access rrdtool as a shared module
 
 SSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS
-         use RRDs::ext
-         RRDs::error
-         RRDs::last ...
-         RRDs::create ...
-         RRDs::update ...
-         RRDs::graph ...
-         RRDs::fetch ...
-         RRDs::tune ...
+       use RRDs;
+       RRDs::error
+       RRDs::last ...
+       RRDs::create ...
+       RRDs::update ...
+       RRDs::graph ...
+       RRDs::fetch ...
+       RRDs::tune ...
 
 
 DDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
-       CCCCaaaalllllllliiiinnnngggg SSSSeeeeqqqquuuueeeennnncccceeee
-
-       This module accesses rrdtool functionality directly from
-       within perl. The arguments to the functions listed in the
-       SYNOPSIS are explained in the regular rrdtool
-       documentation. The commandline call
-
-        rrdtool update mydemo.rrd N:12:13
+     CCCCaaaalllllllliiiinnnngggg SSSSeeeeqqqquuuueeeennnncccceeee
 
-       gets turned into
+     This module accesses rrdtool functionality directly from
+     within perl. The arguments to the functions listed in the
+     SYNOPSIS are explained in the regular rrdtool documentation.
+     The commandline call
 
-        RRDs::update qw(mydemo.rrd N:12:13);
+      rrdtool update mydemo.rrd N:12:13
 
+     gets turned into
 
-       EEEErrrrrrrroooorrrr HHHHaaaannnnddddlllliiiinnnngggg
+      RRDs::update ("mydemo.rrd", "N:12:13");
 
-       The RRD functions will not abort your program even when
-       they can not make sense out of the arguments you fed them.
-       There are two ways to determine if an error has occured.
 
-       First the every function will return the value -1 if an
-       error occured.  Second, the function RRDs::error can be
-       called to get the error message from the last function
-       call. If RRDs::error does not return an error then the
-       previous function has completed its task succesfully.
+     EEEErrrrrrrroooorrrr HHHHaaaannnnddddlllliiiinnnngggg
 
-        RRDs::update qw(mydemo.rrd N:12:13);
-        my $ERR=RRDs::error;
-        die "ERROR while updating mydemo.rrd: $ERR\n" if $ERR;
+     The RRD functions will not abort your program even when they
+     can not make sense out of the arguments you fed them. There
+     are two ways to determine if an error has occured.
 
+     First the every function will return the value -1 if an
+     error occured.  Second, the function RRDs::error can be
+     called to get the error message from the last function call.
+     If RRDs::error does not return an error then the previous
+     function has completed its task succesfully.
 
-       RRRReeeettttuuuurrrrnnnn VVVVaaaalllluuuueeeessss
+      use RRDs;
+      RRDs::update ("mydemo.rrd","N:12:13");
+      my $ERR=RRDs::error;
+      die "ERROR while updating mydemo.rrd: $ERR\n" if $ERR;
 
-       The functions RRDs::last, RRDs::graph and RRDs::fetchgive
-       return their findigs.
 
-       RRDs::last returns a single INTEGER representing the last
-       update time.
+     RRRReeeettttuuuurrrrnnnn VVVVaaaalllluuuueeeessss
 
+     The functions RRDs::last, RRDs::graph and RRDs::fetch return
+     their findings.
 
 
 
-27/Aug/99                     1.0.7                             1
 
+13/Feb/2000            Last change: 1.0.13                      1
 
 
 
 
-RRDs(3pm)                    rrdtool                    RRDs(3pm)
 
 
-        $lastupdate = RRDs::last ...
+rrdtool                                                   RRDs(3)
 
-       RRDs::graph returns an pointer to an ARRAY containing the
-       x-size and y-size of the created gif and results of the
-       PRINT arguments.
 
-        ($averages,$xsize,$ysize) = RRDs::graph ...
-        print "Gifsize: ${xsize}x${ysize}\n";
-        print "Averages: ", (join ", ", @$averages);
 
-       RRDs::fetch is the most complex of the pack regarding
-       return values. There are 4 values. Two normal integers, a
-       pointer to an array and a pointer to a array of pointers.
+     RRDs::last returns a single INTEGER representing the last
+     update time.
 
-        my ($start,$step,$names,$data) = RRDs::fetch ...
-        print "Start:        ".localtime($start)."\n";
-        print "Stepsize:     $step seconds\n";
-        print "Column Names: ".join (", ", @$names)."\n";
-        print "Date:\n";
-        foreach my $line (@$array){
-             print "".localtime($start),"   ";
-             $start += $step;
-             foreach my $val (@$line) {
-                  printf "%12.1f", $val;
-             }
-             print "\n";
-        }
+      $lastupdate = RRDs::last ...
 
-       See the examples directory for more ways to use this
-       extension.
-
-AAAAUUUUTTTTHHHHOOOORRRR
-       Tobias Oetiker <oeitker at ee.ethy.ch>
+     RRDs::graph returns an pointer to an ARRAY containing the
+     x-size and y-size of the created gif and results of the
+     PRINT arguments.
 
+      ($averages,$xsize,$ysize) = RRDs::graph ...
+      print "Gifsize: ${xsize}x${ysize}\n";
+      print "Averages: ", (join ", ", @$averages);
 
+     RRDs::fetch is the most complex of the pack regarding return
+     values. There are 4 values. Two normal integers, a pointer
+     to an array and a pointer to a array of pointers.
 
+       my ($start,$step,$names,$data) = RRDs::fetch ...
+       print "Start:       ", scalar localtime($start), " ($start)\n";
+       print "Step size:   $step seconds\n";
+       print "DS names:    ", join (", ", @$names)."\n";
+       print "Data points: ", $#$data + 1, "\n";
+       print "Data:\n";
+       foreach my $line (@$data) {
+         print "  ", scalar localtime($start), " ($start) ";
+         $start += $step;
+         foreach my $val (@$line) {
+           printf "%12.1f ", $val;
+         }
+         print "\n";
+       }
 
+     See the examples directory for more ways to use this
+     extension.
 
+AAAAUUUUTTTTHHHHOOOORRRR
+     Tobias Oetiker <oeitker at ee.ethy.ch>
 
 
 
@@ -126,7 +126,7 @@
 
 
 
+13/Feb/2000            Last change: 1.0.13                      2
 
-27/Aug/99                     1.0.7                             2
 
 

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/rrdcgi.txt
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/rrdcgi.txt	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/rrdcgi.txt	Sat Jul 13 21:08:12 2002
@@ -1,185 +1,251 @@
 
 
 
-RRDCGI(1)                    rrdtool                    RRDCGI(1)
+rrdtool                                                 RRDCGI(1)
+
 
 
 NNNNAAAAMMMMEEEE
-       rrdcgi - create web pages containing RRD graphs based on
-       templates
+     rrdcgi - create web pages containing RRD graphs based on
+     templates
 
 SSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS
-       #!/path/to/rrrrrrrrddddccccggggiiii [--------ggggooooooooddddffffoooorrrr|----gggg _s_e_c_o_n_d_s] [--------ffffiiiilllltttteeeerrrr]
-       [--------rrrreeeeffffrrrreeeesssshhhh|----rrrr]
+     #!/path/to/rrrrrrrrddddccccggggiiii [--------ggggooooooooddddffffoooorrrr|----gggg _s_e_c_o_n_d_s] [--------ffffiiiilllltttteeeerrrr] [--------
+     rrrreeeeffffrrrreeeesssshhhh|----rrrr]
 
 DDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
-       rrrrrrrrddddccccggggiiii is a sort of very limited script interpreter. Its
-       purpose is to run as a cgi-program and parse a web page
-       template containing special <RRD:: tags. rrrrrrrrddddccccggggiiii will
-       interpret and act according to these tags.  In the end it
-       will printout a web page including the necessary CGI
-       headers.
-
-       rrrrrrrrddddccccggggiiii parses the contents of the template in 2 steps. In
-       each step it looks only for a subset of tags. This allows
-       to nest tags.
+     rrrrrrrrddddccccggggiiii is a sort of very limited script interpreter. Its
+     purpose is to run as a cgi-program and parse a web page
+     template containing special <RRD:: tags. rrrrrrrrddddccccggggiiii will
+     interpret and act according to these tags.  In the end it
+     will printout a web page including the necessary CGI
+     headers.
 
-       The argument parser uses the same semantics as you are
-       used from your c shell.
+     rrrrrrrrddddccccggggiiii parses the contents of the template in 2 steps. In
+     each step it looks only for a subset of tags. This allows to
+     nest tags.
 
-       --------ggggooooooooddddffffoooorrrr|----gggg _s_e_c_o_n_d_s
-               Specify the number of seconds this page should
-               remain valid. This will prompt the rrdcgi to
-               output a Last-Modified and a Expire header.
+     The argument parser uses the same semantics as you are used
+     from your c shell.
 
-       --------ffffiiiilllltttteeeerrrr
-               Assume that rrdcgi is being run as a filter and
-               not as a cgi.
+     --------ffffiiiilllltttteeeerrrr
+             Assume that rrdcgi is being run as a filter and not
+             as a cgi.
 
-       --------rrrreeeeffffrrrreeeesssshhhh|----rrrr
-               If the --------ggggooooooooddddffffoooorrrr flag is specified, then --------rrrreeeeffffrrrreeeesssshhhh
-               will cause rrdcgi to output a Refresh header with
-               the value of the --------ggggooooooooddddffffoooorrrr value.
+     --------rrrreeeeffffrrrreeeesssshhhh|-rrrr
+             If the --------ggggooooooooddddffffoooorrrr flag is specified, then --------rrrreeeeffffrrrreeeesssshhhh
+             will cause rrdcgi to output a Refresh header with
+             the value of the --------ggggooooooooddddffffoooorrrr value.
 
-       PPPPaaaassssssss 1111
+     PPPPaaaassssssss 1111
 
+     RRD::CV _n_a_m_e
+             Inserts the CGI variable of the given name.
 
-       RRD::CV _n_a_m_e
-               Inserts the CGI variable of the given name.
+     RRD::CV::QUOTE _n_a_m_e
+             Inserts the CGI variable of the given name but
+             quotes it, ready for use as an argument in another
+             RRD:: tag. So even when there are spaces in the
+             value of the CGI variable it will still be
+             considered as one argument.
 
-       RRD::CV::QUOTE _n_a_m_e
-               Inserts the CGI variable of the given name but
-               quotes it, ready for use as an argument in another
-               RRD:: tag. So even when there are spaces in the
-               value of the CGI variable it will still be
-               considered as one argument.
+     RRD::CV::PATH _n_a_m_e
+             Inserts the CGI variable of the given name, quotes
+             it and makes sure the it starts neither with a '/'
+             nor contains '..'. This is to make sure that no
+             problematic pathnames can be introduced through the
+             CGI interface.
 
-       RRD::CV::PATH _n_a_m_e
-               Inserts the CGI variable of the given name, quotes
-               it and makes sure the it starts neither with a '/'
-               nor contains '..'. This is to make sure that no
 
 
 
-9/Aug/99                      1.0.7                             1
 
+6/Feb/2000             Last change: 1.0.13                      1
 
 
 
 
-RRDCGI(1)                    rrdtool                    RRDCGI(1)
 
 
-               problematic pathnames can be introduced through
-               the CGI interface.
+rrdtool                                                 RRDCGI(1)
 
-       PPPPaaaassssssss 2222
 
 
-       RRD::INCLUDE _f_i_l_e_n_a_m_e
-               Include the contents of the given file into the
-               page returned from the cgi
+     PPPPaaaassssssss 2222
 
-       PPPPaaaassssssss 3333
+     RRD::GOODFOR _s_e_c_o_n_d_s
+             Specify the number of seconds this page should
+             remain valid. This will prompt the rrdcgi to output
+             a Last-Modified, an Expire and if the number of
+             seconds is _n_e_g_a_t_i_v_e a Refresh headers.
 
+     RRD::INCLUDE _f_i_l_e_n_a_m_e
+             Include the contents of the given file into the page
+             returned from the cgi
 
-       RRD::GRAPH _r_r_d_g_r_a_p_h _a_r_g_u_m_e_n_t_s
-               This tag creates the RRD graph defined in its
-               argument and then gets replaced by an appropriate
-               <IMG> tag referring to the graph.  The --------llllaaaazzzzyyyy
-               option in RRD graph can be used to make sure that
-               graphs are only regenerated when they are out of
-               date. The arguments to the RRRRRRRRDDDD::::::::GGGGRRRRAAAAPPPPHHHH tag work as
-               described in the rrrrrrrrddddggggrrrraaaapppphhhh manual page.
+     RRD::SETENV _v_a_r_i_a_b_l_e _v_a_l_u_e
+             If you want to present your graphs in another time
+             zone than your own, you could use
 
-               Use the --------llllaaaazzzzyyyy option in your RRD::GRAPH tags, to
-               reduce the load on your server. This option makes
-               sure that graphs are only regenerated when the old
-               ones are out of date.
+              <RRD::SETENV TZ UTC>
 
-               If you do not specify your own --------iiiimmmmggggiiiinnnnffffoooo format,
-               the following will be used:
+             to make sure everything is presented in Universal
+             Time. Note that the values permitted to TZ depend on
+             your OS.
 
-                <IMG SRC="%s" WIDTH="%lu" HEIGHT="%lu">
+     RRD::TIME::LAST _r_r_d-_f_i_l_e _s_t_r_f_t_i_m_e-_f_o_r_m_a_t
+             This gets replaced by the last modification time of
+             the selected RRD. The time is _s_t_r_f_t_i_m_e-formated with
+             the string specified in the second argument.
 
-               Note that %s stands for the filename part of the
-               graph generated, all directories given in the GIF
-               file argument will get dropped.
+     RRD::TIME::NOW _s_t_r_f_t_i_m_e-_f_o_r_m_a_t
+             This gets replaced by the current time of day. The
+             time is _s_t_r_f_t_i_m_e-formated with the string specified
+             in the argument.
 
-       RRD::PRINT _n_u_m_b_e_r
-               If the preceding  RRRRRRRRDDDD::::::::GGGGRRRRAAAAPPPPHHHH tag contained and
-               PPPPRRRRIIIINNNNTTTT arguments, then you can access their output
-               with this tag. The _n_u_m_b_e_r argument refers to the
-               number of the PPPPRRRRIIIINNNNTTTT argument. This first PPPPRRRRIIIINNNNTTTT has
-               _n_u_m_b_e_r 0.
+     PPPPaaaassssssss 3333
 
-EEEEXXXXAAAAMMMMPPPPLLLLEEEE
-       The example below creates a web pages with a single RRD
-       graph.
+     RRD::GRAPH _r_r_d_g_r_a_p_h _a_r_g_u_m_e_n_t_s
+             This tag creates the RRD graph defined in its
+             argument and then gets replaced by an appropriate
+             <IMG> tag referring to the graph.  The --------llllaaaazzzzyyyy option
+             in RRD graph can be used to make sure that graphs
+             are only regenerated when they are out of date. The
+             arguments to the RRRRRRRRDDDD::::::::GGGGRRRRAAAAPPPPHHHH tag work as described in
+             the rrrrrrrrddddggggrrrraaaapppphhhh manual page.
 
+             Use the --------llllaaaazzzzyyyy option in your RRD::GRAPH tags, to
+             reduce the load on your server. This option makes
+             sure that graphs are only regenerated when the old
+             ones are out of date.
 
+             If you do not specify your own --------iiiimmmmggggiiiinnnnffffoooo format, the
+             following will be used:
 
+              <IMG SRC="%s" WIDTH="%lu" HEIGHT="%lu">
 
 
 
+6/Feb/2000             Last change: 1.0.13                      2
 
 
 
 
 
-9/Aug/99                      1.0.7                             2
 
+rrdtool                                                 RRDCGI(1)
 
 
 
+             Note that %s stands for the filename part of the
+             graph generated, all directories given in the GIF
+             file argument will get dropped.
 
-RRDCGI(1)                    rrdtool                    RRDCGI(1)
+     RRD::PRINT _n_u_m_b_e_r
+             If the preceding  RRRRRRRRDDDD::::::::GGGGRRRRAAAAPPPPHHHH tag contained and PPPPRRRRIIIINNNNTTTT
+             arguments, then you can access their output with
+             this tag. The _n_u_m_b_e_r argument refers to the number
+             of the PPPPRRRRIIIINNNNTTTT argument. This first PPPPRRRRIIIINNNNTTTT has _n_u_m_b_e_r
+             0.
 
+EEEEXXXXAAAAMMMMPPPPLLLLEEEE 1111
+     The example below creates a web pages with a single RRD
+     graph.
 
-        #!/usr/local/bin/rrdcgi
-        <HTML>
-        <HEAD><TITLE>RRDCGI Demo</TITLE></HEAD>
-        <BODY>
-        <H1>RRDCGI Example Page</H1>
-        <P>
-        <RRD::GRAPH demo.gif --lazy --title="Temperatures"
-                 DEF:cel=demo.rrd:exhaust:AVERAGE
-                 LINE2:cel#00a000:"D. Celsius">
+      #!/usr/local/bin/rrdcgi
+      <HTML>
+      <HEAD><TITLE>RRDCGI Demo</TITLE></HEAD>
+      <BODY>
+      <H1>RRDCGI Example Page</H1>
+      <P>
+      <RRD::GRAPH demo.gif --lazy --title="Temperatures"
+               DEF:cel=demo.rrd:exhaust:AVERAGE
+               LINE2:cel#00a000:"D. Celsius">
 
-        </P>
-        </BODY>
-        </HTML>
+      </P>
+      </BODY>
+      </HTML>
 
 
 EEEEXXXXAAAAMMMMPPPPLLLLEEEE 2222
-       This script is slightly more elaborate, it allows you to
-       run it from a form which sets RRD_NAME. RRD_NAME is then
-       used to select which RRD you want to use a source for your
-       graph.
-
-        #!/usr/local/bin/rrdcgi
-        <HTML>
-        <HEAD><TITLE>RRDCGI Demo</TITLE></HEAD>
-        <BODY>
-        <H1>RRDCGI Example Page for <RRD::CV RRD_NAME></H1>
-        <H2>Selection</H2>
-        <FORM><INPUT NAME=RRD_NAME TYPE=RADIO VALUE=roomA> Room A,
-              <INPUT NAME=RRD_NAME TYPE=RADIO VALUE=roomB> Room B.
-              <INPUT TYPE=SUBMIT></FORM>
-        <H2>Graph</H2>
-        <P>
-        <RRD::GRAPH <RRD::CV::PATH RRD_NAME>.gif --lazy
-                 --title "Temperatures for "<RRD::CV::QUOTE RRD_NAME>
-                 DEF:cel=<RRD::CV::PATH RRD_NAME>.rrd:exhaust:AVERAGE
-                 LINE2:cel#00a000:"D. Celsius">
-
-        </P>
-        </BODY>
-        </HTML>
+     This script is slightly more elaborate, it allows you to run
+     it from a form which sets RRD_NAME. RRD_NAME is then used to
+     select which RRD you want to use a source for your graph.
+
+      #!/usr/local/bin/rrdcgi
+      <HTML>
+      <HEAD><TITLE>RRDCGI Demo</TITLE></HEAD>
+      <BODY>
+      <H1>RRDCGI Example Page for <RRD::CV RRD_NAME></H1>
+      <H2>Selection</H2>
+      <FORM><INPUT NAME=RRD_NAME TYPE=RADIO VALUE=roomA> Room A,
+            <INPUT NAME=RRD_NAME TYPE=RADIO VALUE=roomB> Room B.
+            <INPUT TYPE=SUBMIT></FORM>
+      <H2>Graph</H2>
+      <P>
+      <RRD::GRAPH <RRD::CV::PATH RRD_NAME>.gif --lazy
+               --title "Temperatures for "<RRD::CV::QUOTE RRD_NAME>
+               DEF:cel=<RRD::CV::PATH RRD_NAME>.rrd:exhaust:AVERAGE
+               LINE2:cel#00a000:"D. Celsius">
+
+
+
+
+
+6/Feb/2000             Last change: 1.0.13                      3
+
+
+
+
+
+
+rrdtool                                                 RRDCGI(1)
+
+
+
+      </P>
+      </BODY>
+      </HTML>
 
 
+EEEEXXXXAAAAMMMMPPPPLLLLEEEE 3333
+     This example shows how to handle the case where the RRD,
+     graphs and cgi-bins are seperate directories
+
+      #!/.../bin/rrdcgi
+      <HTML>
+      <HEAD><TITLE>RRDCGI Demo</TITLE></HEAD>
+      <BODY>
+      <H1>RRDCGI test Page</H1>
+      <RRD::GRAPH
+       /.../web/gifs/testhvt.gif
+       --imginfo '<IMG SRC=/.../gifs/%s WIDTH=%lu HEIGHT=%lu >'
+       --lazy --start -1d --end now
+       DEF:http_src=/.../rrds/test.rrd:http_src:AVERAGE
+       AREA:http_src#00ff00:http_src
+      >
+      </BODY>
+      </HTML>
+
+     Note 1: Replace /.../ with the relevant directories
+
+     Note 2: The SRC=/.../gifs should be paths from the view of
+     the webserver/browser
+
 AAAAUUUUTTTTHHHHOOOORRRR
-       Tobias Oetiker <oetiker at ee.ethz.ch>
+     Tobias Oetiker <oetiker at ee.ethz.ch>
+
+
+
+
+
+
+
+
+
+
+
+
 
 
 
@@ -192,14 +258,14 @@
 
 
 
+6/Feb/2000             Last change: 1.0.13                      4
 
-9/Aug/99                      1.0.7                             3
 
 
 
 
 
-RRDCGI(1)                    rrdtool                    RRDCGI(1)
+rrdtool                                                 RRDCGI(1)
 
 
 
@@ -255,10 +321,10 @@
 
 
 
+6/Feb/2000             Last change: 1.0.13                      5
 
 
 
 
-9/Aug/99                      1.0.7                             4
 
 

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/rrdtool.html
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/rrdtool.html	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/rrdtool.html	Sat Jul 13 21:08:12 2002
@@ -1,11 +1,10 @@
-    <HTML> 
-	<HEAD> 
-	    <TITLE>rrdtool - round robin database tool
+<HTML>
+<HEAD>
+<TITLE>rrdtool</TITLE>
+<LINK REV="made" HREF="mailto:karrer at zinal.ee.ethz.ch">
+</HEAD>
 
-</TITLE> 
-	</HEAD>
-
-	<BODY>
+<BODY>
 
 <!-- INDEX BEGIN -->
 <!--
@@ -31,36 +30,25 @@
 <!-- INDEX END -->
 
 <P>
-<H1><A NAME="NAME">NAME
-
-</A></H1>
-rrdtool - round robin database tool
-
-
+<H1><A NAME="NAME">NAME</A></H1>
 <P>
+rrdtool - round robin database tool
 
 <P>
 <HR>
-<H1><A NAME="SYNOPSIS">SYNOPSIS
-
-</A></H1>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
 <STRONG>rrdtool</STRONG>  <STRONG>-</STRONG> | <EM>function</EM>
 
 
 
-
-<P>
-
 <P>
 <HR>
-<H1><A NAME="DESCRIPTION">DESCRIPTION
-
-</A></H1>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
 <P>
 <HR>
-<H2><A NAME="OVERVIEW">OVERVIEW
-
-</A></H2>
+<H2><A NAME="OVERVIEW">OVERVIEW</A></H2>
+<P>
 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
@@ -70,131 +58,77 @@
 generate graphical representations of the data values collected over a
 definable time period.
 
-
 <P>
-
 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
 <STRONG>rrdtool</STRONG> check the corresponding man page.
 
-
 <P>
-
 For an introduction to the usage of rrdtool make sure you check <A HREF="././rrdtutorial.html#">the rrdtutorial manpage</A>.
 
-
-<P>
-
 <P>
 <HR>
-<H2><A NAME="FUNCTIONS">FUNCTIONS
-
-</A></H2>
+<H2><A NAME="FUNCTIONS">FUNCTIONS</A></H2>
+<P>
 While the man pages talk of command line switches you have to set in order
 to make <STRONG>rrdtool</STRONG> work it is important to note that the <STRONG>rrdtool</STRONG> can be 'remote controlled' through a set of pipes. This saves a
 considerable amount of startup time when you plan to make <STRONG>rrdtool</STRONG> do a lot of things quickly. Check the section on <A HREF="#Remote_Control">Remote Control</A> further down.
 
-
-<P>
-
 <DL>
-<DT><STRONG><A NAME="item_create">create
-
-</A></STRONG><DD>
+<DT><STRONG><A NAME="item_create">create</A></STRONG><DD>
+<P>
 Set up a new Round Robin Database (RRD). Check <A HREF="././rrdcreate.html#">the rrdcreate manpage</A>.
 
-
+<DT><STRONG><A NAME="item_update">update</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_update">update
-
-</A></STRONG><DD>
 Store new data values into an RRD. Check <A HREF="././rrdupdate.html#">the rrdupdate manpage</A>.
 
-
+<DT><STRONG><A NAME="item_graph">graph</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_graph">graph
-
-</A></STRONG><DD>
 Create a graph from data stored in one or several RRD. Apart from
 generating graphs, data can also be extracted to stdout. Check <A HREF="././rrdgraph.html#">the rrdgraph manpage</A>.
 
-
+<DT><STRONG><A NAME="item_dump">dump</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_dump">dump
-
-</A></STRONG><DD>
 Dump the contents of an RRD in plain ASCII. In connection with restore you
 can use it to transport an rrd from one architecture to another. Check <A HREF="././rrddump.html#">the rrddump manpage</A>.
 
-
+<DT><STRONG><A NAME="item_restore">restore</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_restore">restore
-
-</A></STRONG><DD>
 Restore an RRD in XML format to a binary rrd ... Check <A HREF="././rrdrestore.html#">the rrdrestore manpage</A>
 
 
 
-
+<DT><STRONG><A NAME="item_fetch">fetch</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_fetch">fetch
-
-</A></STRONG><DD>
 Get data for a certain time period from a RRD. The graph function uses
 fetch to retrieve its data from an rrd. Check <A HREF="././rrdfetch.html#">the rrdfetch manpage</A>.
 
-
+<DT><STRONG><A NAME="item_tune">tune</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_tune">tune
-
-</A></STRONG><DD>
 Alter setup of an RRD. Check <A HREF="././rrdtune.html#">the rrdtune manpage</A>.
 
-
+<DT><STRONG><A NAME="item_last">last</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_last">last
-
-</A></STRONG><DD>
 Find last update time of an RRD. Check <A HREF="././rrdlast.html#">the rrdlast manpage</A>.
 
-
+<DT><STRONG><A NAME="item_rrdresize">rrdresize</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_rrdresize">rrdresize
-
-</A></STRONG><DD>
 Change the size of individual RRAs ... Dangerous! Check <A HREF="././rrdresize.html#">the rrdresize manpage</A>.
 
-
+<DT><STRONG><A NAME="item_rrdcgi">rrdcgi</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_rrdcgi">rrdcgi
-
-</A></STRONG><DD>
 This is a standalone tool for producing rrd graphs on the fly. Check
 <A HREF="././rrdcgi.html#">the rrdcgi manpage</A>.
 
-
-<P>
-
 </DL>
 <P>
 <HR>
-<H2><A NAME="HOW_DOES_RRDTOOL_WORK_">HOW DOES RRDTOOL WORK?
-
-</A></H2>
+<H2><A NAME="HOW_DOES_RRDTOOL_WORK_">HOW DOES RRDTOOL WORK?</A></H2>
 <DL>
-<DT><STRONG><A NAME="item_Data">Data acquisition
-
-</A></STRONG><DD>
+<DT><STRONG><A NAME="item_Data">Data acquisition</A></STRONG><DD>
+<P>
 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 <STRONG>rrdtool</STRONG> lets you update the logfile at any time you want. It will automatically
@@ -202,12 +136,8 @@
 value you have supplied is stored as well and is also taken into account
 when interpolating the next log entry.
 
-
+<DT><STRONG><A NAME="item_Consolidation">Consolidation</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_Consolidation">Consolidation
-
-</A></STRONG><DD>
 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
@@ -218,19 +148,13 @@
 consolidated values (see rrdcreate). You can define any number of different
 consolidation setups within one <STRONG>RRD</STRONG>. They will all be maintained on the fly when new data is loaded into the <STRONG>RRD</STRONG>.
 
-
+<DT><STRONG><A NAME="item_Round">Round Robin Archives</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_Round">Round Robin Archives
-
-</A></STRONG><DD>
 Data values of the same consolidation setup are stored into Round Robin
 Archives (<STRONG>RRA</STRONG>). This is a very efficient manner to store data for a certain amount of
 time, while using a known amount of storage space. 
 
-
 <P>
-
 It works like this: If you want to store 1000 values in 5 minute interval, <STRONG>rrdtool</STRONG> 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
@@ -239,9 +163,7 @@
 and thus keeping a log for the last two months although at a lower
 resolution.
 
-
 <P>
-
 The use of <STRONG>RRA</STRONG>s guarantees that the <STRONG>RRD</STRONG> 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
@@ -249,39 +171,27 @@
 interests you. (Maximum one minute traffic on the LAN, minimum temperature
 of the wine cellar, total minutes down time ...)
 
-
+<DT><STRONG><A NAME="item_Unknown">Unknown Data</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_Unknown">Unknown Data
-
-</A></STRONG><DD>
 As mentioned earlier, the <STRONG>RRD</STRONG> 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 <STRONG>RRD</STRONG>. Data acquisition may not be possible for one reason or an other. The <STRONG>rrdtool</STRONG> handles these situations by storing an <EM>*UNKNOWN*</EM> value into the database. The value '<EM>*UNKNOWN*</EM>' is supported through all the functions of the database. When
 consolidating the amount of <EM>*UNKNOWN*</EM> data is accumulated and when a new consolidated value is ready to be
 written to its Round Robin Archive (<STRONG>RRA</STRONG>) 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 <EM>*UNKNOWN*</EM> value will be written to the <STRONG>RRA</STRONG>.
 
-
+<DT><STRONG><A NAME="item_Graphing">Graphing</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_Graphing">Graphing
-
-</A></STRONG><DD>
 The <STRONG>rrdtool</STRONG> also allows one to generate reports in numerical and graphical form based
 on the data stored in one or several
 <STRONG>RRD</STRONG>s. The graphing feature is fully configurable. Size, color and contents of
 the graph can be defined freely. Check <A HREF="././rrdgraph.html#">the rrdgraph manpage</A>
 for more information on this.
 
-
-<P>
-
 </DL>
 <P>
 <HR>
-<H2><A NAME="REMOTE_CONTROL">REMOTE CONTROL
-
-</A></H2>
+<H2><A NAME="REMOTE_CONTROL">REMOTE CONTROL</A></H2>
+<P>
 When you start <STRONG>rrdtool</STRONG> with the command line option '<STRONG>-</STRONG>', it waits for input via standard in. With this feature you can improve
 performance by attaching <STRONG>rrdtool</STRONG> to another process (mrtg is one example) through a set of pipes. Over the
 pipes <STRONG>rrdtool</STRONG> accepts the same arguments as on the command line. When a command is
@@ -289,41 +199,25 @@
 error occurs, a line of the form '<CODE>ERROR:</CODE>  <EM>Description of error</EM>' will be printed. <STRONG>rrdtool</STRONG>
 will not abort if possible, but follow the ERROR line with an OK line.
 
-
-<P>
-
 <P>
 <HR>
-<H1><A NAME="SEE_ALSO">SEE ALSO
-
-</A></H1>
-rrdcreate, rrdupdate, rrdgraph, rrddump, rrdfetch, rrdtune, rrdlast
-
-
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
 <P>
+rrdcreate, rrdupdate, rrdgraph, rrddump, rrdfetch, rrdtune, rrdlast
 
 <P>
 <HR>
-<H1><A NAME="BUGS">BUGS
-
-</A></H1>
-Bugs ? Features !
-
-
+<H1><A NAME="BUGS">BUGS</A></H1>
 <P>
+Bugs ? Features !
 
 <P>
 <HR>
-<H1><A NAME="AUTHOR">AUTHOR
-
-</A></H1>
-Tobias Oetiker <A
-HREF="MAILTO:<oetiker at ee.ethz.ch>"><oetiker at ee.ethz.ch></A>
-
-
+<H1><A NAME="AUTHOR">AUTHOR</A></H1>
 <P>
+Tobias Oetiker &lt;<A
+HREF="mailto:oetiker at ee.ethz.ch">oetiker at ee.ethz.ch</A>&gt;
 
-</DL>
-    </BODY>
+</BODY>
 
-    </HTML>
+</HTML>

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/rrdlast.txt
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/rrdlast.txt	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/rrdlast.txt	Sat Jul 13 21:08:12 2002
@@ -1,26 +1,26 @@
 
 
 
-RRDLAST(1)                   rrdtool                   RRDLAST(1)
+rrdtool                                                RRDLAST(1)
+
 
 
 NNNNAAAAMMMMEEEE
-       rrdtool last - Return the date of the last data sample in
-       an RRRRRRRRDDDD
+     rrdtool last - Return the date of the last data sample in an
+     RRRRRRRRDDDD
 
 SSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS
-       rrrrrrrrddddttttoooooooollll llllaaaasssstttt _f_i_l_e_n_a_m_e
+     rrrrrrrrddddttttoooooooollll llllaaaasssstttt _f_i_l_e_n_a_m_e
 
 DDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
-       The llllaaaasssstttt function returns the UNIX timestamp when the RRD
-       was last updated.
+     The llllaaaasssstttt function returns the UNIX timestamp when the RRD
+     was last updated.
 
-       _f_i_l_e_n_a_m_e
-               The name of the RRRRRRRRDDDD that contains the data.
+     _f_i_l_e_n_a_m_e
+             The name of the RRRRRRRRDDDD that contains the data.
 
 AAAAUUUUTTTTHHHHOOOORRRR
-       Russ Wright <rwwright at home.com>
-
+     Russ Wright <rwwright at home.com>
 
 
 
@@ -60,7 +60,7 @@
 
 
 
+24/Oct/1999            Last change: 1.0.13                      1
 
-9/Aug/99                      1.0.7                             1
 
 

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/rrdtutorial.txt
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/rrdtutorial.txt	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/rrdtutorial.txt	Sat Jul 13 21:08:13 2002
@@ -1,1459 +1,1591 @@
 
 
 
-RRDTUTORIAL(1)               rrdtool               RRDTUTORIAL(1)
+rrdtool                                            RRDTUTORIAL(1)
+
 
 
 NNNNAAAAMMMMEEEE
-       rrdtutorial - Alex van den Bogaerdts RRDtool tutorial
+     rrdtutorial - Alex van den Bogaerdt's RRDtool tutorial
 
 DDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
-       RRDtool is written by Tobias Oetiker <oetiker at ee.ethz.ch>
-       with contributions from many people all around the world.
-       This document is written by Alex van den Bogaerdt
-       <alex at ergens.op.het.net> to help you understand what
-       RRDtool is and what it can do for you.
-
-       The documentation provided with RRDtool can be too
-       technical for some people and here we help you to
-       understand the basics in order to prepare you to read the
-       documentation yourself. It also explains the general
-       things about statistics with a focus on networking.
+     RRDtool is written by Tobias Oetiker <oetiker at ee.ethz.ch>
+     with contributions from many people all around the world.
+     This document is written by Alex van den Bogaerdt
+     <alex at ergens.op.het.net> to help you understand what RRDtool
+     is and what it can do for you.
+
+     The documentation provided with RRDtool can be too technical
+     for some people. This tutorial is here to help you
+     understand the basics of RRDtool. It should prepare you to
+     read the documentation yourself.  It also explains the
+     general things about statistics with a focus on networking.
 
 TTTTUUUUTTTTOOOORRRRIIIIAAAALLLL
-       IIIImmmmppppoooorrrrttttaaaannnntttt
+     IIIImmmmppppoooorrrrttttaaaannnntttt
+
+     Please don't skip ahead in this document!  The first part of
+     this document explains the basics and may be boring.  But if
+     you don't understand the basics, the examples will not be as
+     meaningful to you.
+
+     WWWWhhhhaaaatttt iiiissss RRRRRRRRDDDDttttoooooooollll ????
+
+     RRDtool refers to Round Robin Database tool.  Round robin is
+     a technique that works with a fixed amount of data, and a
+     pointer to the current element. Think of a circle with some
+     dots plotted on the edge, these dots are the places where
+     data can be stored. Draw an arrow from the center of the
+     circle to one of the dots, this is the pointer.  When the
+     current data is read or written, the pointer moves to the
+     next element. As we are on a circle there is no beginning
+     nor an end, you can go on and on. After a while, all the
+     available places will be used and the process automatically
+     reuses old locations. This way, the database will not grow
+     in size and therefore requires no mainenance.  RRDtool works
+     with with Round Robin Databases (RRDs). It stores and
+     retrieves data from them.
+
+     WWWWhhhhaaaatttt ddddaaaattttaaaa ccccaaaannnn bbbbeeee ppppuuuutttt iiiinnnnttttoooo aaaannnn RRRRDDDDDDDD ????
+
+     You name it, it will probably fit. You should be able to
+     measure some value at several points in time and provide
+     this information to RRDtool. If you can do this, RRDtool
+     will be able to store it. The values need to be numerical
+     but don't have to be, as opposed to MRTG, integers.
+
+     Many examples talk about SNMP which is an acronym for Simple
+     Network Management Protocol. "Simple" refers to the protocol
+     -- it does not mean it is simple to manage or monitor a
+
+
+
+24/Oct/1999            Last change: 1.0.13                      1
+
+
+
+
+
+
+rrdtool                                            RRDTUTORIAL(1)
+
+
+
+     network. After working your way through this document, you
+     should know enough to be able to understand what people are
+     talking about. For now, just realize that SNMP is a way to
+     ask devices for the values of counters they keep.  It is the
+     value from those counters that are kept in the RRD.
+
+     WWWWhhhhaaaatttt ccccaaaannnn IIII ddddoooo wwwwiiiitttthhhh tttthhhhiiiissss ttttoooooooollll ????
+
+     RRDtool originated from MRTG (Multi Router Traffic Grapher).
+     MRTG started as a tiny little script for graphing the use of
+     a connection to the Internet. MRTG evolved into a tool for
+     graphing other data sources including temperature, speed,
+     voltage, number of printouts and the like. Most likely you
+     will start to use the RRDtool to store and process data
+     collected via SNMP. The data will most likely be bytes (or
+     bits) transfered from and to a network or a computer.
+     RRDtool lets you create a database, store data in it,
+     retrieve that data and create graphs in GIF format for
+     display on a web browser. Those GIF images are dependent on
+     the data you collected and could be, for instance, an
+     overview of the average network usage, or the peaks that
+     occurred.  It can also be used to display tidal waves, solar
+     radiation, power consumption, number of visitors at an
+     exhibition, noise levels near an airport, temperature on
+     your favorite holiday location, temperature in the fridge
+     and whatever you imagination can come up with. You need a
+     sensor to measure the data and be able to feed the numbers
+     to RRDtool.
+
+     WWWWhhhhaaaatttt iiiiffff IIII ssssttttiiiillllllll hhhhaaaavvvveeee pppprrrroooobbbblllleeeemmmmssss aaaafffftttteeeerrrr rrrreeeeaaaaddddiiiinnnngggg tttthhhhiiiissss ddddooooccccuuuummmmeeeennnntttt ????
+
+     First of all: read it again! You may have missed something.
+     If you are unable to compile the sources and you have a
+     fairly common OS, it will probably not be the fault of
+     RRDtool. There may be precompiled versions around on the
+     Internet. If they come from trusted sources, get one of
+     those.  If on the other hand the program works but does not
+     give you the expected results, it will be a problem with
+     configuring it. Review your configuration and compare it
+     with the examples that follow.
+
+     There is a mailing list and an archive of it. Read the list
+     for a few weeks and search the archive. It is considered
+     rude to just ask a question without searching the archives:
+     your problem may already have been solved for somebody else!
+     This is true for most, if not all, mailing lists and not
+     only for this particular list! Look in the documentation
+     that came with RRDtool for the location and usage of the
+     list.
+
+     I suggest you take a moment to subscribe to the mailing list
+     right now by sending an email to <rrd-users-
+
+
+
+24/Oct/1999            Last change: 1.0.13                      2
+
+
+
+
+
+
+rrdtool                                            RRDTUTORIAL(1)
+
+
+
+     request at list.ee.ethz.ch> with a subject of "subscribe". If
+     you ever want to leave this list, you write an email to the
+     same address but now with a subject of "unsubscribe".
+
+     HHHHoooowwww wwwwiiiillllllll yyyyoooouuuu hhhheeeellllpppp mmmmeeee ????
+
+     By giving you some detailed descriptions with detailed
+     examples.  It is assumed that following the instructions in
+     the order presented will give you enough knowledge of
+     RRDtool to experiment for yourself.  If it doesn't work the
+     first time, don't give up. Reread the stuff that you did
+     understand, you may have missed something.  By following the
+     examples you get some hands-on experience and, even more
+     important, some background information of how it works.
+
+     You will need to know something about hexadecimal numbers.
+     If you don't then start with reading "bin_dec_hex" before
+     you continue here.
+
+     YYYYoooouuuurrrr ffffiiiirrrrsssstttt RRRRoooouuuunnnndddd RRRRoooobbbbiiiinnnn DDDDaaaattttaaaabbbbaaaasssseeee
+
+     In my opinion the best way to learn something is to actually
+     do it.  Why not start right now?  We will create a database,
+     put some values in it and extract this data again.  Your
+     output should be the same as the output that is included in
+     this document.
+
+     We will start with some easy stuff and compare a car with a
+     router, or compare kilometers (miles if you wish) with bits
+     and bytes. It's all the same: some number over some time.
+
+     Assume we have a device that transfers bytes to and from the
+     Internet.  This device keeps a counter that starts at zero
+     when it is turned on, increasing with every byte that is
+     transfered. This counter will have a maximum value, if that
+     value is reached and an extra byte is counted, the counter
+     starts all over at zero. This is the same as many counters
+     in the world such as the mileage counter in a car.  Most
+     discussions about networking talk about bits per second so
+     lets get used to that right away. Assume a byte is eight
+     bits and start to think in bits not bytes. The counter,
+     however, still counts bytes !  In the SNMP world most of the
+     counters are 32 bits. That means they are counting from 0 to
+     4294967295. We will use these values in the examples.  The
+     device, when asked, returns the current value of the
+     counter. We know the time that has passes since we last
+     asked so we now know how many bytes have been transfered
+     ***on average*** per second. This is not very hard to
+     calculate. First in words, then in calculations:
+
+     1. Take the current counter, subtract the previous value
+        from it.
+
+
+
+24/Oct/1999            Last change: 1.0.13                      3
+
+
+
+
+
+
+rrdtool                                            RRDTUTORIAL(1)
+
 
-       We first have to do some uninteresting reading folks,
-       don't skip this part! Later on, in the examples, you need
-       to know the basics.
 
-       WWWWhhhhaaaatttt iiiissss RRRRRRRRDDDDttttoooooooollll ????
+     2. Do the same with the current time and the previous time.
 
-       RRDtool means Round Robin Database tool.  Round robin is a
-       technique that works with a fixed amount of data, and a
-       pointer to the current element. Think of a circle with
-       some dots plotted on the edge, these dots are the places
-       where data can be stored. Draw an arrow from the center of
-       the circle to one of the dots, this is the pointer.  When
-       the current data is read or written, the pointer moves to
-       the next element. As we are on a circle there is no
-       beginning nor an end, you can go on and on. After a while,
-       all the available places will be used and the process
-       automatically reuses old locations.  RRDtool works with
-       with Round Robin Databases (RRDs). It stores and retrieves
-       data from them.
+     3. Divide the outcome of (1) by the outcome of (2), the
+        result is the amount of bytes per second. Multiply by
+        eight to get the number of bits per second (bps).
 
-       WWWWhhhhaaaatttt ddddaaaattttaaaa ccccaaaannnn bbbbeeee ppppuuuutttt iiiinnnnttttoooo aaaannnn RRRRDDDDDDDD ????
+       bps = (counter_now - counter_before) / (time_now - time_before) * 8
 
-       You name it, it will probably fit. You should be able to
-       measure some value at several points in time and provide
-       this to RRDtool. If you can do this, RRDtool will probably
-       be able to store it.
+     For some people it may help to translate this to a
+     automobile example:  Do not try this example, and if you do,
+     don't blame me for the results.
 
-       Many examples talk about SNMP which is an acronym for
-       Simple Network Management Protocol. The "simple" is about
-       the protocol, it does not mean it is simple to manage a
-       network. After working your way through this document, you
-       will know enough to be able to understand what people are
-       talking about. For now, just assume SNMP is a way to talk
-       to devices and ask those devices about counters they keep.
-       It is the value from those counters that are kept in the
+     People who are not used to think in kilometers per hour can
+     translate most into miles per hour by dividing km by 1.6
+     (close enough).  I will use the following abbreviations:
 
+      M:    meter
+      KM:   kilometer (= 1000 meters).
+      H:    hour
+      S:    second
+      KM/H: kilometers per hour
+      M/S:  meters per second
 
+     You're driving a car. At 12:05 you read the counter in the
+     dashboard and it tells you that the car has moved 12345 KM
+     until that moment.  At 12:10 you look again, it reads 12357
+     KM. This means you have traveled 12 KM in five minutes. A
+     scientist would translate that into meters per second and
+     this makes a nice comparison towards the problem of (bytes
+     per five minutes) versus (bits per second).
 
-9/Aug/99                      1.0.7                             1
+     We traveled 12 kilometers which is 12000 meters. We did that
+     in five minutes which translates into 300 seconds. Our speed
+     is 12000M / 300S equals 40 M/S.
 
+     We could also calculate the speed in KM/H: 12 times five
+     minutes is an hour so we have to multiply 12 KM by 12 to get
+     144 KM/H.  For our native English speaking friends: that's
+     90 MPH so don't try this example at home or where I live :)
 
+     Remember: these numbers are averages only.  There is no way
+     to figure out from the numbers, if you drove at a constant
+     speed.  There is an example later on in this tutorial that
+     explains this.
 
+     I hope you understand that there is no difference in
+     calculating M/S or bps; only the way we collect the data is
+     different. Even the K from kilo is the same as in networking
+     terms k also means 1000.
 
+     We will now create a database where we can keep all these
+     interesting numbers. The method used to start the program
 
-RRDTUTORIAL(1)               rrdtool               RRDTUTORIAL(1)
 
 
-       RRD.
+24/Oct/1999            Last change: 1.0.13                      4
 
-       WWWWhhhhaaaatttt ccccaaaannnn IIII ddddoooo wwwwiiiitttthhhh tttthhhhiiiissss ttttoooooooollll ????
 
-       RRDtool originated from MRTG (multi router traffic
-       grapher) which itself came from a tiny little script to
-       monitor the performance of a connection to the Internet.
-       Since then, MRTG has also been used for several other
-       purposes including temperature, speed, voltage, number of
-       printouts and many other things. Most likely you will
-       start to use the RRDtool to store and process data
-       collected via SNMP. The data will most likely be bytes (or
-       bits) transfered from and to a network or a computer.
-       RRDtool lets you create a database, store data in it,
-       retrieve that data and create graphs in GIF format for
-       display on a web browser. Those GIF images are dependent
-       on the data you collected and could be, for instance, an
-       overview of the average network usage, or rather the peaks
-       that occurred.  It can also be used to display tidal
-       waves, solar radiation, power consumption, number of
-       visitors at an exhibition, noise levels near an airport,
-       temperature on your favorite holiday location, temperature
-       in the fridge and whatever you imagination can come up
-       with. You need a sensor to measure the data and be able to
-       feed the numbers to RRDtool. Many devices have such a
-       sensor.
 
-       WWWWhhhhaaaatttt iiiiffff IIII ssssttttiiiillllllll hhhhaaaavvvveeee pppprrrroooobbbblllleeeemmmmssss aaaafffftttteeeerrrr rrrreeeeaaaaddddiiiinnnngggg tttthhhhiiiissss ddddooooccccuuuummmmeeeennnntttt
-       ????
 
-       More exact, after re-reading this document :) It all
-       depends on the kind of problems you have. If you are
-       unable to compile the sources and you have a fairly common
-       OS, it will probably not be the fault of RRDtool. There
-       may be precompiled versions around on the Internet. If
-       they come from trusted sources, get one of those.  If on
-       the other hand the program works but does not give you the
-       expected results, it will be a problem with configuring
-       it. Review your configuration and compare it with the
-       examples that follow.
 
-       There is a mailing list and an archive of it. Read the
-       list for a few weeks and search the archive. It is
-       considered rude to just ask a question without reading the
-       list, your problem may already have been solved for
-       somebody else and you will be helped without writing a new
-       a message at all ... This is true for most, if not all,
-       mailing lists and not only for this particular list! Look
-       in the documentation that came with RRDtool for the
-       location and usage of the list.
 
-       I suggest you take a moment to subscribe to the mailing
-       list right now by sending an email to <rrd-users-
-       request at list.ee.ethz.ch> with a subject of "subscribe". If
+rrdtool                                            RRDTUTORIAL(1)
 
 
 
-9/Aug/99                      1.0.7                             2
+     may differ slightly from OS to OS but I assume you can
+     figure it out if it works different on your OS. Make sure
+     you do not overwrite any file on your system when executing
+     the following command and type the whole line as one long
+     line (I had to split it for readability) and skip all of the
+     '\' characters.
 
+        rrdtool create test.rrd             \
+                 --start 920804400          \
+                 DS:speed:COUNTER:600:U:U   \
+                 RRA:AVERAGE:0.5:1:24       \
+                 RRA:AVERAGE:0.5:6:10
 
+     (So enter: rrdtool create test.rrd --start 920804400 DS ...)
 
+     WWWWhhhhaaaatttt hhhhaaaassss bbbbeeeeeeeennnn ccccrrrreeeeaaaatttteeeedddd ????
 
+     We created the round robin database called test (test.rrd)
+     which starts at noon the day I started (7th of march, 1999)
+     writing this document. It holds one data source (DS) named
+     "speed" that gets built from a counter. This counter is read
+     every five minutes (default) In the same database two round
+     robin archives (RRAs) are kept, one averages the data every
+     time it is read (eg there's nothing to average) and keeps 24
+     samples (24 times 5 minutes is 2 hours). The other averages
+     6 values (half hour) and contains 10 of such averages (eg 5
+     hours) The remaining options will be discussed later on.
 
-RRDTUTORIAL(1)               rrdtool               RRDTUTORIAL(1)
+     RRDtool works with special time stamps coming from the UNIX
+     world.  This time stamp is the number of seconds that passed
+     since January 1st 1970 UTC.  This time stamp is translated
+     into local time and it will therefore look different for the
+     different time zones.
 
+     Chances are that you are not in the same part of the world
+     as I am.  This means your time zone is different. In all
+     examples where I talk about time, the hours may be wrong for
+     you. This has little effect on the results of the examples,
+     just correct the hours while reading.  As an example: where
+     I will see "12:05" the UK folks will see "11:05".
 
-       you ever want to leave this list, you write an email to
-       the same address but now with a subject of "unsubscribe".
+     We now have to fill our database with some numbers. We'll
+     pretend to have read the following numbers:
 
-       HHHHoooowwww wwwwiiiillllllll yyyyoooouuuu hhhheeeellllpppp mmmmeeee ????
 
-       By giving you some detailed descriptions with detailed
-       examples.  It is assumed that following the instructions
-       in the order presented will build up enough knowledge of
-       the program to experiment for yourself.  If it doesn't
-       work the first time, don't give up. Reread the stuff that
-       you did understand, you may have missed something.  By
-       following the examples you get some hands-on experience
-       and, even more important, some background information of
-       how it works.
 
-       You will need to know something about hexadecimal numbers.
-       If you don't then start with reading "bin_dec_hex" before
-       you continue here.
 
-       YYYYoooouuuurrrr ffffiiiirrrrsssstttt RRRRoooouuuunnnndddd RRRRoooobbbbiiiinnnn DDDDaaaattttaaaabbbbaaaasssseeee
 
-       In my opinion the best way to learn something is to
-       actually do it.  Why not start right now? We will create a
-       database, put some values in it and extract this data
-       again. It is expected that you get the same results when
-       you try these examples yourself so do that.  We will start
-       with some easy stuff and compare a car with a router, or
-       compare kilometers (miles if you wish) with bits and
-       bytes. It's all the same: Some number over some time.
 
-       Assume we have a device that transfers bytes to and from
-       the Internet.  This device keeps a counter that starts at
-       zero when it is turned on, increasing with every byte that
-       is transfered. This counter will have a maximum value, if
-       that value is reached and an extra byte is counted, the
-       counter starts all over at zero. This is the same as many
-       counters in the world such as the mileage counter in a
-       car.  Most discussions about networking talk about bits
-       per second so lets get used to that right away. Assume a
-       byte is eight bits and start to think in bits not bytes.
-       The counter however still counts bytes !  In the SNMP
-       world most of the counters are 32 bits. That means they
-       are counting from 0 to 4294967295. We will use these
-       values in the examples.  The device, when asked, returns
-       the current value of the counter. We know the time that
-       has passes since we last asked so we now know how many
-       bytes have been transfered ***on average*** per second.
-       This is not very hard to calculate. First in words, then
-       in calculi:
 
-       1. Take the current counter, subtract the previous value
-          from it.
 
 
 
 
 
-9/Aug/99                      1.0.7                             3
+24/Oct/1999            Last change: 1.0.13                      5
 
 
 
 
 
-RRDTUTORIAL(1)               rrdtool               RRDTUTORIAL(1)
 
+rrdtool                                            RRDTUTORIAL(1)
 
-       2. Do the same with the current time and the previous
-          time.
 
-       3. Divide the outcome of (1) by the outcome of (2), the
-          result is the amount of bytes per second. Multiply by
-          eight to get the number of bits per second (bps).
 
-            bps = (counter_now - counter_before) / (time_now - time_before) * 8
+      12:05  12345 KM
+      12:10  12357 KM
+      12:15  12363 KM
+      12:20  12363 KM
+      12:25  12363 KM
+      12:30  12373 KM
+      12:35  12383 KM
+      12:40  12393 KM
+      12:45  12399 KM
+      12:50  12405 KM
+      12:55  12411 KM
+      13:00  12415 KM
+      13:05  12420 KM
+      13:10  12422 KM
+      13:15  12423 KM
 
+     We fill the database as follows:
 
-       For some people it may help to translate this to a
-       automobile example: Do not try this example, and if you
-       do, don't blame me for the results.
+      rrdtool update test.rrd 920804700:12345 920805000:12357 920805300:12363
+      rrdtool update test.rrd 920805600:12363 920805900:12363 920806200:12373
+      rrdtool update test.rrd 920806500:12383 920806800:12393 920807100:12399
+      rrdtool update test.rrd 920807400:12405 920807700:12411 920808000:12415
+      rrdtool update test.rrd 920808300:12420 920808600:12422 920808900:12423
 
-       People who are not used to think in kilometers per hour
-       can translate most into miles per hour by dividing km by
-       1.6 (close enough).  I will use the following
-       abbreviations:
+     This reads: update our test database with the following
+     numbers
 
-        M:    meter
-        KM:   kilometer (= 1000 meters).
-        H:    hour
-        S:    second
-        KM/H: kilometers per hour
-        M/S:  meters per second
+      time 920804700, value 12345
+      time 920805000, value 12357
 
-       You're driving a car. At 12:05 you read the counter in the
-       dashboard and it tells you that the car has moved 12345 KM
-       until that moment.  At 12:10 you look again, it reads
-       12357 KM. This means you have traveled 12 KM in five
-       minutes. A scientist would translate that into meters per
-       second and this makes a nice comparison towards the
-       problem of (bytes per five minutes) versus (bits per
-       second).
+     etcetera.
 
-       We traveled 12 kilometers which is 12000 meters. We did
-       that in five minutes which translates into 300 seconds.
-       Our speed is 12000M / 300S equals 40 M/S.
+     As you can see, it is possible to feed more than one value
+     into the database in one command. I had to stop at three for
+     readability but the real maximum is OS dependent.
 
-       We could also calculate the speed in KM/H: twelve times
-       five minutes is an hour so we have to multiply 12 KM by 12
-       to get 144 KM/H.  For our native English speaking friends:
-       this is ninety MPH and therefore not recommended to try
-       for yourself where I live :)
+     We can now retrieve the data from our database using
+     "rrdtool fetch":
 
-       Remember: these numbers are averages and there is no way
-       to figure out from the numbers we got that you drove at a
-       constant speed.
+      rrdtool fetch test.rrd AVERAGE --start 920804400 --end 920809200
 
-       I hope you understand that there is no difference in
-       calculating M/S or bps, only the way we collect the data
-       is different. Even the K from kilo is the same as in
-       networking terms k also means 1000.
+     It should return the following output:
 
+                     speed
 
 
 
-9/Aug/99                      1.0.7                             4
 
 
 
 
 
-RRDTUTORIAL(1)               rrdtool               RRDTUTORIAL(1)
 
 
-       We will now create a database where we can keep all these
-       interesting numbers. The method used to start the program
-       may differ slightly from OS to OS but I assume you can
-       figure it out if it works different on your OS. Make sure
-       you do not overwrite any file on your system when
-       executing the following command (so: first look if it's
-       safe!) and type the whole line as one long line (I had to
-       split it for readability) and skip all of the '\'
-       characters.
 
-          rrdtool create test.rrd             \
-                   --start 920804400          \
-                   DS:speed:COUNTER:600:U:U   \
-                   RRA:AVERAGE:0.5:1:24       \
-                   RRA:AVERAGE:0.5:6:10
+24/Oct/1999            Last change: 1.0.13                      6
 
-       (So enter: rrdtool create test.rrd --start 920804400 DS
-       ...)
 
-       WWWWhhhhaaaatttt hhhhaaaassss bbbbeeeeeeeennnn ccccrrrreeeeaaaatttteeeedddd ????
 
-       We created the round robin database called test (test.rrd)
-       which starts at noon the day I started (7th of march,
-       1999) writing this document. It holds one data source (DS)
-       named "speed" that gets built from a counter. This counter
-       is read every five minutes (default) In the same database
-       two round robin archives (RRAs) are kept, one averages the
-       data every time it is read (so: there's nothing to
-       average) and keeps 24 samples (24 times 5 minutes is 2
-       hours). The other averages 6 values (half hour) and
-       contains 10 of such averages (so: 5 hours) The remaining
-       options will be discussed later on.  Chances are that you
-       are not in the same part of the world as I am.  This means
-       your time zone is different. In all examples where I talk
-       about time, the hours may be wrong for you. This has
-       little effect on the results of the examples, just correct
-       the hours while reading.
 
-       We now have to fill our database with some numbers. We'll
-       pretend to have read the following numbers:
 
 
+rrdtool                                            RRDTUTORIAL(1)
 
 
 
+      920804700:       NaN
+      920805000:      0.04
+      920805300:      0.02
+      920805600:      0.00
+      920805900:      0.00
+      920806200:      0.03
+      920806500:      0.03
+      920806800:      0.03
+      920807100:      0.02
+      920807400:      0.02
+      920807700:      0.02
+      920808000:      0.01
+      920808300:      0.02
+      920808600:      0.01
+      920808900:      0.00
+      920809200:       NaN
 
+     If it doesn't, something may be wrong.  Perhaps your OS will
+     print "NaN" in a different form.  It represents "Not A
+     Number".  If your OS writes "U" or "UNKN" or something
+     similar that's okay.  If something else is wrong, it will
+     probably be due to an error you made (assuming that my
+     tutorial is correct of course :-). In that case: delete the
+     database and try again.
 
+     What this output represents will become clear in the rest of
+     the tutorial.
 
+     IIIItttt iiiissss ttttiiiimmmmeeee ttttoooo ccccrrrreeeeaaaatttteeee ssssoooommmmeeee ggggrrrraaaapppphhhhiiiiccccssss
 
+     Try the following command:
 
+      rrdtool graph speed.gif                                 \
+              --start 920804400 --end 920808000               \
+              DEF:myspeed=test.rrd:speed:AVERAGE              \
+              LINE2:myspeed#FF0000
 
+     This will create speed.gif which starts at 12:00 and ends at
+     13:00.  There is a definition of variable myspeed, it is the
+     data from RRA "speed" out of database "test.rrd". The line
+     drawn is 2 pixels high, and comes from variable myspeed. The
+     color is red.  You'll notice that the start of the graph is
+     not at 12:00 but at 12:05 and this is because we have
+     insufficient data to tell the average before that time. This
+     will only happen when you miss some samples, this will not
+     happen a lot, hopefully.
 
+     If this has worked: congratulations! If not, check what went
+     wrong.
 
+     The colors are built up from red, green and blue. For each
+     of the components, you specify how much to use in
 
 
 
+24/Oct/1999            Last change: 1.0.13                      7
 
-9/Aug/99                      1.0.7                             5
 
 
 
 
 
-RRDTUTORIAL(1)               rrdtool               RRDTUTORIAL(1)
+rrdtool                                            RRDTUTORIAL(1)
 
 
-        12:05  12345 KM
-        12:10  12357 KM
-        12:15  12363 KM
-        12:20  12363 KM
-        12:25  12363 KM
-        12:30  12373 KM
-        12:35  12383 KM
-        12:40  12393 KM
-        12:45  12399 KM
-        12:50  12405 KM
-        12:55  12411 KM
-        13:00  12415 KM
-        13:05  12420 KM
-        13:10  12422 KM
-        13:15  12423 KM
 
-       We fill the database as follows:
+     hexadecimal where 00 means not included and FF means fully
+     included.  The "color" white is a mixture of red, green and
+     blue: FFFFFF The "color" black is all colors off: 000000
 
-        rrdtool update test.rrd 920804700:12345 920805000:12357 920805300:12363
-        rrdtool update test.rrd 920805600:12363 920805900:12363 920806200:12373
-        rrdtool update test.rrd 920806500:12383 920806800:12393 920807100:12399
-        rrdtool update test.rrd 920807400:12405 920807700:12411 920808000:12415
-        rrdtool update test.rrd 920808300:12420 920808600:12422 920808900:12423
+        red     #FF0000
+        green   #00FF00
+        blue    #0000FF
+        magenta #FF00FF     (mixed red with blue)
+        gray    #555555     (one third of all components)
 
-       This reads: update our test database with the following
-       numbers
+     The GIF you just created can be displayed using your
+     favorite image viewer.  Web browsers will display the GIF
+     via the URL "file://the/path/to/speed.gif"
 
-        time 920804700, value 12345
-        time 920805000, value 12357
+     GGGGrrrraaaapppphhhhiiiiccccssss wwwwiiiitttthhhh ssssoooommmmeeee mmmmaaaatttthhhh
 
-       etcetera.
+     When looking at the image, you notice that the horizontal
+     axis is labeled 12:10, 12:20, 12:30, 12:40 and 12:50. The
+     two remaining times (12:00 and 13:00) would not be displayed
+     nicely so they are skipped.  The vertical axis displays the
+     range we entered. We provided kilometers and when divided by
+     300 seconds, we get very small numbers. To be exact, the
+     first value was 12 (12357-12345) and divided by 300 this
+     makes 0.04, which is displayed by RRDtool as "40 m" meaning
+     "40/1000". The "m" has nothing to do with meters, kilometers
+     or millimeters! RRDtool doesn't know about all this, it just
+     works with numbers and not with meters...
 
-       As you can see, it is possible to feed more than one value
-       into the database in one command. I had to stop at three
-       for readability but the real maximum will be OS dependent.
+     What we did wrong was that we should have measured in
+     meters, this would have been (12357000-12345000)/300 =
+     12000/300 = 40.
 
-       The time value may look strange to you, it is written in
-       seconds since the first of January, 1970, midnight. Don't
-       worry about this yet, just notice that there is a
-       difference of 300 in between all values.
+     Let's correct that. We could recreate our database and store
+     the correct data but there is a better way: do some
+     calculations while creating the gif file !
 
-       IIIItttt iiiissss ttttiiiimmmmeeee ttttoooo ccccrrrreeeeaaaatttteeee ssssoooommmmeeee ggggrrrraaaapppphhhhiiiiccccssss
+        rrdtool graph speed2.gif                           \
+           --start 920804400 --end 920808000               \
+           --vertical-label m/s                            \
+           DEF:myspeed=test.rrd:speed:AVERAGE              \
+           CDEF:realspeed=myspeed,1000,*                   \
+           LINE2:realspeed#FF0000
 
-       Try the following command:
+     After viewing this GIF, you notice the "m" has disappeared.
+     This it what the correct result would be. Also, a label has
+     been added to the image.  Apart from the things mentioned
+     above, the GIF should be the same.
 
-        rrdtool graph speed.gif                                 \
-                --start 920804400 --end 920808000               \
-                DEF:myspeed=test.rrd:speed:AVERAGE              \
-                LINE2:myspeed#FF0000
+     The calculations are in the CDEF part and are in Reverse
+     Polish Notation ("RPN"). What it says is: "take the data
+     source myspeed and the number 1000; multiply those". Don't
+     bother with RPN yet, it will be explained later on in more
 
-       This will create speed.gif which starts at 12:00 and ends
-       at 13:00.  There is a definition of variable myspeed, it
-       is the data from RRA "speed" out of database "test.rrd".
-       The line drawn is 2 pixels high, and comes from variable
 
 
+24/Oct/1999            Last change: 1.0.13                      8
 
-9/Aug/99                      1.0.7                             6
 
 
 
 
 
-RRDTUTORIAL(1)               rrdtool               RRDTUTORIAL(1)
+rrdtool                                            RRDTUTORIAL(1)
 
 
-       myspeed. The color is red.  You'll notice that the start
-       of the graph is not at 12:00 but at 12:05 and this is
-       because we have insufficient data to tell the average
-       before that time. This will only happen when you miss some
-       samples, this will not happen a lot, hopefully.
 
-       If this has worked: Congratulations. If not, check what
-       went wrong.
+     detail. Also, you may want to read my tutorial on CDEFs and
+     Steve Rader's tutorial on RPN. But first finish this
+     tutorial.
 
-       The colors are built up from red, green and blue. For each
-       of the components, you specify how much to use in
-       hexadecimal where 00 means not included and FF means fully
-       included.  The color white is a mixture of red, green and
-       blue: FFFFFF The color black is all colors off: 000000
-       (Please, no discussions if black and white can be called
-       colors)
+     Hang on! If we can multiply values with 1000, it should also
+     be possible to display kilometers per hour from the same
+     data!
 
-          red    #FF0000
-          green  #00FF00
-          blue   #0000FF
-          purple #FF00FF     (mixed red with blue)
-          gray   #555555     (one third of all components)
+     To change a value that is measured in meters per second:
+      -*- Calculate meters per hour:     value * 3600
+      -*- Calculate kilometers per hour: value / 1000
+      -*- Together this makes:           value * (3600/1000) ==
+     value * 3.6
 
-       The GIF you just created can be displayed using a web
-       browser or other software you like. I can not provide you
-       with an example of that, because there are too many
-       different setups, possibilities etc.
+     In our example database we made a mistake and we need to
+     compensate for this by multiplying with 1000. Applying that
+     correction:
+      -*- value * 3.6  *1000 == value * 3600
 
-       GGGGrrrraaaapppphhhhiiiiccccssss wwwwiiiitttthhhh ssssoooommmmeeee mmmmaaaatttthhhh
+     Now let's create this GIF, and add some more magic ...
 
-       When looking at the image, you notice that the horizontal
-       axis displays 12:10, 12:20, 12:30, 12:40 and 12:50. The
-       two remaining times (12:00 and 13:00) would not be
-       displayed nicely so they are skipped.  The vertical axis
-       displays the range we entered. We provided kilometers and
-       when divided by 300 seconds, we get very small numbers. To
-       be exact, the first value was 12 (12357-12345) and divided
-       by 300 this makes 0.04 RRDtool displays this as 40 m which
-       means 40 milli (so: NOT meters).  What we did wrong was
-       that we should have measured in meters, this would have
-       been (12357000-12345000)/300 = 12000/300 = 40.
+        rrdtool graph speed3.gif                           \
+           --start 920804400 --end 920808000               \
+           --vertical-label km/h                           \
+           DEF:myspeed=test.rrd:speed:AVERAGE              \
+           "CDEF:kmh=myspeed,3600,*"                       \
+           CDEF:fast=kmh,100,GT,kmh,0,IF                   \
+           CDEF:good=kmh,100,GT,0,kmh,IF                   \
+           HRULE:100#0000FF:"Maximum allowed"              \
+           AREA:good#00FF00:"Good speed"                   \
+           AREA:fast#FF0000:"Too fast"
 
-       Let's correct that. We could recreate our database and
-       store the correct data but there is another way: do some
-       calculations while creating the gif file !
+     This looks much better. Speed in KM/H and even an extra line
+     with the maximum allowed speed (on the road I travel at). I
+     also changed the colors used to display speed and changed it
+     from a line into an area.
 
-          rrdtool graph speed2.gif                           \
-             --start 920804400 --end 920808000               \
-             --vertical-label m/s                            \
-             DEF:myspeed=test.rrd:speed:AVERAGE              \
-             "CDEF:realspeed=myspeed,1000,*"                 \
-             LINE2:realspeed#FF0000
+     The calculations are more complex now. For the "good" speed
+     they are:
 
-       After viewing this GIF, you notice the "m" has
+        Check if kmh is greater than 100    ( kmh,100 ) GT
+        If so, return 0, else kmh           ((( kmh,100 ) GT ), 0, kmh) IF
 
+     For the other speed:
 
+        Check if kmh is greater than 100    ( kmh,100 ) GT
+        If so, return kmh, else return 0    ((( kmh,100) GT ), kmh, 0) IF
 
-9/Aug/99                      1.0.7                             7
 
 
 
 
 
-RRDTUTORIAL(1)               rrdtool               RRDTUTORIAL(1)
 
 
-       disappeared. This it what the correct result would be.
-       Also, a label has been added to the image.  Apart from the
-       things mentioned above, the GIF should be the same.
+24/Oct/1999            Last change: 1.0.13                      9
 
-       The calculations are done with the CDEF part. What it says
-       is: take the data source myspeed and the number 1000,
-       multiply those. The calculations are done using Reverse
-       Polish Notation. It is an easy way of performing
-       calculations after you understand it. You will, eventually
-       but for now assume it is correct what I write and just
-       keep to the examples in this file. Read the documentation
-       that came with RRDtool (look in rrdgraph.doc) when you're
-       ready for it.
 
-       Hang on! If we can multiply values with 1000, it should
-       also be possible to display kilometers per hour from the
-       same data !  What do we need to do ? If we have meters per
-       second, we can make this meters per hour by multiplying
-       the value with 3600 (there go 3600 seconds in one hour).
-       To get kilometers per hour, we need to divide by 1000.  We
-       end up with: value * 3600 / 1000 = value * 3.6 . Remember
-       we also have to correct our mistake, so it is value * 3600
-       for us.
 
-       Now let's create this GIF, and add some more magic ...
 
-          rrdtool graph speed3.gif                           \
-             --start 920804400 --end 920808000               \
-             --vertical-label km/h                           \
-             DEF:myspeed=test.rrd:speed:AVERAGE              \
-             "CDEF:kmh=myspeed,3600,*"                       \
-             CDEF:fast=kmh,100,GT,kmh,0,IF                   \
-             CDEF:good=kmh,100,GT,0,kmh,IF                   \
-             HRULE:100#0000FF:"Maximum allowed"              \
-             AREA:good#00FF00:"Good speed"                   \
-             AREA:fast#FF0000:"Too fast"
 
-       This looks much better. Speed in KM/H and even an extra
-       line with the maximum allowed speed (on the road I travel
-       at). I also changed the colors used to display speed and
-       changed it from a line into an area.
 
-       The calculations are more complex now. For the "good"
-       speed they are:
+rrdtool                                            RRDTUTORIAL(1)
 
-       +o Check if kmh is greater than 100    ( kmh,100 ) GT
 
-       +o If so, return 0, else kmh           ((( kmh,100 ) GT ),
-         0, kmh) IF
 
-       For the other speed:
+     GGGGrrrraaaapppphhhhiiiiccccssss MMMMaaaaggggiiiicccc
 
-       +o Check if kmh is greater than 100    ( kmh,100 ) GT
+     I like to believe there are virtually no limits to how
+     RRDtool graph can manipulate data. I will not explain how it
+     works, but look at the following GIF:
 
+        rrdtool graph speed4.gif                           \
+           --start 920804400 --end 920808000               \
+           --vertical-label km/h                           \
+           DEF:myspeed=test.rrd:speed:AVERAGE              \
+           "CDEF:kmh=myspeed,3600,*"                       \
+           CDEF:fast=kmh,100,GT,100,0,IF                   \
+           CDEF:over=kmh,100,GT,kmh,100,-,0,IF             \
+           CDEF:good=kmh,100,GT,0,kmh,IF                   \
+           HRULE:100#0000FF:"Maximum allowed"              \
+           AREA:good#00FF00:"Good speed"                   \
+           AREA:fast#550000:"Too fast"                     \
+           STACK:over#FF0000:"Over speed"
 
+     Let's create a quick and dirty HTML page to view three GIFs:
 
+        <HTML><HEAD><TITLE>Speed</TITLE></HEAD><BODY>
+        <IMG src="speed2.gif" alt="Speed in meters per second">
+        <BR>
+        <IMG src="speed3.gif" alt="Speed in kilometers per hour">
+        <BR>
+        <IMG src="speed4.gif" alt="Traveled too fast?">
+        </BODY></HTML>
 
-9/Aug/99                      1.0.7                             8
+     Name the file "speed.html" or similar, and view it.
 
+     Now, all you have to do is measure the values regularly and
+     update the database.  When you want to view the data,
+     recreate the GIFs and make sure to refresh them in your
+     browser. (Note: just clicking reload may not be enough;
+     Netscape in particular has a problem doing so and you'll
+     need to click reload while pressing the shift key).
 
+     UUUUppppddddaaaatttteeeessss iiiinnnn RRRReeeeaaaalllliiiittttyyyy
 
+     We've already used the "update" command: it took one or more
+     parameters in the form of "<time>:<value>". You'll be glad
+     to know that you can get the current time by filling in a
+     "N" as the time.  If you wish, you can also use the "time"
+     function in perl.  The shortest example in this doc :)
 
+        perl -e 'print time, "\n" '
 
-RRDTUTORIAL(1)               rrdtool               RRDTUTORIAL(1)
+     How you can run a program on regular intervals is OS
+     specific. But here's an example in pseudo code:
 
 
-       +o If so, return kmh, else return 0    ((( kmh,100) GT ),
-         kmh, 0) IF
 
-       GGGGrrrraaaapppphhhhiiiiccccssss MMMMaaaaggggiiiicccc
 
-       I like to believe there are virtually no limits about what
-       RRDtool can do. I will not explain how it works, but look
-       at the following GIF:
 
-          rrdtool graph speed4.gif                           \
-             --start 920804400 --end 920808000               \
-             --vertical-label km/h                           \
-             DEF:myspeed=test.rrd:speed:AVERAGE              \
-             "CDEF:kmh=myspeed,3600,*"                       \
-             CDEF:fast=kmh,100,GT,100,0,IF                   \
-             CDEF:over=kmh,100,GT,kmh,100,-,0,IF             \
-             CDEF:good=kmh,100,GT,0,kmh,IF                   \
-             HRULE:100#0000FF:"Maximum allowed"              \
-             AREA:good#00FF00:"Good speed"                   \
-             AREA:fast#550000:"Too fast"                     \
-             STACK:over#FF0000:"Over speed"
+24/Oct/1999            Last change: 1.0.13                     10
 
-       Let's create a quick and dirty HTML page to view three
-       GIFs:
 
-          <HTML><HEAD><TITLE>Speed</TITLE></HEAD><BODY>
-          <IMG src="speed2.gif" alt="Speed in meters per second">
-          <BR>
-          <IMG src="speed3.gif" alt="Speed in kilometers per hour">
-          <BR>
-          <IMG src="speed4.gif" alt="Traveled too fast?">
-          </BODY></HTML>
 
-       Name the file "speed.html" or similar, and view it.
 
-       Now, all you have to do is measure the values regularly
-       and update the database. Every time you create these three
-       GIFs and reload the page and the GIFs (better reread these
-       last three words!) you know how fast you traveled.
 
-       UUUUppppddddaaaatttteeeessss iiiinnnn RRRReeeeaaaalllliiiittttyyyy
 
-       You already looked at the "update" tool. It took one or
-       more parameters in the form of "<time>:<value>". You'll be
-       glad to know that you can get the current time by filling
-       in a "N" as the time.  If you wish, you can also use the
-       "time" function in perl.  The shortest example in this doc
-       :)
+rrdtool                                            RRDTUTORIAL(1)
 
-          perl -e 'print time, "\n" '
 
-       How you can run a program on regular intervals is OS
-       specific, so I just give you an example script in a sort
-       of pseudo code: (Do not try this with our test database,
 
+        Get the value, put it in variable "$speed"
+        rrdtool update speed.rrd N:$speed
 
+     (Do not try this with our test database, it is used in
+     further examples)
 
-9/Aug/99                      1.0.7                             9
+     This is all. Run this script every five minutes. When you
+     need to know what the graphics look like, run the examples
+     above. You could put them in a script. After running that
+     script, view index.html
 
+     SSSSoooommmmeeee wwwwoooorrrrddddssss oooonnnn SSSSNNNNMMMMPPPP
 
+     I can imagine very few people will be able to get real data
+     from their car every five minutes, all other people will
+     have to settle for some other kind of counter. You could
+     measure the number of pages printed by a printer, the coffee
+     made by the coffee machine, a device that counts the
+     electricity used, whatever. Any incrementing counter can be
+     monitored and graphed using the stuff you learned until now.
+     Later on we will also be able to monitor other types of
+     values like temperature.  Most people will use the counter
+     that keeps track of octets (bytes) transfered by a network
+     device so we have to do just that. We will start with a
+     description of how to collect data.  Some people will make a
+     remark that there are tools who can do this data collection
+     for you. They are right!  However, I feel it is important
+     that you understand they are not necessary.  When you have
+     to determine why things went wrong you need to know how they
+     work.
 
+     One tool used in the example has been talked about very
+     briefly in the beginning of this document, it is called
+     SNMP. It is a way of talking to equipment. The tool I use
+     below is called "snmpget" and this is how it works:
 
+        snmpget device password OID
 
-RRDTUTORIAL(1)               rrdtool               RRDTUTORIAL(1)
+     For device you substitute the name, or the IP address, of
+     your device.  For password you use the "community read
+     string" as it is called in the SNMP world.  For some devices
+     the default of "public" might work, however this can be
+     disabled, altered or protected for privacy and security
+     reasons.  Read the documentation that comes with your device
+     or program.
 
+     Then there is this third parameter, called OID, which means
+     "object identifier".
 
-       it is used in further examples)
+     When you start to learn about SNMP it looks very confusing.
+     It isn't all that difficult when you look at the Management
+     Information Base ("MIB").  It is an upside-down tree that
 
-          Get the value, put it in variable "$speed"
-          rrdtool update speed.rrd N:$speed
 
-       This is all. Run this script every five minutes. When you
-       need to know what the graphics look like, run the examples
-       above. You could put them in a script. After running that
-       script, view index.html
 
-       SSSSoooommmmeeee wwwwoooorrrrddddssss oooonnnn SSSSNNNNMMMMPPPP
+24/Oct/1999            Last change: 1.0.13                     11
 
-       I can imagine very few people will be able to get real
-       data from their car every five minutes, all other people
-       will have to settle for some other kind of counter. You
-       could measure the number of pages printed by the laser-jet
-       printer, the coffee made by the coffee machine, a device
-       that counts the electricity used, whatever. Just as long
-       as it is an incrementing counter that you can measure
-       regularly, you can graph it against time as we did. Most
-       people will use the counter that keeps track of octets
-       (bytes) transfered by a routing device so we have to do
-       just that. We will start with a description of how to
-       collect data.  Some people will make a remark that there
-       are tools who can do this data collection for you. They
-       are right! However, I feel it is important that you
-       understand they are not necessary. If you have to look why
-       things went wrong, you need to know how the stuff works.
 
-       One tool used in the example has been talked about very
-       briefly in the beginning of this document, it is called
-       SNMP. It is a way of talking to equipment. The tool I use
-       below is called "snmpget" and this is how it works:
 
-          snmpget device password OID
 
-       For device you substitute the name of your device, for
-       password you use the "community" as it is called. For most
-       devices "public" will do but this can be disabled, altered
-       or protected for privacy and security reasons. You will
-       need to find this out as there is no way I can tell what
-       you ( ...your device... ) are keeping a secret from me.
 
-       Then there is this third parameter, called OID.  When you
-       start to learn about SNMP it looks very confusing. It
-       isn't all that difficult when you look at the Management
-       Information Base or in short: the MIB. It is an upside-
-       down tree, with a single node as the root and from there a
-       number of branches. These branches end up in another node,
-       they branch out, etc. All the branches have a name and
-       they form the path that we follow all the way down. The
-       branches that we follow are named: iso, org, dod,
-       internet, mgmt and mib-2.  These names can also be written
-       down as numbers and are 1 3 6 1 2 1.
 
+rrdtool                                            RRDTUTORIAL(1)
 
 
-9/Aug/99                      1.0.7                            10
 
+     describes data, with a single node as the root and from
+     there a number of branches.  These branches end up in
+     another node, they branch out, etc.  All the branches have a
+     name and they form the path that we follow all the way down.
+     The branches that we follow are named: iso, org, dod,
+     internet, mgmt and mib-2.  These names can also be written
+     down as numbers and are 1 3 6 1 2 1.
 
+        iso.org.dod.internet.mgmt.mib-2 (1.3.6.1.2.1)
 
+     There is a lot of confusion about the leading dot that some
+     programs use.  There is *no* leading dot in an OID.
+     However, some programs can use above part of OIDs as a
+     default.  To indicate the difference between abbreviated
+     OIDs and full OIDs they need a leading dot when you specify
+     the complete OID.  Often those programs will leave out the
+     default portion when returning the data to you.  To make
+     things worse, they have several default prefixes ...
 
+     Right, lets continue to the start of our OID: we had
+     1.3.6.1.2.1 From there, we are especially interested in the
+     branch "interfaces" which has number 2 (eg 1.3.6.1.2.1.2 or
+     1.3.6.1.2.1.interfaces).
 
-RRDTUTORIAL(1)               rrdtool               RRDTUTORIAL(1)
+     First, we have to get some SNMP program. First look if there
+     is a pre-compiled package available for your OS. This is the
+     preferred way.  If not, you will have to get yourself the
+     sources and compile those.  The Internet is full of sources,
+     programs etc. Find information using a search engine or
+     whatever you prefer. As a suggestion: look for CMU-SNMP.  It
+     is commonly used.
 
+     Assume you got the program. First try to collect some data
+     that is available on most systems. Remember: there is a
+     short name for the part of the tree that interests us most
+     in the world we live in!
 
-          iso.org.dod.internet.mgmt.mib-2 (1.3.6.1.2.1)
+     I will use the short version as I think this document is
+     large enough as it is. If that doesn't work for you, prefix
+     with .1.3.6.1.2.1 and try again.  Also, Read The Fine
+     Manual.  Skip the parts you cannot understand yet, you
+     should be able to find out how to start the program and use
+     it.
 
-       From there, we are especially interested in the branch
-       "interfaces" which has number 2 (so: 1.3.6.1.2.1.2 or
-       1.3.6.1.2.1.interfaces).
+        snmpget myrouter public system.sysdescr.0
 
-       The SNMP programs that I know can take above path as a
-       default, so I could walk to interfaces without writing it
-       in full. To do that, the path has to be written as
-       interfaces, without a leading dot.  I could also use the
-       long form, then I need to start with a dot.
+     The device should answer with a description of itself,
+     perhaps empty.  Until you got a valid answer from a device,
+     perhaps using a different "password", or a different device,
+     there is no point in continuing.
 
-       I can intermix numbers and names as I like.  1.3.6.1.2.1
-       is the same as iso.org.dod.1.2.1 and
-       1.3.6.internet.2.mib-2 For interfaces I could write
-       "interfaces", 2, or a long version by prefixing it with
-       ".1.3.6.1.2.1.". Just try what works for you and do read
-       the manual for the version of snmpget you are using.
 
-       First, we have to get some SNMP program. First look if
-       there is a pre-compiled package available for your OS.
-       This is the preferred way.  If not, you will have to get
-       yourself the sources and compile those.  The Internet is
-       full of sources, programs etc. Find information using a
-       search engine or whatever you prefer. You are on your own
-       here, sorry.
 
-       Assume you got the program. First try to collect some data
-       that is available on most systems. Remember: there is a
-       short name for the part of the tree that interests us most
-       in the world we live in !  I will use the short version as
-       I think this document is large enough as it is. If that
-       doesn't work for you, prefix with .1.3.6.1.2.1 and try
-       again. Also, Read The Fine Manual. Skip the parts you
-       cannot understand yet, you should be able to find out how
-       to start the program and use it.
 
-          snmpget myrouter public system.sysdescr.0
 
-       The device should answer with a description of itself,
-       perhaps empty.  Until you got a valid answer from a
-       device, perhaps using a different "password", or a
-       different device, there is no point in continuing.
+24/Oct/1999            Last change: 1.0.13                     12
 
-          snmpget myrouter public interfaces.ifnumber.0
 
-       Hopefully you get a number as a result, the number of
-       interfaces.  If so, you can carry on and try a different
-       program called "snmpwalk".
 
-          snmpwalk myrouter public interfaces.iftable.ifentry.ifdescr
 
-       If it returns with a list of interfaces, you're almost
-       there.  Here's an example:
 
 
+rrdtool                                            RRDTUTORIAL(1)
 
-9/Aug/99                      1.0.7                            11
 
 
+        snmpget myrouter public interfaces.ifnumber.0
 
+     Hopefully you get a number as a result, the number of
+     interfaces.  If so, you can carry on and try a different
+     program called "snmpwalk".
 
+        snmpwalk myrouter public interfaces.iftable.ifentry.ifdescr
 
-RRDTUTORIAL(1)               rrdtool               RRDTUTORIAL(1)
+     If it returns with a list of interfaces, you're almost
+     there.  Here's an example:
+        [user at host /home/alex]$ snmpwalk cisco public 2.2.1.2
 
+        interfaces.ifTable.ifEntry.ifDescr.1 = "BRI0: B-Channel 1"
+        interfaces.ifTable.ifEntry.ifDescr.2 = "BRI0: B-Channel 2"
+        interfaces.ifTable.ifEntry.ifDescr.3 = "BRI0" Hex: 42 52 49 30
+        interfaces.ifTable.ifEntry.ifDescr.4 = "Ethernet0"
+        interfaces.ifTable.ifEntry.ifDescr.5 = "Loopback0"
 
-          [user at host /home/alex]$ snmpwalk cisco public 2.2.1.2
+     On this cisco equipment, I would like to monitor the
+     "Ethernet0" interface and see that it is number four. I try:
 
-          interfaces.ifTable.ifEntry.ifDescr.1 = "BRI0: B-Channel 1"
-          interfaces.ifTable.ifEntry.ifDescr.2 = "BRI0: B-Channel 2"
-          interfaces.ifTable.ifEntry.ifDescr.3 = "BRI0" Hex: 42 52 49 30
-          interfaces.ifTable.ifEntry.ifDescr.4 = "Ethernet0"
-          interfaces.ifTable.ifEntry.ifDescr.5 = "Loopback0"
+        [user at host /home/alex]$ snmpget cisco public 2.2.1.10.4 2.2.1.16.4
 
-       On this cisco equipment, I would like to monitor the
-       "Ethernet0" interface and see that it is number four. I
-       try:
+        interfaces.ifTable.ifEntry.ifInOctets.4 = 2290729126
+        interfaces.ifTable.ifEntry.ifOutOctets.4 = 1256486519
 
-          [user at host /home/alex]$ snmpget cisco public 2.2.1.10.4 2.2.1.16.4
+     So now I have two OIDs to monitor and they are (in full,
+     this time):
 
-          interfaces.ifTable.ifEntry.ifInOctets.4 = 2290729126
-          interfaces.ifTable.ifEntry.ifOutOctets.4 = 1256486519
+        1.3.6.1.2.1.2.2.1.10
 
-       So now I have two OIDs to monitor and they are (in full,
-       this time):
+     and
 
-          1.3.6.1.2.1.2.2.1.10
+        1.3.6.1.2.1.2.2.1.16
 
-       and
+     both with an interface number of 4.
 
-          1.3.6.1.2.1.2.2.1.16
+     Don't get fooled, this wasn't my first try. It took some
+     time for me too to understand what all these numbers mean,
+     it does help a lot when they get translated into descriptive
+     text... At least, when people are talking about MIBs and
+     OIDs you know what it's all about.  Do not forget the
+     interface number (0 if it is not interface dependent) and
+     try snmpwalk if you don't get an answer from snmpget.
 
-       both with an interface number of 4.
+     If you understand above part, and get numbers from your
+     device, continue on with this tutorial. If not, then go back
+     and re-read this part.
 
-       Don't get fooled, this wasn't my first try. It took some
-       time for me too to understand what all these numbers mean,
-       it does help a lot when they get translated into
-       descriptive text... At least, when people are talking
-       about MIBs and OIDs you know what it's all about.  Do not
-       forget the interface number (0 if it is not interface
-       dependent) and try snmpwalk if you don't get an answer
-       from snmpget.
 
-       If you understand above part, and get numbers from your
-       device, it is time to continue with the following. If not,
-       then go back.
 
-       AAAA RRRReeeeaaaallll WWWWoooorrrrlllldddd EEEExxxxaaaammmmpppplllleeee
 
-       Let the fun begin. First, create a new database. It
-       contains data from two counters, called input and output.
-       The data is put into archives that average it. They take
-       1, 6, 24 or 288 samples at a time.  They also go into
-       archives that keep the maximum numbers. This will be
-       explained later on. The time in-between samples is 300
-       seconds, a good starting point, which is the same as five
-       minutes.
 
 
 
+24/Oct/1999            Last change: 1.0.13                     13
 
 
 
-9/Aug/99                      1.0.7                            12
 
 
 
+rrdtool                                            RRDTUTORIAL(1)
 
 
-RRDTUTORIAL(1)               rrdtool               RRDTUTORIAL(1)
 
+     AAAA RRRReeeeaaaallll WWWWoooorrrrlllldddd EEEExxxxaaaammmmpppplllleeee
 
-        1 sample averaged stays 1 period of 5 minutes
-        6 samples averaged become one average on 30 minutes
-        24 samples averaged become one average on 2 hours
-        288 samples averaged become one average on 1 day
+     Let the fun begin. First, create a new database. It contains
+     data from two counters, called input and output. The data is
+     put into archives that average it. They take 1, 6, 24 or 288
+     samples at a time.  They also go into archives that keep the
+     maximum numbers. This will be explained later on. The time
+     in-between samples is 300 seconds, a good starting point,
+     which is the same as five minutes.
 
-        There are 600 samples of five minutes, together just over two days
-        There are 600 samples of 30 minutes, almost two weeks
-        There are 600 samples of 2 hours, 50 hour or almost two months
-        There are 732 samples of 1 day, just over two years
+      1 sample "averaged" stays 1 period of 5 minutes
+      6 samples averaged become one average on 30 minutes
+      24 samples averaged become one average on 2 hours
+      288 samples averaged become one average on 1 day
 
-       For people used to MRTG that even have read the manuals,
-       these numbers should look familiar...
+     Lets try to be compatible with MRTG:  MRTG stores about the
+     following amount of data:
 
-          rrdtool create myrouter.rrd         \
-                   DS:input:COUNTER:600:U:U   \
-                   DS:output:COUNTER:600:U:U  \
-                   RRA:AVERAGE:0.5:1:600      \
-                   RRA:AVERAGE:0.5:6:600      \
-                   RRA:AVERAGE:0.5:24:600     \
-                   RRA:AVERAGE:0.5:288:732    \
-                   RRA:MAX:0.5:1:600          \
-                   RRA:MAX:0.5:6:600          \
-                   RRA:MAX:0.5:24:600         \
-                   RRA:MAX:0.5:288:732
+      600 5-minute samples:    2   days and 2 hours
+      600 30-minute samples:  12.5 days
+      600 2-hour samples:     50   days
+      600 1-day samples:     732   days
 
-       Next thing to do is collect data and store it. Here is an
-       example.  It is written partially in pseudo code so you
-       will have to find out what to do exactly on your OS to
-       make it work.
+     These ranges are appended so the total amount of data kept
+     is approximately 797 days.  RRDtool stores the data
+     differently, it doesn't start the "weekly" archive where the
+     "daily" archive stopped.  For both archives the most recent
+     data will be near "now" and therefore we will need to keep
+     more data than MRTG does!
 
-          while not the end of the universe
-          do
-             get result of
-                snmpget router community 2.2.1.10.4
-             into variable $in
-             get result of
-                snmpget router community 2.2.1.16.4
-             into variable $out
+     We will need:
 
-             rrdtool update myrouter.rrd N:$in:$out
+      600 samples of 5 minutes  (2 days and 2 hours)
+      700 samples of 30 minutes (2 days and 2 hours, plus 12.5 days)
+      775 samples of 2 hours    (above + 50 days)
+      797 samples of 1 day      (above + 732 days, rounded up to 797)
 
-             wait for 5 minutes
-          done
+        rrdtool create myrouter.rrd         \
+                 DS:input:COUNTER:600:U:U   \
+                 DS:output:COUNTER:600:U:U  \
+                 RRA:AVERAGE:0.5:1:600      \
+                 RRA:AVERAGE:0.5:6:700      \
+                 RRA:AVERAGE:0.5:24:775     \
+                 RRA:AVERAGE:0.5:288:797    \
+                 RRA:MAX:0.5:1:600          \
+                 RRA:MAX:0.5:6:700          \
+                 RRA:MAX:0.5:24:775         \
+                 RRA:MAX:0.5:288:797
 
-       Then, after collecting data for a day, try to create an
-       image using:
+     Next thing to do is collect data and store it. Here is an
+     example.  It is written partially in pseudo code so you will
+     have to find out what to do exactly on your OS to make it
 
-          rrdtool graph myrouter-day.gif --start -86400 \
-                   DEF:inoctets=myrouter.rrd:input:AVERAGE \
-                   DEF:outoctets=myrouter.rrd:output:AVERAGE \
-                   AREA:inoctets#00FF00:"In traffic" \
-                   LINE1:outoctets#0000FF:"Out traffic"
 
-       This should produce a picture with one day worth of
 
+24/Oct/1999            Last change: 1.0.13                     14
 
 
-9/Aug/99                      1.0.7                            13
 
 
 
 
+rrdtool                                            RRDTUTORIAL(1)
 
-RRDTUTORIAL(1)               rrdtool               RRDTUTORIAL(1)
 
 
-       traffic.  One day is 24 hours of 60 minutes of 60 seconds:
-       24*60*60=86400, we start at now minus 86400 seconds. We
-       DEFine inoctets and outoctets as the average values from
-       the database myrouter.rrd and draw an area for the "in"
-       traffic and a line for the "out" traffic.
+     work.
 
-       View the image and keep logging for a few more days.  If
-       you like, you could try the examples from the test
-       database and see if you can play around with the options
-       and calculations.
+        while not the end of the universe
+        do
+           get result of
+              snmpget router community 2.2.1.10.4
+           into variable $in
+           get result of
+              snmpget router community 2.2.1.16.4
+           into variable $out
 
-       Suggestion:
+           rrdtool update myrouter.rrd N:$in:$out
 
-       Display in bytes per second and in bits per second. Make
-       the Ethernet graphics go red if they are over four
-       megabits per second.
+           wait for 5 minutes
+        done
 
-       CCCCoooonnnnssssoooolllliiiiddddaaaattttiiiioooonnnn FFFFuuuunnnnccccttttiiiioooonnnnssss
+     Then, after collecting data for a day, try to create an
+     image using:
 
-       A few paragraphs back I mentioned the possibility of
-       keeping the maximum values instead of the average values.
-       Let's go into this a bit more.
+        rrdtool graph myrouter-day.gif --start -86400 \
+                 DEF:inoctets=myrouter.rrd:input:AVERAGE \
+                 DEF:outoctets=myrouter.rrd:output:AVERAGE \
+                 AREA:inoctets#00FF00:"In traffic" \
+                 LINE1:outoctets#0000FF:"Out traffic"
 
-       Recall all the stuff about the speed of the car. Suppose
-       we drove at 144 KM/H during 5 minutes and then were
-       stopped by the police for 25 minutes.  At the end of the
-       lecture we would take our laptop and create+view the image
-       taken from the database. If we look at the second RRA we
-       did create, we would have the average from 6 samples. The
-       samples measured would be 144+0+0+0+0+0=144, divided by 30
-       minutes, corrected for the error by 1000, translated into
-       KM/H, with a result of 24 KM/H.  I would still get a
-       ticket but not for speeding anymore :)
+     This should produce a picture with one day worth of traffic.
+     One day is 24 hours of 60 minutes of 60 seconds:
+     24*60*60=86400, we start at now minus 86400 seconds. We
+     define (with DEFs) inoctets and outoctets as the average
+     values from the database myrouter.rrd and draw an area for
+     the "in" traffic and a line for the "out" traffic.
 
-       Obviously, in this case, we shouldn't look at the
-       averages. In some cases they are handy. If you want to
-       know how much KM you had traveled, the picture would be
-       the right one to look at. On the other hand, for the speed
-       that we traveled at, the maximum number seen is much more
-       valuable. (later we will see more types)
+     View the image and keep logging data for a few more days.
+     If you like, you could try the examples from the test
+     database and see if you can get various options and
+     calculations working.
 
-       It is the same for data. If you want to know the amount,
-       look at the averages. If you want to know the rate, look
-       at the maximum.  Over time, they will grow apart more and
-       more. In the last database we have created, there are two
-       archives that keep data per day. The archive that keeps
-       averages will show low numbers, the archive that shows
-       maxima will have higher numbers.  For my car this would
-       translate in averages per day of 96/24=4 KM/H (as I travel
-       about 94 kilometers on a day) during week days, and
-       maximum of 120 KM/H on weekdays (my top speed that I reach
-       every day).
+     Suggestion:
 
-       Big difference. Do not look at the second graph to
+     Display in bytes per second and in bits per second. Make the
+     Ethernet graphics go red if they are over four megabits per
+     second.
 
+     CCCCoooonnnnssssoooolllliiiiddddaaaattttiiiioooonnnn FFFFuuuunnnnccccttttiiiioooonnnnssss
 
+     A few paragraphs back I mentioned the possibility of keeping
+     the maximum values instead of the average values. Let's go
+     into this a bit more.
 
-9/Aug/99                      1.0.7                            14
+     Recall all the stuff about the speed of the car. Suppose we
+     drove at 144 KM/H during 5 minutes and then were stopped by
+     the police for 25 minutes.  At the end of the lecture we
 
 
 
+24/Oct/1999            Last change: 1.0.13                     15
 
 
-RRDTUTORIAL(1)               rrdtool               RRDTUTORIAL(1)
 
 
-       estimate the distances that I travel and do not look at
-       the first graph to estimate my speed. This will work if
-       the samples are close together, as they are in five
-       minutes, but not if you average.
 
-       On some days, I go for a long ride. If I go across Europe
-       and travel for over 12 hours, the first graph will rise to
-       about 60 KM/H. The second one will show 180 KM/H. This
-       means that I traveled a distance of 60 KM/H times 24 H =
-       1440 KM. I did this with a higher speed and a maximum
-       around 180 KM/H. This doesn't mean that I traveled for 8
-       hours at a constant speed of 180 KM/H !  This is a real
-       example: go with the flow through Germany and stop a few
-       times for gas and coffee. Drive slowly through Austria and
-       the Netherlands. Be careful in the mountains and villages.
-       If you would look at the graphs created from the five-
-       minute averages you would get a totally different picture.
-       You would see the same values on the average and maximum
-       graphs (provided I measured every 300 seconds).  You would
-       be able to see when I stopped, when I was in top gear,
-       when I drove over fast motor-ways etc. The granularity of
-       the data is much higher, so you can see more. However,
-       this takes 12 samples per hour, or 288 values per day, so
-       it would be too much to keep for a long period of time.
-       Therefore we average it, eventually to one value per day.
-       From this one value, we cannot see much detail.
 
-       Make sure you understand the last few paragraphs. There is
-       no value in only a line and a few axis, you need to know
-       what they mean and interpret the data in a good way. This
-       is true for all data.
+rrdtool                                            RRDTUTORIAL(1)
 
-       The biggest mistake you can make is to use the collected
-       data for something that it is not suitable for. You would
-       be better off if you would not have the graphics at all in
-       that case.
 
-       LLLLeeeetttt''''ssss rrrreeeevvvviiiieeeewwww wwwwhhhhaaaatttt yyyyoooouuuu nnnnoooowwww sssshhhhoooouuuulllldddd kkkknnnnoooowwww....
 
-       You now know how to create a database. You can put the
-       numbers in it, get them out again by creating an image, do
-       math on the data from the database and view the outcome
-       instead of the raw data.  You know about the difference
-       between averages and maxima, and when to use which (or at
-       least you have an idea).
+     would take our laptop and create+view the image taken from
+     the database. If we look at the second RRA we did create, we
+     would have the average from 6 samples. The samples measured
+     would be 144+0+0+0+0+0=144, divided by 30 minutes, corrected
+     for the error by 1000, translated into KM/H, with a result
+     of 24 KM/H.  I would still get a ticket but not for speeding
+     anymore :)
 
-       RRDtool can do more than what we have learned up to now.
-       Before you continue with the rest of this doc, I recommend
-       that you reread from the start and try some modifications
-       on the examples. Make sure you fully understand
-       everything. It will be worth the effort and helps you not
-       only with the rest of this doc but also in your day to day
-       monitoring long after you read this introduction.
+     Obviously, in this case, we shouldn't look at the averages.
+     In some cases they are handy. If you want to know how much
+     KM you had traveled, the picture would be the right one to
+     look at. On the other hand, for the speed that we traveled
+     at, the maximum number seen is much more valuable. (later we
+     will see more types)
 
+     It is the same for data. If you want to know the amount,
+     look at the averages. If you want to know the rate, look at
+     the maximum.  Over time, they will grow apart more and more.
+     In the last database we have created, there are two archives
+     that keep data per day. The archive that keeps averages will
+     show low numbers, the archive that shows maxima will have
+     higher numbers.  For my car this would translate in averages
+     per day of 96/24=4 KM/H (as I travel about 94 kilometers on
+     a day) during week days, and maximum of 120 KM/H on weekdays
+     (my top speed that I reach every day).
 
+     Big difference. Do not look at the second graph to estimate
+     the distances that I travel and do not look at the first
+     graph to estimate my speed. This will work if the samples
+     are close together, as they are in five minutes, but not if
+     you average.
 
+     On some days, I go for a long ride. If I go across Europe
+     and travel for over 12 hours, the first graph will rise to
+     about 60 KM/H. The second one will show 180 KM/H. This means
+     that I traveled a distance of 60 KM/H times 24 H = 1440 KM.
+     I did this with a higher speed and a maximum around 180
+     KM/H. This doesn't mean that I traveled for 8 hours at a
+     constant speed of 180 KM/H !  This is a real example: go
+     with the flow through Germany (fast!) and stop a few times
+     for gas and coffee. Drive slowly through Austria and the
+     Netherlands. Be careful in the mountains and villages. If
+     you would look at the graphs created from the five-minute
+     averages you would get a totally different picture. You
+     would see the same values on the average and maximum graphs
+     (provided I measured every 300 seconds).  You would be able
+     to see when I stopped, when I was in top gear, when I drove
+     over fast hiways etc. The granularity of the data is much
+     higher, so you can see more. However, this takes 12 samples
+     per hour, or 288 values per day, so it would be too much to
+     keep for a long period of time. Therefore we average it,
+     eventually to one value per day. From this one value, we
 
-9/Aug/99                      1.0.7                            15
 
 
+24/Oct/1999            Last change: 1.0.13                     16
 
 
 
-RRDTUTORIAL(1)               rrdtool               RRDTUTORIAL(1)
 
 
-       DDDDaaaattttaaaa SSSSoooouuuurrrrcccceeee TTTTyyyyppppeeeessss
 
-       All right, you feel like continuing. Welcome back and get
-       ready for an increased speed in the examples and
-       explanation.
+rrdtool                                            RRDTUTORIAL(1)
 
-       You know that in order to view a counter over time, you
-       have to take two numbers and divide the difference of them
-       between the time lapsed. This makes sense for the examples
-       I gave you but there are other possibilities. For
-       instance, I'm able to retrieve the temperature from my
-       router in three places namely the inlet, the so called
-       hot-spot and the exhaust. If I take the difference of the
-       two samples and divide that by 300 (seconds) there would
-       not be very much to display ... If there would be anything
-       to display it would be the fluctuations in the temperature
-       and if they produce noticeable results when divided by
-       300, I'd better look for a new computer room.
 
-       So, what can we do ?  RRDtool can also store the values
-       you measure directly as they are (this is not entirely
-       true but close enough). The graphs we make look much
-       better, they will show a rather constant value. I know
-       when the router is busy (it works -> it uses more
-       electricity -> it generates more heat -> the temperature
-       rises). I know when the doors are left open (the room is
-       cooled -> the warm air from the rest of the building flows
-       into the computer room -> the inlet temperature rises)
-       etc. The data type we use when creating the database
-       before was counter, we now have a different data type and
-       thus a different name for it. It is called GAUGE. There
-       are more such data types:
 
-        - COUNTER   we already know this one
-        - GAUGE     we just learned this one
-        - DERIVE
-        - ABSOLUTE
+     cannot see much detail.
 
-       The two new types are DERIVE and ABSOLUTE. Absolute can be
-       used like counter with one difference: RRDtool assumes the
-       counter is reset when it's read. That is: its delta is
-       known without calculation by RRDtool whereas RRDtool needs
-       to calculate it for the counter type.  Example: our first
-       example (12345, 12357, 12363, 12363) would read: unknown,
-       12, 6, 0. The rest of the calculations stay the same.  The
-       other one, derive, is like counter. Unlike counter, it can
-       also decrease so it can have a negative delta. Again, the
-       rest of the calculations stay the same.
+     Make sure you understand the last few paragraphs. There is
+     no value in only a line and a few axis, you need to know
+     what they mean and interpret the data in a good way. This is
+     true for all data.
 
-       Let's try them all:
+     The biggest mistake you can make is to use the collected
+     data for something that it is not suitable for. You would be
+     better off if you would not have the graphics at all in that
+     case.
 
+     LLLLeeeetttt''''ssss rrrreeeevvvviiiieeeewwww wwwwhhhhaaaatttt yyyyoooouuuu nnnnoooowwww sssshhhhoooouuuulllldddd kkkknnnnoooowwww....
 
+     You now know how to create a database. You can put the
+     numbers in it, get them out again by creating an image, do
+     math on the data from the database and view the outcome
+     instead of the raw data.  You know about the difference
+     between averages and maxima, and when to use which (or at
+     least you have an idea).
 
+     RRDtool can do more than what we have learned up to now.
+     Before you continue with the rest of this doc, I recommend
+     that you reread from the start and try some modifications on
+     the examples. Make sure you fully understand everything. It
+     will be worth the effort and helps you not only with the
+     rest of this doc but also in your day to day monitoring long
+     after you read this introduction.
 
+     DDDDaaaattttaaaa SSSSoooouuuurrrrcccceeee TTTTyyyyppppeeeessss
 
+     All right, you feel like continuing. Welcome back and get
+     ready for an increased speed in the examples and
+     explanation.
 
+     You know that in order to view a counter over time, you have
+     to take two numbers and divide the difference of them
+     between the time lapsed.  This makes sense for the examples
+     I gave you but there are other possibilities.  For instance,
+     I'm able to retrieve the temperature from my router in three
+     places namely the inlet, the so called hot-spot and the
+     exhaust.  These values are not counters.  If I take the
+     difference of the two samples and divide that by 300 seconds
+     I would be asking for the temperature change per second.
+     Hopefully this is zero! If not, the computerroom is on fire
+     :)
 
-9/Aug/99                      1.0.7                            16
+     So, what can we do ?  We can tell RRDtool to store the
+     values we measure directly as they are (this is not entirely
+     true but close enough). The graphs we make will look much
+     better, they will show a rather constant value. I know when
+     the router is busy (it works -> it uses more electricity ->
 
 
 
+24/Oct/1999            Last change: 1.0.13                     17
 
 
-RRDTUTORIAL(1)               rrdtool               RRDTUTORIAL(1)
 
 
-          rrdtool create all.rrd --start 978300900 \
-                   DS:a:COUNTER:600:U:U \
-                   DS:b:GAUGE:600:U:U \
-                   DS:c:DERIVE:600:U:U \
-                   DS:d:ABSOLUTE:600:U:U \
-                   RRA:AVERAGE:0.5:1:10
-          rrdtool update all.rrd \
-                   978301200:300:1:600:300    \
-                   978301500:600:3:1200:600   \
-                   978301800:900:5:1800:900   \
-                   978302100:1200:3:2400:1200 \
-                   978302400:1500:1:2400:1500 \
-                   978302700:1800:2:1800:1800 \
-                   978303000:2100:4:0:2100    \
-                   978303300:2400:6:600:2400  \
-                   978303600:2700:4:600:2700  \
-                   978303900:3000:2:1200:3000
-          rrdtool graph all1.gif -s 978300600 -e 978304200 -h 400 \
-                   DEF:linea=all.rrd:a:AVERAGE LINE3:linea#FF0000:"Line A" \
-                   DEF:lineb=all.rrd:b:AVERAGE LINE3:lineb#00FF00:"Line B" \
-                   DEF:linec=all.rrd:c:AVERAGE LINE3:linec#0000FF:"Line C" \
-                   DEF:lined=all.rrd:d:AVERAGE LINE3:lined#000000:"Line D"
 
 
-       RRRRRRRRDDDDttttoooooooollll uuuunnnnddddeeeerrrr tttthhhheeee MMMMiiiiccccrrrroooossssccccooooppppeeee
+rrdtool                                            RRDTUTORIAL(1)
 
 
-       +o Line A is a counter so it should continuously increment
-         and RRDtool should calculate the differences. Also,
-         RRDtool needs to divide the difference by the amount of
-         time lapsed. This should end up as a straight line at 1
-         (the deltas are 300, the time is 300).
 
-       +o Line B is of type gauge. These are "real" values so they
-         should match what we put in: a sort of a wave.
+     it generates more heat -> the temperature rises). I know
+     when the doors are left open (the room is cooled -> the warm
+     air from the rest of the building flows into the computer
+     room -> the inlet temperature rises) etc. The data type we
+     use when creating the database before was counter, we now
+     have a different data type and thus a different name for it.
+     It is called GAUGE. There are more such data types:
 
-       +o Line C is derive. It should be a counter that can
-         decrease. It does so between 2400 and 0, with 1800 in-
-         between.
+      - COUNTER   we already know this one
+      - GAUGE     we just learned this one
+      - DERIVE
+      - ABSOLUTE
 
-       +o Line D is of type absolute. This is like counter but it
-         works on values without calculating the difference. The
-         numbers are the same and as you can see (hopefully) this
-         has a different result.
+     The two new types are DERIVE and ABSOLUTE. Absolute can be
+     used like counter with one difference: RRDtool assumes the
+     counter is reset when it's read. That is: its delta is known
+     without calculation by RRDtool whereas RRDtool needs to
+     calculate it for the counter type.  Example: our first
+     example (12345, 12357, 12363, 12363) would read:  unknown,
+     12, 6, 0. The rest of the calculations stay the same.  The
+     other one, derive, is like counter. Unlike counter, it can
+     also decrease so it can have a negative delta. Again, the
+     rest of the calculations stay the same.
 
-       This translates in the following values, starting at 23:10
-       and ending at 00:10 the next day (where U means
-       unknown/unplotted):
+     Let's try them all:
 
-        - Line A:  u  u  1  1  1  1  1  1  1  1  1  u
-        - Line B:  u  1  3  5  3  1  2  4  6  4  2  u
-        - Line C:  u  u  2  2  2  0 -2 -6 -2  0  2  u
-        - Line D:  u  1  2  3  4  5  6  7  8  9 10  u
+        rrdtool create all.rrd --start 978300900 \
+                 DS:a:COUNTER:600:U:U \
+                 DS:b:GAUGE:600:U:U \
+                 DS:c:DERIVE:600:U:U \
+                 DS:d:ABSOLUTE:600:U:U \
+                 RRA:AVERAGE:0.5:1:10
+        rrdtool update all.rrd \
+                 978301200:300:1:600:300    \
+                 978301500:600:3:1200:600   \
+                 978301800:900:5:1800:900   \
+                 978302100:1200:3:2400:1200 \
+                 978302400:1500:1:2400:1500 \
+                 978302700:1800:2:1800:1800 \
+                 978303000:2100:4:0:2100    \
+                 978303300:2400:6:600:2400  \
+                 978303600:2700:4:600:2700  \
+                 978303900:3000:2:1200:3000
+        rrdtool graph all1.gif -s 978300600 -e 978304200 -h 400 \
+                 DEF:linea=all.rrd:a:AVERAGE LINE3:linea#FF0000:"Line A" \
+                 DEF:lineb=all.rrd:b:AVERAGE LINE3:lineb#00FF00:"Line B" \
+                 DEF:linec=all.rrd:c:AVERAGE LINE3:linec#0000FF:"Line C" \
+                 DEF:lined=all.rrd:d:AVERAGE LINE3:lined#000000:"Line D"
 
 
 
 
-9/Aug/99                      1.0.7                            17
 
 
 
+24/Oct/1999            Last change: 1.0.13                     18
 
 
-RRDTUTORIAL(1)               rrdtool               RRDTUTORIAL(1)
 
 
-       If your GIF shows all this, you know you have typed the
-       data correct, the RRDtool executable is working properly,
-       your viewer doesn't fool you and you successfully entered
-       the year 2000 :) You could try the same example four
-       times, each time with only one of the lines.
 
-       Let's go over the data again:
 
-       +o Line A: 300,600,900 and so on. The counter delta is a
-         constant 300 and so it the time delta. A number divided
-         by itself is always 1 (except when dividing by zero
-         which is undefined/illegal).  Why is it that the first
-         point is unknown ? We do know what we put into the
-         database ? True ! But we didn't have a value to
-         calculate the delta from so we don't know where we
-         started. It would be wrong to assume we started at zero
-         so we don't !
+rrdtool                                            RRDTUTORIAL(1)
 
-       +o Line B: There is nothing to calculate. The numbers are
-         as is.
 
-       +o Line C: Again, the start-out value is unknown. The same
-         story is valid like for line A. In this case the deltas
-         are not constant so the line is not. If we would put the
-         same numbers in the database as we did for line A, we
-         would have gotten the same line. Unlike type counter,
-         this type can decrease and I hope to show you later on
-         why there is a difference.
 
-       +o Line D: Here the device calculates the deltas. Therefore
-         we DO know the first delta and it is plotted. We had the
-         same input as with line A but the meaning of this input
-         is different. Therefore the line is different.  In this
-         case the deltas increase each time with 300. The time
-         delta stays at a constant 300 and therefore the division
-         of the two gives increasing results.
+     RRRRRRRRDDDDttttoooooooollll uuuunnnnddddeeeerrrr tttthhhheeee MMMMiiiiccccrrrroooossssccccooooppppeeee
 
-       CCCCoooouuuunnnntttteeeerrrr WWWWrrrraaaappppssss
+     +o Line A is a counter so it should continuously increment
+       and RRDtool should calculate the differences. Also,
+       RRDtool needs to divide the difference by the amount of
+       time lapsed. This should end up as a straight line at 1
+       (the deltas are 300, the time is 300).
 
-       There are a few more basics to show. Some important
-       options are still to be covered and we haven't look at
-       counter wraps yet. First the counter wrap: In our car we
-       notice that our counter shows 999987. We travel 20 KM and
-       the counter should go to 1000007. Unfortunately, there are
-       only six digits on our counter so it really shows 000007.
-       If we would plot that on a type DERIVE, it would mean that
-       the counter was set back 999980 KM. It wasn't, and there
-       has to be some protection for this. This protection is
-       only available for type COUNTER which should be used for
-       this kind of counter anyways. How does it work ? Type
-       counter should never decrease and therefore RRDtool must
-       assume it wrapped if it does decrease !  If the delta is
-       negative, this can be compensated for by adding the
-       maximum value of the counter + 1. For our car this would
+     +o Line B is of type gauge. These are "real" values so they
+       should match what we put in: a sort of a wave.
 
+     +o Line C is derive. It should be a counter that can
+       decrease. It does so between 2400 and 0, with 1800 in-
+       between.
 
+     +o Line D is of type absolute. This is like counter but it
+       works on values without calculating the difference. The
+       numbers are the same and as you can see (hopefully) this
+       has a different result.
 
-9/Aug/99                      1.0.7                            18
+     This translates in the following values, starting at 23:10
+     and ending at 00:10 the next day (where U means
+     unknown/unplotted):
 
+      - Line A:  u  u  1  1  1  1  1  1  1  1  1  u
+      - Line B:  u  1  3  5  3  1  2  4  6  4  2  u
+      - Line C:  u  u  2  2  2  0 -2 -6  2  0  2  u
+      - Line D:  u  1  2  3  4  5  6  7  8  9 10  u
 
+     If your GIF shows all this, you know you have typed the data
+     correct, the RRDtool executable is working properly, your
+     viewer doesn't fool you and you successfully entered the
+     year 2000 :)  You could try the same example four times,
+     each time with only one of the lines.
 
+     Let's go over the data again:
 
+     +o Line A: 300,600,900 and so on. The counter delta is a
+       constant 300 and so it the time delta. A number divided by
+       itself is always 1 (except when dividing by zero which is
+       undefined/illegal).  Why is it that the first point is
+       unknown ? We do know what we put into the database ? True
+       ! But we didn't have a value to calculate the delta from
+       so we don't know where we started. It would be wrong to
+       assume we started at zero so we don't !
 
-RRDTUTORIAL(1)               rrdtool               RRDTUTORIAL(1)
+     +o Line B: There is nothing to calculate. The numbers are as
+       is.
 
+     +o Line C: Again, the start-out value is unknown. The same
+       story is valid like for line A. In this case the deltas
+       are not constant so the line is not. If we would put the
 
-       be:
 
-        Delta = 7 - 999987 = -999980    (instead of 1000007-999987=20)
 
-        Real delta = -999980 + 999999 + 1 = 20
+24/Oct/1999            Last change: 1.0.13                     19
 
-       At the moment of writing this document, RRDtool knows of
-       counters that are either 32 bits or 64 bits of size. These
-       counters can handle the following different values:
 
-        - 32 bits: 0 ..           4294967295
-        - 64 bits: 0 .. 18446744073709551615
 
-       If these numbers look strange to you, you would like to
-       view them in their hexadecimal form:
 
-        - 32 bits: 0 ..         FFFFFFFF
-        - 64 bits: 0 .. FFFFFFFFFFFFFFFF
 
-       RRDtool handles both counters the same. If an overflow
-       occurs and the delta would be negative, RRDtool first adds
-       the maximum of a small counter + 1 to the delta. If the
-       delta is still negative, it had to be the large counter
-       that wrapped. Add the maximum possible value of the large
-       counter + 1 and subtract the falsely added small value.
-       There is a risk in this: suppose the large counter wrapped
-       while adding a huge delta, it could happen in theory that
-       adding the smaller value would make the delta positive. In
-       this unlikely case the results would not be correct. The
-       increase should be nearly as high as the maximum counter
-       value for that to happen so chances are you would have
-       several other problems as well and this particular problem
-       would not even be worth thinking about. Even though I did
-       include an example of it so you can judge that for
-       yourself.
 
-       The next section gives you some numerical examples for
-       counter-wraps.  Try to do the calculations yourself or
-       just believe me if your calculator can't handle the
-       numbers :)
+rrdtool                                            RRDTUTORIAL(1)
 
-       Correction numbers:
 
-        - 32 bits: (4294967295+1) =                                 4294967296
-        - 64 bits: (18446744073709551615+1)-correction1 = 18446744069414584320
 
-        Before:        4294967200
-        Increase:             100
-        Should become: 4294967300
-        But really is:          4
-        Delta:        -4294967196
-        Correction1:  -4294967196 +4294967296 = 100
+       same numbers in the database as we did for line A, we
+       would have gotten the same line. Unlike type counter, this
+       type can decrease and I hope to show you later on why
+       there is a difference.
 
+     +o Line D: Here the device calculates the deltas. Therefore
+       we DO know the first delta and it is plotted. We had the
+       same input as with line A but the meaning of this input is
+       different. Therefore the line is different.  In this case
+       the deltas increase each time with 300. The time delta
+       stays at a constant 300 and therefore the division of the
+       two gives increasing results.
 
+     CCCCoooouuuunnnntttteeeerrrr WWWWrrrraaaappppssss
 
+     There are a few more basics to show. Some important options
+     are still to be covered and we haven't look at counter wraps
+     yet. First the counter wrap:  In our car we notice that our
+     counter shows 999987. We travel 20 KM and the counter should
+     go to 1000007. Unfortunately, there are only six digits on
+     our counter so it really shows 000007. If we would plot that
+     on a type DERIVE, it would mean that the counter was set
+     back 999980 KM. It wasn't, and there has to be some
+     protection for this. This protection is only available for
+     type COUNTER which should be used for this kind of counter
+     anyways. How does it work ? Type counter should never
+     decrease and therefore RRDtool must assume it wrapped if it
+     does decrease !  If the delta is negative, this can be
+     compensated for by adding the maximum value of the counter +
+     1. For our car this would be:
 
+      Delta = 7 - 999987 = -999980    (instead of 1000007-999987=20)
 
-9/Aug/99                      1.0.7                            19
+      Real delta = -999980 + 999999 + 1 = 20
 
+     At the time of writing this document, RRDtool knows of
+     counters that are either 32 bits or 64 bits of size. These
+     counters can handle the following different values:
 
+      - 32 bits: 0 ..           4294967295
+      - 64 bits: 0 .. 18446744073709551615
 
+     If these numbers look strange to you, you would like to view
+     them in their hexadecimal form:
 
+      - 32 bits: 0 ..         FFFFFFFF
+      - 64 bits: 0 .. FFFFFFFFFFFFFFFF
 
-RRDTUTORIAL(1)               rrdtool               RRDTUTORIAL(1)
+     RRDtool handles both counters the same. If an overflow
+     occurs and the delta would be negative, RRDtool first adds
+     the maximum of a small counter + 1 to the delta. If the
+     delta is still negative, it had to be the large counter that
 
 
-        Before:        18446744073709551000
-        Increase:                       800
-        Should become: 18446744073709551800
-        But really is:                  184
-        Delta:        -18446744073709550816
-        Correction1:  -18446744073709550816 +4294967296 = -18446744069414583520
-        Correction2:  -18446744069414583520 +18446744069414584320 = 800
 
-        Before:        18446744073709551615 ( maximum value )
-        Increase:      18446744069414584320 ( absurd increase, minimum for
-        Should become: 36893488143124135935             this example to work )
-        But really is: 18446744069414584319
-        Delta:                  -4294967296
-        Correction1:  -4294967296 + 4294967296 = 0
-        (not negative -> no correction2)
+24/Oct/1999            Last change: 1.0.13                     20
 
-        Before:        18446744073709551615 ( maximum value )
-        Increase:      18446744069414584319 ( one less increase )
-        Should become: 36893488143124135934
-        But really is: 18446744069414584318
-        Delta:                  -4294967297
-        Correction1:  -4294967297 +4294967296 = -1
-        Correction2:  -1 +18446744069414584320 = 18446744069414584319
 
-       As you can see from the last two examples, you need
-       strange numbers for RRDtool to fail (provided it's bug
-       free of course) so this should not happen. However, SNMP
-       or whatever method you choose to collect the data might
-       also fail and it is not uncommon to get wrong numbers
-       occasionally. We can't prevent all errors but there are
-       some things we could do. RRDtool create takes two special
-       parameters for this. They define the minimum and maximum
-       allowed value. Until now, we made them "U" for Unknown.
-       You may (not: must) provide values for one or both of them
-       and if RRDtool receives values that are outside these
-       limits, it will ignore them. For a thermometer in degrees
-       Celsius, the absolute minimum is just under -273. For my
-       router, I can assume this minimum is much higher so I
-       would say it is 10. The maximum temperature for my router
-       I would state as 80. Any higher and the device would be
-       out of order.  For my car, I would never expect negative
-       numbers and also I would not expect numbers to be higher
-       than 230. Anything else, and there must have been an
-       error. Remember: the opposite is not true, if the numbers
-       pass this check it doesn't mean that they are correct.
-       Always judge the graph with a healthy dose of paranoia if
-       it looks weird.
 
-       DDDDaaaattttaaaa RRRReeeessssaaaammmmpppplllliiiinnnngggg
 
-       One important feature of RRDtool has not been explained
-       yet: It is virtually impossible to collect the data and
-       feed it into RRDtool on exact intervals. RRDtool therefore
-       interpolates the data so it is on exact intervals. If you
 
 
+rrdtool                                            RRDTUTORIAL(1)
 
-9/Aug/99                      1.0.7                            20
 
 
+     wrapped. Add the maximum possible value of the large counter
+     + 1 and subtract the falsely added small value.  There is a
+     risk in this: suppose the large counter wrapped while adding
+     a huge delta, it could happen in theory that adding the
+     smaller value would make the delta positive. In this
+     unlikely case the results would not be correct. The increase
+     should be nearly as high as the maximum counter value for
+     that to happen so chances are you would have several other
+     problems as well and this particular problem would not even
+     be worth thinking about. Even though I did include an
+     example of it so you can judge that for yourself.
 
+     The next section gives you some numerical examples for
+     counter-wraps.  Try to do the calculations yourself or just
+     believe me if your calculator can't handle the numbers :)
 
+     Correction numbers:
 
-RRDTUTORIAL(1)               rrdtool               RRDTUTORIAL(1)
+      - 32 bits: (4294967295+1) =                                 4294967296
+      - 64 bits: (18446744073709551615+1)-correction1 = 18446744069414584320
 
+      Before:        4294967200
+      Increase:             100
+      Should become: 4294967300
+      But really is:          4
+      Delta:        -4294967196
+      Correction1:  -4294967196 +4294967296 = 100
 
-       do not know what this means or how it works, then here's
-       the help you seek:
+      Before:        18446744073709551000
+      Increase:                       800
+      Should become: 18446744073709551800
+      But really is:                  184
+      Delta:        -18446744073709550816
+      Correction1:  -18446744073709550816 +4294967296 = -18446744069414583520
+      Correction2:  -18446744069414583520 +18446744069414584320 = 800
 
-       Suppose a counter increases with exactly one for every
-       second. You want to measure it in 300 seconds intervals.
-       You should retrieve values that are exactly 300 apart.
-       However, due to various circumstances you are a few
-       seconds late and the interval is 303. The delta will also
-       be 303 in that case. Obviously RRDtool should not put 303
-       in the database and make you believe that the counter
-       increased 303 in 300 seconds.  This is where RRDtool
-       interpolates: it alters the 303 value as if it would have
-       been stored earlier and it will be 300 in 300 seconds.
-       Next time you are at exactly the right time. This means
-       that the current interval is 297 seconds and also the
-       counter increased with 297. Again RRDtool alters the value
-       and stores 300 as it should be.
+      Before:        18446744073709551615 ( maximum value )
+      Increase:      18446744069414584320 ( absurd increase, minimum for
+      Should become: 36893488143124135935             this example to work )
+      But really is: 18446744069414584319
+      Delta:                  -4294967296
+      Correction1:  -4294967296 + 4294967296 = 0
+      (not negative -> no correction2)
 
-             in the RDD                 in real
+      Before:        18446744073709551615 ( maximum value )
+      Increase:      18446744069414584319 ( one less increase )
+      Should become: 36893488143124135934
+      But really is: 18446744069414584318
+      Delta:                  -4294967297
+      Correction1:  -4294967297 +4294967296 = -1
+      Correction2:  -1 +18446744069414584320 = 18446744069414584319
 
-        time+000:   0 delta="U"   time+000:    0 delta="U"
-        time+300: 300 delta=300   time+300:  300 delta=300
-        time+600: 600 delta=300   time+603:  603 delta=303
-        time+900: 900 delta=300   time+900:  900 delta=297
 
-       Let's create two identical databases. I've chosen the time
-       range 920805000 to 920805900 as this goes very well with
-       the example numbers.
 
-          rrdtool create seconds1.rrd   \
-             --start 920804700          \
-             DS:seconds:COUNTER:600:U:U \
-             RRA:AVERAGE:0.5:1:24
 
-          for Unix: cp seconds1.rrd seconds2.rrd
-          for Dos:  copy seconds1.rrd seconds2.rrd
-          for vms:  how would I know :)
+24/Oct/1999            Last change: 1.0.13                     21
 
-          rrdtool update seconds1.rrd \
-             920805000:000 920805300:300 920805600:600 920805900:900
-          rrdtool update seconds2.rrd \
-             920805000:000 920805300:300 920805603:603 920805900:900
 
 
 
 
 
+rrdtool                                            RRDTUTORIAL(1)
 
 
 
+     As you can see from the last two examples, you need strange
+     numbers for RRDtool to fail (provided it's bug free of
+     course) so this should not happen.  However, SNMP or
+     whatever method you choose to collect the data might also
+     report wrong numbers occasionally.  We can't prevent all
+     errors but there are some things we can do.  The RRDtool
+     "create" command takes two special parameters for this. They
+     define the minimum and maximum allowed value. Until now, we
+     used "U", meaning "unknown". If you provide values for one
+     or both of them and if RRDtool receives values that are
+     outside these limits, it will ignore those values. For a
+     thermometer in degrees Celsius, the absolute minimum is just
+     under -273. For my router, I can assume this minimum is much
+     higher so I would say it is 10. The maximum temperature for
+     my router I would state as 80. Any higher and the device
+     would be out of order.  For my car, I would never expect
+     negative numbers and also I would not expect numbers to be
+     higher than 230. Anything else, and there must have been an
+     error. Remember: the opposite is not true, if the numbers
+     pass this check it doesn't mean that they are correct.
+     Always judge the graph with a healthy dose of paranoia if it
+     looks weird.
 
+     DDDDaaaattttaaaa RRRReeeessssaaaammmmpppplllliiiinnnngggg
 
+     One important feature of RRDtool has not been explained yet:
+     It is virtually impossible to collect the data and feed it
+     into RRDtool on exact intervals. RRDtool therefore
+     interpolates the data so it is on exact intervals. If you do
+     not know what this means or how it works, then here's the
+     help you seek:
 
+     Suppose a counter increases with exactly one for every
+     second. You want to measure it in 300 seconds intervals. You
+     should retrieve values that are exactly 300 apart. However,
+     due to various circumstances you are a few seconds late and
+     the interval is 303. The delta will also be 303 in that
+     case. Obviously RRDtool should not put 303 in the database
+     and make you believe that the counter increased 303 in 300
+     seconds.  This is where RRDtool interpolates: it alters the
+     303 value as if it would have been stored earlier and it
+     will be 300 in 300 seconds.  Next time you are at exactly
+     the right time. This means that the current interval is 297
+     seconds and also the counter increased with 297. Again
+     RRDtool alters the value and stores 300 as it should be.
 
+           in the RDD                 in reality
 
+      time+000:   0 delta="U"   time+000:    0 delta="U"
+      time+300: 300 delta=300   time+300:  300 delta=300
+      time+600: 600 delta=300   time+603:  603 delta=303
+      time+900: 900 delta=300   time+900:  900 delta=297
 
 
-9/Aug/99                      1.0.7                            21
 
+24/Oct/1999            Last change: 1.0.13                     22
 
 
 
 
-RRDTUTORIAL(1)               rrdtool               RRDTUTORIAL(1)
 
 
-          rrdtool graph seconds1.gif                       \
-             --start 920804700 --end 920806200             \
-             --height 200                                  \
-             --upper-limit 1.05 --lower-limit 0.95 --rigid \
-             DEF:seconds=seconds1.rrd:seconds:AVERAGE      \
-             CDEF:unknown=seconds,UN                       \
-             LINE2:seconds#0000FF                          \
-             AREA:unknown#FF0000
-          rrdtool graph seconds2.gif                       \
-             --start 920804700 --end 920806200             \
-             --height 200                                  \
-             --upper-limit 1.05 --lower-limit 0.95 --rigid \
-             DEF:seconds=seconds2.rrd:seconds:AVERAGE      \
-             CDEF:unknown=seconds,UN                       \
-             LINE2:seconds#0000FF                          \
-             AREA:unknown#FF0000
+rrdtool                                            RRDTUTORIAL(1)
 
-       Both graphs should show the same.
+
+
+     Let's create two identical databases. I've chosen the time
+     range 920805000 to 920805900 as this goes very well with the
+     example numbers.
+
+        rrdtool create seconds1.rrd   \
+           --start 920804700          \
+           DS:seconds:COUNTER:600:U:U \
+           RRA:AVERAGE:0.5:1:24
+
+        for Unix: cp seconds1.rrd seconds2.rrd
+        for Dos:  copy seconds1.rrd seconds2.rrd
+        for vms:  how would I know :)
+
+        rrdtool update seconds1.rrd \
+           920805000:000 920805300:300 920805600:600 920805900:900
+        rrdtool update seconds2.rrd \
+           920805000:000 920805300:300 920805603:603 920805900:900
+
+        rrdtool graph seconds1.gif                       \
+           --start 920804700 --end 920806200             \
+           --height 200                                  \
+           --upper-limit 1.05 --lower-limit 0.95 --rigid \
+           DEF:seconds=seconds1.rrd:seconds:AVERAGE      \
+           CDEF:unknown=seconds,UN                       \
+           LINE2:seconds#0000FF                          \
+           AREA:unknown#FF0000
+        rrdtool graph seconds2.gif                       \
+           --start 920804700 --end 920806200             \
+           --height 200                                  \
+           --upper-limit 1.05 --lower-limit 0.95 --rigid \
+           DEF:seconds=seconds2.rrd:seconds:AVERAGE      \
+           CDEF:unknown=seconds,UN                       \
+           LINE2:seconds#0000FF                          \
+           AREA:unknown#FF0000
+
+     Both graphs should show the same.
 
 WWWWRRRRAAAAPPPPUUUUPPPP
-       It's time to wrap up this document. You now know all the
-       basics to be able to work with RRDtool and to read the
-       documentation available.  There is plenty more to discover
-       about RRDtool and you will find more and more uses for the
-       program. You could create easy graphics using just the
-       examples provided and using only RRDtool. You could also
-       use the front ends that are available.
+     It's time to wrap up this document. You now know all the
+     basics to be able to work with RRDtool and to read the
+     documentation available.  There is plenty more to discover
+     about RRDtool and you will find more and more uses for the
+     package. You could create easy graphics using just the
+     examples provided and using only RRDtool. You could also use
+     the front ends that are available.
 
 MMMMAAAAIIIILLLLIIIINNNNGGGGLLLLIIIISSSSTTTT
-       Remember to subscribe to the mailing-list. Even if you are
-       not answering the mails that come by, it helps both you
-       and the rest. A lot of the stuff that I know about MRTG
-       (and therefore about RRDtool) I've learned while just
-       reading the list without posting to it. I did not need to
-       ask the basic questions as they are answered in the FAQ
-       (so: read that too) and in various mails by other users.
-       With thousands of users all over the world, there will
-       always be people who ask questions that you can answer
-       because you read this and other documentation and they
-       didn't.
+     Remember to subscribe to the mailing-list. Even if you are
+     not answering the mails that come by, it helps both you and
+     the rest. A lot of the stuff that I know about MRTG (and
+     therefore about RRDtool) I've learned while just reading the
+     list without posting to it. I did not need to ask the basic
+
+
+
+24/Oct/1999            Last change: 1.0.13                     23
+
+
+
+
+
+
+rrdtool                                            RRDTUTORIAL(1)
+
+
+
+     questions as they are answered in the FAQ (read it!) and in
+     various mails by other users.  With thousands of users all
+     over the world, there will always be people who ask
+     questions that you can answer because you read this and
+     other documentation and they didn't.
 
 SSSSEEEEEEEE AAAALLLLSSSSOOOO
-       The RRDtool manpages
+     The RRDtool manpages
 
 AAAAUUUUTTTTHHHHOOOORRRR
-       I hope you enjoyed the examples and their descriptions. If
-       you do, help other people by pointing them to this
-       document when they are asking basic questions. They will
-       not only get their answer but at the same time learn a
-       whole lot more.
+     I hope you enjoyed the examples and their descriptions. If
+     you do, help other people by pointing them to this document
+     when they are asking basic questions. They will not only get
+     their answer but at the same time learn a whole lot more.
+
+     Alex van den Bogaerdt <alex at ergens.op.het.net>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 
-       Alex van den Bogaerdt <alex at ergens.op.het.net>
 
 
 
 
+24/Oct/1999            Last change: 1.0.13                     24
 
-9/Aug/99                      1.0.7                            22
 
 
 
 
 
-RRDTUTORIAL(1)               rrdtool               RRDTUTORIAL(1)
+rrdtool                                            RRDTUTORIAL(1)
 
 
 
@@ -1509,10 +1641,10 @@
 
 
 
+24/Oct/1999            Last change: 1.0.13                     25
 
 
 
 
-9/Aug/99                      1.0.7                            23
 
 

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/rrdgraph.pod
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/rrdgraph.pod	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/rrdgraph.pod	Sat Jul 13 21:08:13 2002
@@ -107,7 +107,7 @@
 at noon. By defining a precision of 24 hours or rather 86400 seconds,
 you make sure that this happens.
 
-=item B<-y>B<--y-grid> I<grid step>:I<label factor> (default autoconfigure)
+=item B<-y>|B<--y-grid> I<grid step>:I<label factor> (default autoconfigure)
 
 Makes vertical grid lines appear at I<grid step> interval. Every
 I<label factor> gridstep, a major grid line is printed, along with
@@ -178,13 +178,22 @@
 
 =item B<-u>|B<--upper-limit> I<value> (default autoconfigure)
 
-The maximum value to be graphed. By default This will be
-autoconfigured from the data you select with the graphing functions.
+This is not the upper limit of a graph!  But rather, this is the
+minimum upper bound of a graph.  Use this to expand graphs up.
+For example, the value 100 will result in graphs that have a upper
+bound of 100 or more.  Setting the upper limit to the maximum value
+for some DS will result in disabling RRDtool's autoscaling down (ie
+it will "expand" graphs up.)  To disable RRDtool's autoscaling up
+(to the max value for the DSs graphed), use a nifty CDEF like so:
+CDEF:mcpu=cpu,100,GT,100,cpu,IF.  If this CDEF is applied to all DSs
+in a graph, then the graph will have an upper limit of 100.
 
 =item B<-l>|B<--lower-limit> I<value> (default autoconfigure)
 
-The minimum value to be graphed. By default This will be
-autoconfigured from the data you select with the graphing functions.
+This is not the lower limit of a graph.  But rather, this is the
+maximum lower bound of a graph.  For example, the value -100 will
+result in a graph that has a lower limit of -100 or less.  Use this
+keyword to expand graphs down.
 
 =item B<-r>|B<--rigid>
 
@@ -218,11 +227,11 @@
 
 Define virtual name for a data source. This name can then be used
 in the functions explained below. The
-DEF call automatically chooses an B<RRA> which provides data in a
+DEF call automatically chooses an B<RRA> which contains I<CF> consolidated data in a
 resolution appropriate for the size of the graph to be drawn.  Ideally
 this means that one data point from the B<RRA> should be represented
 by one pixel in the graph.  If the resolution of the B<RRA> is higher
-than the resolution of the graph, the data in the RRA will be
+than the resolution of the graph, the data in the RRA will be further
 consolidated according to the consolidation function (I<CF>) chosen.
 
 =item B<CDEF:>I<vname>B<=>I<rpn-expression>
@@ -298,6 +307,12 @@
 
 Push an I<*UNKNOWN*> value onto the stack.
 
+=item PREV
+
+Push I<*UNKNOWN*> if its at the first value of a data set or otherwise
+the value of this CDEF at the previous time step. This allows you to
+perform calculations across the data.
+
 =item INF, NEGINF
 
 Push a positive or negative infinite (oo) value onto the stack. When
@@ -386,32 +401,43 @@
  
 =back
 
-=head1 NOTE
+=head1 NOTES on legend arguments
+
+=head2 Escaping the colon
 
 In a ':' in a I<legend> argument will mark the end of the legend. To
 enter a ':' into a legend, the colon must be escaped with a backslash '\:'.
 Beware, that many environments look for backslashes themselves, so it may
 be necessary to write two backslashes so that one is passed onto rrd_graph.
 
-=head1 NOTE 2
+=head2 String Formatting
 
 The text printed below the actual graph can be formated by appending special
 escaped characters at the end of a text. When ever such a character occurs,
-all pending text is pushed onto the graph according to the character specified.
+all pending text is pushed onto the graph according to the character
+specified.
 
-Valid characters are: B<j> for justified, B<l> for left aligned, B<r>
-for right aligned and B<c> for centered. In the next section there is an example
-showing how to use centered formating. 
+Valid markers are: B<\j> for justified, B<\l> for left aligned, B<\r> for
+right aligned and B<\c> for centered. In the next section there is an
+example showing how to use centered formating.
+
+Normally there are two space characters inserted between every two items
+printed into the graph. The space following a string can be suppressed by
+putting a B<\g> at the end of the string. The B<\g> also squshes any space
+inside the string if it is at the very end of the string. This can be used
+in connection with B<%s> to supress empty unit strings.
 
-A special case is COMMENT:\s this inserts some additional vertical space before
-placing the next row of legends. 
+ GPRINT:a:MAX:%lf%s\g
+ 
+A special case is COMMENT:B<\s> this inserts some additional vertical space
+before placing the next row of legends.
 
-=head1 NOTE 3
+=head1 NOTE on Return Values
 
 Whenever rrd_graph gets called, it prints a line telling the size of
 the gif it has just created to STDOUT. This line looks like this: XSIZExYSIZE.
 
-=head1 EXAMPLE
+=head1 EXAMPLE 1
 
   rrdtool graph demo.gif --title="Demo Graph" \
           DEF:cel=demo.rrd:exhaust:AVERAGE \
@@ -419,7 +445,7 @@
           LINE2:cel#00a000:"D. Celsius" \
           LINE2:far#ff0000:"D. Fahrenheit\c"
 
-=head1 EXAMPLE2
+=head1 EXAMPLE 2
 
 This example demonstrates the syntax for using IF and UN to set
 I<*UNKNOWN*> values to 0.  This technique is useful if you are
@@ -445,7 +471,7 @@
 real value like 7942099, then the stack would have 0,0,7942099 and the
 real value would be the replacement.  
 
-=head1 EXAMPLE3
+=head1 EXAMPLE 3
 
 This example shows two ways to use the INF function. First it makes
 the background change color during half of the hours. Then, it uses
@@ -475,18 +501,18 @@
 checking the outcome of sum(val1,val2,val3,val4). Again, INF is returned when
 the condition is true, UNKN is used to not plot the data.
 
-The different items are plotted in a particular order. First do the background,+then use a
-normal area to overlay it with data. Stack the other data until they+are all plotted. Last but
+The different items are plotted in a particular order. First do the background, then use a
+normal area to overlay it with data. Stack the other data until they are all plotted. Last but
 not least, overlay everything with eye-hurting red
 to signal any unknown data.
 
 Note that this example assumesthat your data is in the positive half of the y-axis
 otherwhise you would would have to add NEGINF in order to extend the coverage
 of the rea to whole graph.
-  
+
 =head1 AUTHOR
 
-Tobias Oetiker <oetiker at ee.ethz.ch>
+Tobias Oetiker E<lt>oetiker at ee.ethz.chE<gt>
 
 =head1 REFERENCES
 

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/rrdcgi.pod
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/rrdcgi.pod	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/rrdcgi.pod	Sat Jul 13 21:08:14 2002
@@ -23,10 +23,6 @@
 
 =over 8
 
-=item B<--goodfor>|B<-g> I<seconds>
-
-Specify the number of seconds this page should remain valid. This will prompt
-the rrdcgi to output a Last-Modified and a Expire header.
 
 =item B<--filter>
 
@@ -66,10 +62,36 @@
 
 =over 8
 
+=item RRD::GOODFOR I<seconds>
+
+Specify the number of seconds this page should remain valid. This will prompt
+the rrdcgi to output a Last-Modified, an Expire and if the number of
+seconds is I<negative> a Refresh headers.
+
 =item RRD::INCLUDE I<filename>
 
 Include the contents of the given file into the page returned from the cgi
 
+=item RRD::SETENV I<variable> I<value>
+
+If you want to present your graphs in another time zone than your own, you
+could use
+
+ <RRD::SETENV TZ UTC>
+
+to make sure everything is presented in Universal Time. Note that the
+values permitted to TZ depend on your OS.
+
+=item RRD::TIME::LAST I<rrd-file> I<strftime-format>
+
+This gets replaced by the last modification time of the selected RRD. The
+time is I<strftime>-formated with the string specified in the second argument.
+
+=item RRD::TIME::NOW I<strftime-format>
+
+This gets replaced by the current time of day. The
+time is I<strftime>-formated with the string specified in the argument.
+
 =back
 
 =head2 Pass 3
@@ -104,7 +126,7 @@
 
 =back
 
-=head1 EXAMPLE
+=head1 EXAMPLE 1
 
 The example below creates a web pages with a single RRD graph.
 
@@ -148,6 +170,31 @@
  </BODY>
  </HTML>
 
+=head1 EXAMPLE 3
+
+This example shows how to handle the case where the RRD, graphs and
+cgi-bins are seperate directories
+
+ #!/.../bin/rrdcgi
+ <HTML>
+ <HEAD><TITLE>RRDCGI Demo</TITLE></HEAD>
+ <BODY>
+ <H1>RRDCGI test Page</H1>
+ <RRD::GRAPH
+  /.../web/gifs/testhvt.gif
+  --imginfo '<IMG SRC=/.../gifs/%s WIDTH=%lu HEIGHT=%lu >'
+  --lazy --start -1d --end now
+  DEF:http_src=/.../rrds/test.rrd:http_src:AVERAGE
+  AREA:http_src#00ff00:http_src
+ >
+ </BODY>
+ </HTML>
+
+Note 1: Replace /.../ with the relevant directories
+
+Note 2: The SRC=/.../gifs should be paths from the view of the
+webserver/browser
+
 =head1 AUTHOR
 
 Tobias Oetiker E<lt>oetiker at ee.ethz.chE<gt>

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/rrddump.txt
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/rrddump.txt	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/rrddump.txt	Sat Jul 13 21:08:14 2002
@@ -1,29 +1,29 @@
 
 
 
-RRDDUMP(1)                   rrdtool                   RRDDUMP(1)
+rrdtool                                                RRDDUMP(1)
+
 
 
 NNNNAAAAMMMMEEEE
-       rrdtool dump - dump the contents of an RRRRRRRRDDDD to XML format
+     rrdtool dump - dump the contents of an RRRRRRRRDDDD to XML format
 
 SSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS
-       rrrrrrrrddddttttoooooooollll dddduuuummmmpppp _f_i_l_e_n_a_m_e_._r_r_d > _f_i_l_e_n_a_m_e_._x_m_l
+     rrrrrrrrddddttttoooooooollll dddduuuummmmpppp _f_i_l_e_n_a_m_e._r_r_d > _f_i_l_e_n_a_m_e._x_m_l
 
 DDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
-       The dddduuuummmmpppp function prints the contents of an RRRRRRRRDDDD in human
-       readable (?) XML format. This format can be read by
-       rrdrestore.  Together they allow you to transfer your
-       files from one architecture to another as well as
-       manipulating the contents of an RRRRRRRRDDDD file in a somewhat
-       more convenient manner.
+     The dddduuuummmmpppp function prints the contents of an RRRRRRRRDDDD in human
+     readable (?) XML format. This format can be read by
+     rrdrestore.  Together they allow you to transfer your files
+     from one architecture to another as well as manipulating the
+     contents of an RRRRRRRRDDDD file in a somewhat more convenient
+     manner.
 
-       _f_i_l_e_n_a_m_e_._r_r_d
-               The name of the RRRRRRRRDDDD you want to dump.
+     _f_i_l_e_n_a_m_e._r_r_d
+             The name of the RRRRRRRRDDDD you want to dump.
 
 AAAAUUUUTTTTHHHHOOOORRRR
-       Tobias Oetiker <oetiker at ee.ethz.ch>
-
+     Tobias Oetiker <oetiker at ee.ethz.ch>
 
 
 
@@ -60,7 +60,7 @@
 
 
 
+24/Oct/1999            Last change: 1.0.13                      1
 
-9/Aug/99                      1.0.7                             1
 
 

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/rrdtutorial.pod
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/rrdtutorial.pod	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/rrdtutorial.pod	Sat Jul 13 21:08:14 2002
@@ -1,6 +1,6 @@
 =head1 NAME
 
-rrdtutorial - Alex van den Bogaerdts RRDtool tutorial
+rrdtutorial - Alex van den Bogaerdt's RRDtool tutorial
 
 =head1 DESCRIPTION
 
@@ -10,20 +10,22 @@
 understand what RRDtool is and what it can do for you.
 
 The documentation provided with RRDtool can be too technical for some
-people and here we help you to understand the basics in order to
-prepare you to read the documentation yourself. It also explains the
-general things about statistics with a focus on networking.
+people. This tutorial is here to help you understand the basics of
+RRDtool. It should prepare you to read the documentation yourself.
+It also explains the general things about statistics with a focus on
+networking.
 
 =head1 TUTORIAL
 
 =head2 Important
 
-We first have to do some uninteresting reading folks, don't skip this
-part! Later on, in the examples, you need to know the basics.
+Please don't skip ahead in this document!  The first part of this
+document explains the basics and may be boring.  But if you don't
+understand the basics, the examples will not be as meaningful to you.
 
 =head2 What is RRDtool ?
 
-RRDtool means Round Robin Database tool.
+RRDtool refers to Round Robin Database tool.
 Round robin is a technique that works with a fixed amount of data, and a
 pointer to the current element. Think of a circle with some dots plotted
 on the edge, these dots are the places where data can be stored. Draw an
@@ -31,60 +33,60 @@
 When the current data is read or written, the pointer moves to the next
 element. As we are on a circle there is no beginning nor an end, you can
 go on and on. After a while, all the available places will be used and
-the process automatically reuses old locations.
+the process automatically reuses old locations. This way, the database
+will not grow in size and therefore requires no mainenance.
 RRDtool works with with Round Robin Databases (RRDs). It stores and retrieves
 data from them.
 
 =head2 What data can be put into an RDD ?
 
 You name it, it will probably fit. You should be able to measure some value
-at several points in time and provide this to RRDtool. If you can do this,
-RRDtool will probably be able to store it.
+at several points in time and provide this information to RRDtool. If you
+can do this, RRDtool will be able to store it. The values need to be
+numerical but don't have to be, as opposed to MRTG, integers.
 
 Many examples talk about SNMP which is an acronym for
-Simple Network Management Protocol. The "simple" is about the protocol,
-it does not mean it is simple to manage a network. After working your
-way through this document, you will know enough to be able to understand
-what people are talking about. For now, just assume SNMP is a way to
-talk to devices and ask those devices about counters they keep.
+Simple Network Management Protocol. "Simple" refers to the protocol --
+it does not mean it is simple to manage or monitor a network. After working your
+way through this document, you should know enough to be able to understand
+what people are talking about. For now, just realize that SNMP is a way to
+ask devices for the values of counters they keep.
 It is the value from those counters that are kept in the RRD.
 
 =head2 What can I do with this tool ?
 
-RRDtool originated from MRTG (multi router traffic grapher) which itself
-came from a tiny little script to monitor the performance of a connection
-to the Internet. Since then, MRTG has also been used for several other
-purposes including temperature, speed, voltage, number of printouts and
-many other things. Most likely you will start to use the RRDtool to store
+RRDtool originated from MRTG (Multi Router Traffic Grapher).  MRTG started
+as a tiny little script for graphing the use of a connection
+to the Internet. MRTG evolved into a tool for graphing other data sources
+including temperature, speed, voltage, number of printouts and
+the like. Most likely you will start to use the RRDtool to store
 and process data collected via SNMP. The data will most likely be bytes
 (or bits) transfered from and to a network or a computer.
 RRDtool lets you create a database, store data in it, retrieve that data
 and create graphs in GIF format for display on a web browser. Those GIF
 images are dependent on the data you collected and could be, for instance,
-an overview of the average network usage, or rather the peaks that occurred.
+an overview of the average network usage, or the peaks that occurred.
 It can also be used to display tidal waves, solar radiation, power
 consumption, number of visitors at an exhibition, noise levels near an
 airport, temperature on your favorite holiday location, temperature in the
 fridge and whatever you imagination can come up with. You need a sensor to
-measure the data and be able to feed the numbers to RRDtool. Many devices
-have such a sensor.
+measure the data and be able to feed the numbers to RRDtool.
 
 =head2 What if I still have problems after reading this document ?
 
-More exact, after re-reading this document :)
-It all depends on the kind of problems you have. If you are unable to
-compile the sources and you have a fairly common OS, it will probably
-not be the fault of RRDtool. There may be precompiled versions around
-on the Internet. If they come from trusted sources, get one of those.
+First of all: read it again! You may have missed something.
+If you are unable to compile the sources and you have a fairly common
+OS, it will probably not be the fault of RRDtool. There may be precompiled
+versions around on the Internet. If they come from trusted sources, get
+one of those.
 If on the other hand the program works but does not give you the
 expected results, it will be a problem with configuring it. Review
 your configuration and compare it with the examples that follow.
 
 There is a mailing list and an archive of it. Read the list for a few
 weeks and search the archive. It is considered rude to just ask
-a question without reading the list, your problem may already have been
-solved for somebody else and you will be helped without writing a new
-a message at all ... This is true for most, if not all, mailing lists
+a question without searching the archives: your problem may already have been
+solved for somebody else!  This is true for most, if not all, mailing lists
 and not only for this particular list! Look in the documentation that
 came with RRDtool for the location and usage of the list.
 
@@ -97,7 +99,7 @@
 
 By giving you some detailed descriptions with detailed examples.
 It is assumed that following the instructions in the order presented
-will build up enough knowledge of the program to experiment for yourself.
+will give you enough knowledge of RRDtool to experiment for yourself.
 If it doesn't work the first time, don't give up. Reread the stuff that
 you did understand, you may have missed something.
 By following the examples you get some hands-on experience and, even
@@ -109,12 +111,13 @@
 =head2 Your first Round Robin Database
 
 In my opinion the best way to learn something is to actually do it.
-Why not start right now? We will create a database, put some values in
-it and extract this data again. It is expected that you get the same
-results when you try these examples yourself so do that.
+Why not start right now?  We will create a database, put some values
+in it and extract this data again.  Your output should be the same
+as the output that is included in this document.
+
 We will start with some easy stuff and compare a car with a router,
 or compare kilometers (miles if you wish) with bits and bytes. It's
-all the same: Some number over some time.
+all the same: some number over some time.
 
 Assume we have a device that transfers bytes to and from the Internet.
 This device keeps a counter that starts at zero when it is turned on,
@@ -124,13 +127,13 @@
 in the world such as the mileage counter in a car.
 Most discussions about networking talk about bits per second so lets
 get used to that right away. Assume a byte is eight bits and start to
-think in bits not bytes. The counter however still counts bytes !
+think in bits not bytes. The counter, however, still counts bytes !
 In the SNMP world most of the counters are 32 bits. That means they are
 counting from 0 to 4294967295. We will use these values in the examples.
 The device, when asked, returns the current value of the counter. We
 know the time that has passes since we last asked so we now know how
 many bytes have been transfered ***on average*** per second. This is
-not very hard to calculate. First in words, then in calculi:
+not very hard to calculate. First in words, then in calculations:
 
 =over 3
 
@@ -148,10 +151,10 @@
 the amount of bytes per second. Multiply by eight to get the
 number of bits per second (bps).
 
-  bps = (counter_now - counter_before) / (time_now - time_before) * 8
-
 =back
 
+  bps = (counter_now - counter_before) / (time_now - time_before) * 8
+
 For some people it may help to translate this to a automobile example:
 Do not try this example, and if you do, don't blame me for the results.
 
@@ -177,24 +180,25 @@
 minutes which translates into 300 seconds. Our speed is 12000M / 300S
 equals 40 M/S.
 
-We could also calculate the speed in KM/H: twelve times five minutes
+We could also calculate the speed in KM/H: 12 times five minutes
 is an hour so we have to multiply 12 KM by 12 to get 144 KM/H.
-For our native English speaking friends: this is ninety MPH and
-therefore not recommended to try for yourself where I live :)
+For our native English speaking friends: that's 90 MPH so don't
+try this example at home or where I live :)
 
-Remember: these numbers are averages and there is no way to figure out
-from the numbers we got that you drove at a constant speed.
+Remember: these numbers are averages only.  There is no way to figure out
+from the numbers, if you drove at a constant speed.  There is an example
+later on in this tutorial that explains this.
 
 I hope you understand that there is no difference in calculating M/S or
-bps, only the way we collect the data is different. Even the K from kilo
+bps; only the way we collect the data is different. Even the K from kilo
 is the same as in networking terms k also means 1000.
 
 We will now create a database where we can keep all these interesting
 numbers. The method used to start the program may differ slightly from
 OS to OS but I assume you can figure it out if it works different on
 your OS. Make sure you do not overwrite any file on your system when
-executing the following command (so: first look if it's safe!) and type
-the whole line as one long line (I had to split it for readability)
+executing the following command and type the whole line as one long
+line (I had to split it for readability)
 and skip all of the '\' characters.
 
    rrdtool create test.rrd             \
@@ -212,14 +216,21 @@
 this document. It holds one data source (DS) named "speed" that gets
 built from a counter. This counter is read every five minutes (default)
 In the same database two round robin archives (RRAs) are kept, one
-averages the data every time it is read (so: there's nothing to average)
+averages the data every time it is read (eg there's nothing to average)
 and keeps 24 samples (24 times 5 minutes is 2 hours). The other averages
-6 values (half hour) and contains 10 of such averages (so: 5 hours)
+6 values (half hour) and contains 10 of such averages (eg 5 hours)
 The remaining options will be discussed later on.
+
+RRDtool works with special time stamps coming from the UNIX world.
+This time stamp is the number of seconds that passed since January
+1st 1970 UTC.  This time stamp is translated into local time and
+it will therefore look different for the different time zones.
+
 Chances are that you are not in the same part of the world as I am.
 This means your time zone is different. In all examples where I talk
 about time, the hours may be wrong for you. This has little effect on
 the results of the examples, just correct the hours while reading.
+As an example: where I will see "12:05" the UK folks will see "11:05".
 
 We now have to fill our database with some numbers. We'll pretend to
 have read the following numbers:
@@ -257,11 +268,41 @@
 
 As you can see, it is possible to feed more than one value into the
 database in one command. I had to stop at three for readability but
-the real maximum will be OS dependent.
+the real maximum is OS dependent.
+
+We can now retrieve the data from our database using "rrdtool fetch":
+
+ rrdtool fetch test.rrd AVERAGE --start 920804400 --end 920809200
+
+It should return the following output:
+
+                speed
+
+ 920804700:       NaN
+ 920805000:      0.04
+ 920805300:      0.02
+ 920805600:      0.00
+ 920805900:      0.00
+ 920806200:      0.03
+ 920806500:      0.03
+ 920806800:      0.03
+ 920807100:      0.02
+ 920807400:      0.02
+ 920807700:      0.02
+ 920808000:      0.01
+ 920808300:      0.02
+ 920808600:      0.01
+ 920808900:      0.00
+ 920809200:       NaN
+
+If it doesn't, something may be wrong.  Perhaps your OS will print
+"NaN" in a different form.  It represents "Not A Number".  If your OS
+writes "U" or "UNKN" or something similar that's okay.  If something
+else is wrong, it will probably be due to an error you made (assuming
+that my tutorial is correct of course :-). In that case: delete the
+database and try again.
 
-The time value may look strange to you, it is written in seconds since
-the first of January, 1970, midnight. Don't worry about this yet, just
-notice that there is a difference of 300 in between all values.
+What this output represents will become clear in the rest of the tutorial.
 
 =head2 It is time to create some graphics
 
@@ -281,70 +322,72 @@
 that time. This will only happen when you miss some samples, this will
 not happen a lot, hopefully.
 
-If this has worked: Congratulations. If not, check what went wrong.
+If this has worked: congratulations! If not, check what went wrong.
 
 
 The colors are built up from red, green and blue. For each of the
 components, you specify how much to use in hexadecimal where 00 means
 not included and FF means fully included.
-The color white is a mixture of red, green and blue: FFFFFF
-The color black is all colors off: 000000
-(Please, no discussions if black and white can be called colors)
+The "color" white is a mixture of red, green and blue: FFFFFF
+The "color" black is all colors off: 000000
 
-   red    #FF0000
-   green  #00FF00
-   blue   #0000FF
-   purple #FF00FF     (mixed red with blue)
-   gray   #555555     (one third of all components)
-
-
-
-The GIF you just created can be displayed using a web browser or other
-software you like. I can not provide you with an example of that,
-because there are too many different setups, possibilities etc.
+   red     #FF0000
+   green   #00FF00
+   blue    #0000FF
+   magenta #FF00FF     (mixed red with blue)
+   gray    #555555     (one third of all components)
+
+The GIF you just created can be displayed using your favorite image
+viewer.  Web browsers will display the GIF via the URL
+"file://the/path/to/speed.gif"
 
 =head2 Graphics with some math
 
-When looking at the image, you notice that the horizontal axis displays
+When looking at the image, you notice that the horizontal axis is labeled
 12:10, 12:20, 12:30, 12:40 and 12:50. The two remaining times (12:00 and
 13:00) would not be displayed nicely so they are skipped.
 The vertical axis displays the range we entered. We provided kilometers
 and when divided by 300 seconds, we get very small numbers. To be exact,
-the first value was 12 (12357-12345) and divided by 300 this makes 0.04
-RRDtool displays this as 40 m which means 40 milli (so: NOT meters).
+the first value was 12 (12357-12345) and divided by 300 this makes 0.04,
+which is displayed by RRDtool as "40 m" meaning "40/1000". The "m" has
+nothing to do with meters, kilometers or millimeters! RRDtool doesn't
+know about all this, it just works with numbers and not with meters...
+
 What we did wrong was that we should have measured in meters, this would
 have been (12357000-12345000)/300 = 12000/300 = 40.
 
 Let's correct that. We could recreate our database and store the correct
-data but there is another way: do some calculations while creating the
+data but there is a better way: do some calculations while creating the
 gif file !
 
    rrdtool graph speed2.gif                           \
       --start 920804400 --end 920808000               \
       --vertical-label m/s                            \
       DEF:myspeed=test.rrd:speed:AVERAGE              \
-      "CDEF:realspeed=myspeed,1000,*"                 \
+      CDEF:realspeed=myspeed,1000,*                   \
       LINE2:realspeed#FF0000
 
 After viewing this GIF, you notice the "m" has disappeared. This it what
 the correct result would be. Also, a label has been added to the image.
 Apart from the things mentioned above, the GIF should be the same.
 
-The calculations are done with the CDEF part. What it says is: take the
-data source myspeed and the number 1000, multiply those. The calculations
-are done using Reverse Polish Notation. It is an easy way of performing
-calculations after you understand it. You will, eventually but for now
-assume it is correct what I write and just keep to the examples in this
-file. Read the documentation that came with RRDtool (look in rrdgraph.doc)
-when you're ready for it.
+The calculations are in the CDEF part and are in Reverse Polish Notation
+("RPN"). What it says is: "take the data source myspeed and the number
+1000; multiply those". Don't bother with RPN yet, it will be explained
+later on in more detail. Also, you may want to read my tutorial on CDEFs
+and Steve Rader's tutorial on RPN. But first finish this tutorial.
 
 Hang on! If we can multiply values with 1000, it should also be possible
-to display kilometers per hour from the same data !
-What do we need to do ? If we have meters per second, we can make this
-meters per hour by multiplying the value with 3600 (there go 3600 seconds
-in one hour). To get kilometers per hour, we need to divide by 1000.
-We end up with: value * 3600 / 1000 = value * 3.6 . Remember we also have
-to correct our mistake, so it is value * 3600 for us.
+to display kilometers per hour from the same data!
+
+To change a value that is measured in meters per second:
+ -*- Calculate meters per hour:     value * 3600
+ -*- Calculate kilometers per hour: value / 1000
+ -*- Together this makes:           value * (3600/1000) == value * 3.6
+
+In our example database we made a mistake and we need to compensate for
+this by multiplying with 1000. Applying that correction:
+ -*- value * 3.6  *1000 == value * 3600
 
 Now let's create this GIF, and add some more magic ...
 
@@ -365,37 +408,19 @@
 
 The calculations are more complex now. For the "good" speed they are:
 
-=over 2
-
-=item *
-
-Check if kmh is greater than 100    ( kmh,100 ) GT
-
-=item *
-
-If so, return 0, else kmh           ((( kmh,100 ) GT ), 0, kmh) IF
-
-=back
+   Check if kmh is greater than 100    ( kmh,100 ) GT
+   If so, return 0, else kmh           ((( kmh,100 ) GT ), 0, kmh) IF
 
 For the other speed:
 
-=over 2
-
-=item *
-
-Check if kmh is greater than 100    ( kmh,100 ) GT
-
-=item *
-
-If so, return kmh, else return 0    ((( kmh,100) GT ), kmh, 0) IF
-
-=back
+   Check if kmh is greater than 100    ( kmh,100 ) GT
+   If so, return kmh, else return 0    ((( kmh,100) GT ), kmh, 0) IF
 
 =head2 Graphics Magic
 
-I like to believe there are virtually no limits about what RRDtool
-can do. I will not explain how it works, but look at the following
-GIF:
+I like to believe there are virtually no limits to how RRDtool graph
+can manipulate data. I will not explain how it works, but look at the
+following GIF:
 
    rrdtool graph speed4.gif                           \
       --start 920804400 --end 920808000               \
@@ -423,13 +448,14 @@
 Name the file "speed.html" or similar, and view it.
 
 Now, all you have to do is measure the values regularly and update the
-database. Every time you create these three GIFs and reload the page
-and the GIFs (better reread these last three words!) you know how fast
-you traveled.
+database.  When you want to view the data, recreate the GIFs and make
+sure to refresh them in your browser. (Note: just clicking reload may
+not be enough; Netscape in particular has a problem doing so and you'll
+need to click reload while pressing the shift key).
 
 =head2 Updates in Reality
 
-You already looked at the "update" tool. It took one or more parameters
+We've already used the "update" command: it took one or more parameters
 in the form of "<time>:<value>". You'll be glad to know that you can
 get the current time by filling in a "N" as the time.
 If you wish, you can also use the "time" function in perl.
@@ -437,13 +463,14 @@
 
    perl -e 'print time, "\n" '
 
-How you can run a program on regular intervals is OS specific, so I just
-give you an example script in a sort of pseudo code:
-(Do not try this with our test database, it is used in further examples)
+How you can run a program on regular intervals is OS specific. But here's
+an example in pseudo code:
 
    Get the value, put it in variable "$speed"
    rrdtool update speed.rrd N:$speed
 
+(Do not try this with our test database, it is used in further examples)
+
 This is all. Run this script every five minutes. When you need to know
 what the graphics look like, run the examples above. You could put them
 in a script. After running that script, view index.html
@@ -453,16 +480,17 @@
 I can imagine very few people will be able to get real data from their
 car every five minutes, all other people will have to settle for some
 other kind of counter. You could measure the number of pages printed by
-the laser-jet printer, the coffee made by the coffee machine, a device
-that counts the electricity used, whatever. Just as long as it is an
-incrementing counter that you can measure regularly, you can graph it
-against time as we did. Most people will use the counter that keeps track
-of octets (bytes) transfered by a routing device so we have to do just
+a printer, the coffee made by the coffee machine, a device that counts
+the electricity used, whatever. Any incrementing counter can be monitored
+and graphed using the stuff you learned until now. Later on we will also
+be able to monitor other types of values like temperature.
+Most people will use the counter that keeps track
+of octets (bytes) transfered by a network device so we have to do just
 that. We will start with a description of how to collect data.
 Some people will make a remark that there are tools who can do this data
-collection for you. They are right! However, I feel it is important that
-you understand they are not necessary. If you have to look why things
-went wrong, you need to know how the stuff works.
+collection for you. They are right!  However, I feel it is important that
+you understand they are not necessary.  When you have to determine why
+things went wrong you need to know how they work.
 
 One tool used in the example has been talked about very briefly in the
 beginning of this document, it is called SNMP. It is a way of talking to
@@ -471,50 +499,52 @@
 
    snmpget device password OID
 
-For device you substitute the name of your device, for password you
-use the "community" as it is called. For most devices "public" will do
-but this can be disabled, altered or protected for privacy and security
-reasons. You will need to find this out as there is no way I can tell
-what you ( ...your device... ) are keeping a secret from me.
+For device you substitute the name, or the IP address, of your device.
+For password you use the "community read string" as it is called in the
+SNMP world.  For some devices the default of "public" might work, however
+this can be disabled, altered or protected for privacy and security
+reasons.  Read the documentation that comes with your device or program.
+
+Then there is this third parameter, called OID, which means "object
+identifier".
 
-Then there is this third parameter, called OID.
 When you start to learn about SNMP it looks very confusing. It isn't
 all that difficult when you look at the Management Information Base
-or in short: the MIB. It is an upside-down tree, with a single node
-as the root and from there a number of branches. These branches end
-up in another node, they branch out, etc. All the branches have a name
-and they form the path that we follow all the way down. The branches
+("MIB").  It is an upside-down tree that describes data, with a single node
+as the root and from there a number of branches.  These branches end
+up in another node, they branch out, etc.  All the branches have a name
+and they form the path that we follow all the way down.  The branches
 that we follow are named: iso, org, dod, internet, mgmt and mib-2.
 These names can also be written down as numbers and are 1 3 6 1 2 1.
 
    iso.org.dod.internet.mgmt.mib-2 (1.3.6.1.2.1)
 
-From there, we are especially interested in the branch "interfaces"
-which has number 2 (so: 1.3.6.1.2.1.2 or 1.3.6.1.2.1.interfaces).
+There is a lot of confusion about the leading dot that some programs
+use.  There is *no* leading dot in an OID.  However, some programs
+can use above part of OIDs as a default.  To indicate the difference
+between abbreviated OIDs and full OIDs they need a leading dot when
+you specify the complete OID.  Often those programs will leave out
+the default portion when returning the data to you.  To make things
+worse, they have several default prefixes ...
 
-The SNMP programs that I know can take above path as a default, so
-I could walk to interfaces without writing it in full. To do that,
-the path has to be written as interfaces, without a leading dot.
-I could also use the long form, then I need to start with a dot.
-
-I can intermix numbers and names as I like.  1.3.6.1.2.1 is the same
-as iso.org.dod.1.2.1 and 1.3.6.internet.2.mib-2
-For interfaces I could write "interfaces", 2, or a long version by
-prefixing it with ".1.3.6.1.2.1.". Just try what works for you and
-do read the manual for the version of snmpget you are using.
+Right, lets continue to the start of our OID: we had 1.3.6.1.2.1
+From there, we are especially interested in the branch "interfaces"
+which has number 2 (eg 1.3.6.1.2.1.2 or 1.3.6.1.2.1.interfaces).
 
 First, we have to get some SNMP program. First look if there is a
 pre-compiled package available for your OS. This is the preferred way.
 If not, you will have to get yourself the sources and compile those.
 The Internet is full of sources, programs etc. Find information using
-a search engine or whatever you prefer. You are on your own here, sorry.
+a search engine or whatever you prefer. As a suggestion: look for
+CMU-SNMP.  It is commonly used.
 
 Assume you got the program. First try to collect some data that is
 available on most systems. Remember: there is a short name for the
-part of the tree that interests us most in the world we live in !
+part of the tree that interests us most in the world we live in!
+
 I will use the short version as I think this document is large enough
 as it is. If that doesn't work for you, prefix with .1.3.6.1.2.1 and
-try again. Also, Read The Fine Manual. Skip the parts you cannot
+try again.  Also, Read The Fine Manual.  Skip the parts you cannot
 understand yet, you should be able to find out how to start the
 program and use it.
 
@@ -566,8 +596,8 @@
 Do not forget the interface number (0 if it is not interface dependent)
 and try snmpwalk if you don't get an answer from snmpget.
 
-If you understand above part, and get numbers from your device, it is
-time to continue with the following. If not, then go back.
+If you understand above part, and get numbers from your device, continue
+on with this tutorial. If not, then go back and re-read this part.
 
 =head2 A Real World Example
 
@@ -578,30 +608,43 @@
 explained later on. The time in-between samples is 300 seconds, a good
 starting point, which is the same as five minutes.
 
- 1 sample averaged stays 1 period of 5 minutes
+ 1 sample "averaged" stays 1 period of 5 minutes
  6 samples averaged become one average on 30 minutes
  24 samples averaged become one average on 2 hours
  288 samples averaged become one average on 1 day
 
- There are 600 samples of five minutes, together just over two days
- There are 600 samples of 30 minutes, almost two weeks
- There are 600 samples of 2 hours, 50 hour or almost two months
- There are 732 samples of 1 day, just over two years
+Lets try to be compatible with MRTG:
+MRTG stores about the following amount of data:
 
-For people used to MRTG that even have read the manuals, these numbers
-should look familiar...
+ 600 5-minute samples:    2   days and 2 hours
+ 600 30-minute samples:  12.5 days
+ 600 2-hour samples:     50   days
+ 600 1-day samples:     732   days
+
+These ranges are appended so the total amount of data kept is approximately
+797 days.  RRDtool stores the data differently, it doesn't start the "weekly"
+archive where the "daily" archive stopped.  For both archives the most recent
+data will be near "now" and therefore we will need to keep more data than
+MRTG does!
+
+We will need:
+
+ 600 samples of 5 minutes  (2 days and 2 hours)
+ 700 samples of 30 minutes (2 days and 2 hours, plus 12.5 days)
+ 775 samples of 2 hours    (above + 50 days)
+ 797 samples of 1 day      (above + 732 days, rounded up to 797)
 
    rrdtool create myrouter.rrd         \
             DS:input:COUNTER:600:U:U   \
             DS:output:COUNTER:600:U:U  \
             RRA:AVERAGE:0.5:1:600      \
-            RRA:AVERAGE:0.5:6:600      \
-            RRA:AVERAGE:0.5:24:600     \
-            RRA:AVERAGE:0.5:288:732    \
+            RRA:AVERAGE:0.5:6:700      \
+            RRA:AVERAGE:0.5:24:775     \
+            RRA:AVERAGE:0.5:288:797    \
             RRA:MAX:0.5:1:600          \
-            RRA:MAX:0.5:6:600          \
-            RRA:MAX:0.5:24:600         \
-            RRA:MAX:0.5:288:732
+            RRA:MAX:0.5:6:700          \
+            RRA:MAX:0.5:24:775         \
+            RRA:MAX:0.5:288:797
 
 Next thing to do is collect data and store it. Here is an example.
 It is written partially in pseudo code so you will have to find out what
@@ -631,13 +674,13 @@
 
 This should produce a picture with one day worth of traffic.
 One day is 24 hours of 60 minutes of 60 seconds: 24*60*60=86400, we
-start at now minus 86400 seconds. We DEFine inoctets and outoctets
-as the average values from the database myrouter.rrd and draw an area
-for the "in" traffic and a line for the "out" traffic.
+start at now minus 86400 seconds. We define (with DEFs) inoctets and
+outoctets as the average values from the database myrouter.rrd and draw
+an area for the "in" traffic and a line for the "out" traffic.
 
-View the image and keep logging for a few more days.
+View the image and keep logging data for a few more days.
 If you like, you could try the examples from the test database and
-see if you can play around with the options and calculations.
+see if you can get various options and calculations working.
 
 Suggestion:
 
@@ -687,14 +730,14 @@
 of 60 KM/H times 24 H = 1440 KM. I did this with a higher speed and
 a maximum around 180 KM/H. This doesn't mean that I traveled for 8
 hours at a constant speed of 180 KM/H !
-This is a real example: go with the flow through Germany and stop
+This is a real example: go with the flow through Germany (fast!) and stop
 a few times for gas and coffee. Drive slowly through Austria and the
 Netherlands. Be careful in the mountains and villages. If you would
 look at the graphs created from the five-minute averages you would
 get a totally different picture. You would see the same values on the
 average and maximum graphs (provided I measured every 300 seconds).
 You would be able to see when I stopped, when I was in top gear, when
-I drove over fast motor-ways etc. The granularity of the data is much
+I drove over fast hiways etc. The granularity of the data is much
 higher, so you can see more. However, this takes 12 samples per hour,
 or 288 values per day, so it would be too much to keep for a long
 period of time. Therefore we average it, eventually to one value per
@@ -731,18 +774,17 @@
 
 You know that in order to view a counter over time, you have to
 take two numbers and divide the difference of them between the
-time lapsed. This makes sense for the examples I gave you but there
-are other possibilities. For instance, I'm able to retrieve the
+time lapsed.  This makes sense for the examples I gave you but there
+are other possibilities.  For instance, I'm able to retrieve the
 temperature from my router in three places namely the inlet, the
-so called hot-spot and the exhaust. If I take the difference of
-the two samples and divide that by 300 (seconds) there would not be very
-much to display ... If there would be anything to display it would
-be the fluctuations in the temperature and if they produce noticeable
-results when divided by 300, I'd better look for a new computer room.
+so called hot-spot and the exhaust.  These values are not counters.
+If I take the difference of the two samples and divide that by
+300 seconds I would be asking for the temperature change per second.
+Hopefully this is zero! If not, the computerroom is on fire :)
 
-So, what can we do ?  RRDtool can also store the values you measure
+So, what can we do ?  We can tell RRDtool to store the values we measure
 directly as they are (this is not entirely true but close enough). The
-graphs we make look much better, they will show a rather constant
+graphs we make will look much better, they will show a rather constant
 value. I know when the router is busy (it
 works -> it uses more electricity -> it generates more heat -> the
 temperature rises). I know when the doors are left open (the room is
@@ -826,7 +868,7 @@
 
  - Line A:  u  u  1  1  1  1  1  1  1  1  1  u
  - Line B:  u  1  3  5  3  1  2  4  6  4  2  u
- - Line C:  u  u  2  2  2  0 -2 -6 -2  0  2  u
+ - Line C:  u  u  2  2  2  0 -2 -6  2  0  2  u
  - Line D:  u  1  2  3  4  5  6  7  8  9 10  u
 
 If your GIF shows all this, you know you have typed the data correct,
@@ -892,7 +934,7 @@
 
  Real delta = -999980 + 999999 + 1 = 20
 
-At the moment of writing this document, RRDtool knows of counters that
+At the time of writing this document, RRDtool knows of counters that
 are either 32 bits or 64 bits of size. These counters can handle the
 following different values:
 
@@ -961,14 +1003,14 @@
 
 As you can see from the last two examples, you need strange numbers
 for RRDtool to fail (provided it's bug free of course) so this should
-not happen. However, SNMP or whatever method you choose to collect the
-data might also fail and it is not uncommon to get wrong numbers
-occasionally. We can't prevent all errors but there are some things we
-could do. RRDtool create takes two special parameters for this. They define
-the minimum and maximum allowed value. Until now, we made them "U"
-for Unknown. You may (not: must) provide values for one or both of them
-and if RRDtool receives values that are outside these limits, it will ignore
-them. For a thermometer in degrees Celsius, the absolute minimum is
+not happen.  However, SNMP or whatever method you choose to collect the
+data might also report wrong numbers occasionally.  We can't prevent all
+errors but there are some things we can do.  The RRDtool "create" command
+takes two special parameters for this. They define
+the minimum and maximum allowed value. Until now, we used "U", meaning
+"unknown". If you provide values for one or both of them and if RRDtool
+receives values that are outside these limits, it will ignore those
+values. For a thermometer in degrees Celsius, the absolute minimum is
 just under -273. For my router, I can assume this minimum is much higher
 so I would say it is 10. The maximum temperature for my router I would
 state as 80. Any higher and the device would be out of order.
@@ -998,7 +1040,7 @@
 interval is 297 seconds and also the counter increased with 297. Again
 RRDtool alters the value and stores 300 as it should be.
 
-      in the RDD                 in real
+      in the RDD                 in reality
 
  time+000:   0 delta="U"   time+000:    0 delta="U"
  time+300: 300 delta=300   time+300:  300 delta=300
@@ -1046,7 +1088,7 @@
 It's time to wrap up this document. You now know all the basics to be
 able to work with RRDtool and to read the documentation available.
 There is plenty more to discover about RRDtool and you will find more and
-more uses for the program. You could create easy graphics using just the
+more uses for the package. You could create easy graphics using just the
 examples provided and using only RRDtool. You could also use the front
 ends that are available.
 
@@ -1056,7 +1098,7 @@
 the mails that come by, it helps both you and the rest. A lot of the stuff
 that I know about MRTG (and therefore about RRDtool) I've learned while
 just reading the list without posting to it. I did not need to ask the
-basic questions as they are answered in the FAQ (so: read that too) and
+basic questions as they are answered in the FAQ (read it!) and
 in various mails by other users.
 With thousands of users all over the world, there will always be people
 who ask questions that you can answer because you read this and other

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/rrdrestore.html
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/rrdrestore.html	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/rrdrestore.html	Sat Jul 13 21:08:14 2002
@@ -1,11 +1,10 @@
-    <HTML> 
-	<HEAD> 
-	    <TITLE>restore - restore the contents of an B<RRD> from its XML dump format
+<HTML>
+<HEAD>
+<TITLE>rrdrestore</TITLE>
+<LINK REV="made" HREF="mailto:karrer at zinal.ee.ethz.ch">
+</HEAD>
 
-</TITLE> 
-	</HEAD>
-
-	<BODY>
+<BODY>
 
 <!-- INDEX BEGIN -->
 <!--
@@ -21,77 +20,48 @@
 <!-- INDEX END -->
 
 <P>
-<H1><A NAME="NAME">NAME
-
-</A></H1>
-rrdtool restore - restore the contents of an <STRONG>RRD</STRONG> from its XML dump format
-
-
+<H1><A NAME="NAME">NAME</A></H1>
 <P>
+rrdtool restore - restore the contents of an <STRONG>RRD</STRONG> from its XML dump format
 
 <P>
 <HR>
-<H1><A NAME="SYNOPSIS">SYNOPSIS
-
-</A></H1>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
 <STRONG>rrdtool</STRONG>  <STRONG>restore</STRONG>  <EM>filename.xml</EM>  <EM>filename.rrd</EM>
 
 [<STRONG>--range-check</STRONG>|<STRONG>-r</STRONG>]
 
 
 
-
-<P>
-
 <P>
 <HR>
-<H1><A NAME="DESCRIPTION">DESCRIPTION
-
-</A></H1>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
 The <STRONG>restore</STRONG> function reads the XML representation of an RRD and converts it into the
 native <STRONG>RRD</STRONG> format.
 
-
-<P>
-
 <DL>
-<DT><STRONG><A NAME="item_filename">filename.xml
-
-</A></STRONG><DD>
+<DT><STRONG><A NAME="item_filename">filename.xml</A></STRONG><DD>
+<P>
 The name of the <STRONG>XML</STRONG> you want to restore.
 
-
+<DT><STRONG><A NAME="item_filename">filename.rrd</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_filename">filename.rrd
-
-</A></STRONG><DD>
 The name of the <STRONG>RRD</STRONG> to restore.
 
-
+<DT><STRONG><A NAME="item__range_check_r">--range-check|-r</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__range_check_r">--range-check|-r
-
-</A></STRONG><DD>
 Make sure the values in the RRAs do not exceed the limits defined for the
 different datasources.
 
-
-<P>
-
 </DL>
 <P>
 <HR>
-<H1><A NAME="AUTHOR">AUTHOR
-
-</A></H1>
-Tobias Oetiker <A
-HREF="MAILTO:<oetiker at ee.ethz.ch>"><oetiker at ee.ethz.ch></A>
-
+<H1><A NAME="AUTHOR">AUTHOR</A></H1>
 <P>
+Tobias Oetiker &lt;<A
+HREF="mailto:oetiker at ee.ethz.ch">oetiker at ee.ethz.ch</A>&gt;
+</BODY>
 
-</DL>
-    </BODY>
-
-    </HTML>
+</HTML>

Added: trunk/orca/packages/rrdtool-1.0.13/doc/rpntutorial.txt
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/rpntutorial.txt	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/rpntutorial.txt	Sat Jul 13 21:08:15 2002
@@ -0,0 +1,264 @@
+
+
+
+rrdtool                                            RPNTUTORIAL(1)
+
+
+
+NNNNAAAAMMMMEEEE
+     rpntutorial - Reading RRDTtool RPN Expressions by Steve
+     Rader
+
+DDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
+     This tutorial should help you get to grips with rrdtool RPN
+     expressions as seen in CDEF arguments of rrdtool graph.
+
+RRRReeeeaaaaddddiiiinnnngggg CCCCoooommmmppppaaaarrrriiiissssoooonnnn OOOOppppeeeerrrraaaattttoooorrrrssss
+     The LT, LE, GT, GE and EQ RPN logic operators are not as
+     tricky as they appear.  These operators act on the two
+     values on the stack preceding them (to the left).  Read
+     these two values on the stack from left to right inserting
+     the operator in the middle.  If the resulting statement is
+     true, the replace the three values from the stack with "1".
+     If the statement if false, replace the three values with
+     "0".
+
+     For example think about "2,1,GT".  This RPN expression could
+     be read as "is two greater than one?"  The answer to that
+     question is "true".  So the three values should be replaced
+     with "1".  Thus the RPN expression 2,1,GT evaluates to 1.
+
+     Now also consider "2,1,LE".  This RPN expression could be
+     read as "is two less than or equal to one?".   The natural
+     response is "no" and thus the RPN expression 2,1,LE
+     evaluates to 0.
+
+RRRReeeeaaaaddddiiiinnnngggg tttthhhheeee IIIIFFFF OOOOppppeeeerrrraaaattttoooorrrr
+     The IF RPN logic operator can be straightforward also.  The
+     key to reading IF operators is to understand that the
+     condition part of the traditional "if X than Y else Z"
+     notation has *already* been evaluated.  So the IF operator
+     acts on only one value on the stack: the third value to the
+     left of the IF value.  The second value to the left of the
+     IF corresponds to the true ("Y") branch.  And the first
+     value to the left of the IF corresponds to the false ("Z")
+     branch.  Read the RPN expression "X,Y,Z,IF" from left to
+     right like so: "if X then Y else Z".
+
+     For example, consider "1,10,100,IF".  It looks bizzare to
+     me.  But when I read "if 1 then 10 else 100" it's crystal
+     clear: 1 is true so the answer is 10.  Note that only zero
+     is false; all other values are true.  "2,20,200,IF" ("if 2
+     then 20 else 200") evaluates to 20.  And "0,1,2,IF" ("if 0
+     then 1 else 2) evaluates to 2.
+
+     Notice that none of the above examples really simulate the
+     whole "if X then Y else Z" statement.  This is because
+     computer programmers read this statement as "if Some
+     Condition then Y else Z".  So it's important to be able to
+     read IF operators along with the LT, LE, GT, GE and EQ
+
+
+
+24/Nov/1999            Last change: 1.0.13                      1
+
+
+
+
+
+
+rrdtool                                            RPNTUTORIAL(1)
+
+
+
+     operators.
+
+SSSSoooommmmeeee EEEExxxxaaaammmmpppplllleeeessss
+     While compound expressions can look overly complex, they can
+     be considered elegantly simple.  To quickly comprehend RPN
+     expressions, you must know the the algorithm for evaluating
+     RPN expressions:  iterate searches from the left to the
+     right looking for an operator, when it's found, apply that
+     operator by popping the operator and some number of values
+     (and by definition, not operators) off the stack.
+
+     For example, the stack "1,2,3,+,+" gets "2,3,+" evaluated
+     (as "2+3") during the first iteration which is replaced by
+     5.  This results in the stack "1,5,+".  Finally, "1,5,+" is
+     evaluated resulting in the answer 6.  For convenience sake,
+     it's useful to write this set of operations as:
+
+      1) 1,2,3,+,+    eval is 2,3,+ = 5    result is 1,5,+
+      2) 1,5,+        eval is 1,5,+ = 6    result is 6
+      3) 6
+
+     Let's use that notation to conviently solve some complex RPN
+     expressions with multiple logic operators:
+
+      1) 20,10,GT,10,20,IF  eval is 20,10,GT = 1     result is 1,10,20,IF
+
+     read the eval as pop "20 is greater than 10" so push 1
+
+      2) 1,10,20,IF         eval is 1,10,20,IF = 10  result is 10
+
+     read pop "if 1 then 10 else 20" so push 10.  Only 10 is left
+     so 10 is the answer.
+
+     Let's read a complex RPN expression that also has the
+     traditional multiplication operator:
+
+      1) 128,8,*,7000,GT,7000,128,8,*,IF  eval 128,8,*       result is 1024
+      2) 1024,7000,GT,7000,128,8,*,IF     eval 1024,7000,GT  result is 0
+      3) 0,128,8,*,IF                     eval 128,8,*       result is 1024
+      4) 0,7000,1024,IF                                      result is 1024
+
+     Now let's go back to the first example of multiple logic
+     operators but replace the value 20 with the variable
+     "input":
+
+      1) input,10,GT,10,input,IF  eval is input,10,GT  result is A
+
+     Read eval as "if input > 10 then true" and replace
+     "input,10,GT" with "A:
+
+      2) A,10,input,IF            eval is A,10,input,IF
+
+
+
+
+24/Nov/1999            Last change: 1.0.13                      2
+
+
+
+
+
+
+rrdtool                                            RPNTUTORIAL(1)
+
+
+
+     read "if A then 10 else input".  Now replace A it's verbose
+     description and--voila!--you have a easily readable
+     description of the expression:
+
+      if input > 10 then 10 else input
+
+     Lastly, let's to back the first most complex example and
+     replace the value 128 with "input":
+
+      1) input,8,*,7000,GT,7000,input,8,*,IF  eval input,8,*     result is A
+
+     where A is "input * 8"
+
+      2) A,7000,GT,7000,input,8,*,IF          eval is A,7000,GT  result is B
+
+     where B is "if ((input * 8) > 7000) then true"
+
+      3) B,7000,input,8,*,IF                  eval is input,8,*  result is C
+
+     where C is "input * 8"
+
+      4) B,7000,C,IF
+
+     At last we have a readable decoding of the complex RPN
+     expression with a variable:
+
+      if ((input * 8) > 7000) then 7000 else (input * 8)
+
+
+EEEExxxxeeeerrrrcccciiiisssseeeessss
+     Exercise 1:
+
+     Compute "3,2,*,1,+ and "3,2,1,+,*" by hand.  Rewrite them in
+     traditional notation.  Explain why they have different
+     answers.
+
+     Answer 1:
+
+         3*2+1 = 7 and 3*(2+1) = 9.  These expressions have
+         different answers because the altering of the plus and
+         times operators alter the order of their evaluation.
+
+     Exercise 2:
+
+     One may be tempted to shorten the expression
+
+      input,8,*,56000,GT,56000,input,*,8,IF
+
+     by removing the redundant use of "input,8,*" like so:
+
+      input,56000,GT,56000,input,IF,8,*
+
+
+
+
+24/Nov/1999            Last change: 1.0.13                      3
+
+
+
+
+
+
+rrdtool                                            RPNTUTORIAL(1)
+
+
+
+     Use tradition notation to show these expressions are not the
+     same.  Write an expression that's equivalent to the first
+     expression but uses the LE and DIV operators.
+
+     Answer 2:
+
+         if (input <= 56000/8 ) { input*8 } else { 56000 }
+         input,56000,8,DIV,LT,input,8,*,56000,IF
+
+     Exercise 3:
+
+     Briefly explain why traditional mathematic notation requires
+     the use of parentheses.  Explain why RPN notation does not
+     require the use of parentheses.
+
+     Answer 3:
+
+         Traditional mathematic expressions are evaluated by
+         doing multiplication and division first, then addition and
+         subtraction.  Perentences are used to force the evaluation of
+         addition before multiplication (etc).  RPN does not require
+         parentheses because the ordering of objects on the stack
+         can force the evaluation of addition before multiplication.
+
+     Exercise 4:
+
+     Explain why it is desirable for the RRDtool developers to
+     implement RPN notation instead of traditional mathematical
+     notation.
+
+     Answer 4:
+
+         The algorithm that implements traditional mathematical
+         notation is more complex then algorithm used for RPN.
+         So implementing RPN allowed Tobias Oetiker to write less
+         code!  (The code is also less complex and therefore less
+         likely to have bugs.)
+
+
+AAAAUUUUTTTTHHHHOOOORRRR
+     steve rader <rader at wiscnet.net>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+24/Nov/1999            Last change: 1.0.13                      4
+
+
+

Added: trunk/orca/packages/rrdtool-1.0.13/doc/cdeftutorial.txt
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/cdeftutorial.txt	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/cdeftutorial.txt	Sat Jul 13 21:08:15 2002
@@ -0,0 +1,1122 @@
+
+
+
+rrdtool                                           CDEFTUTORIAL(1)
+
+
+
+NNNNAAAAMMMMEEEE
+     cdeftutorial - Alex van den Bogaerdt's CDEF tutorial
+
+DDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
+     YYYYoooouuuu pppprrrroooovvvviiiiddddeeee aaaa qqqquuuueeeessssttttiiiioooonnnn aaaannnndddd IIII wwwwiiiillllllll ttttrrrryyyy ttttoooo pppprrrroooovvvviiiiddddeeee aaaannnn aaaannnnsssswwwweeeerrrr
+     iiiinnnn tttthhhheeee nnnneeeexxxxtttt rrrreeeelllleeeeaaaasssseeee. NNNNoooo ffffeeeeeeeeddddbbbbaaaacccckkkk eeeeqqqquuuuaaaallllssss nnnnoooo cccchhhhaaaannnnggggeeeessss!!!!
+
+     _A_d_d_i_t_i_o_n_s _t_o _t_h_i_s _d_o_c_u_m_e_n_t _a_r_e _a_l_s_o _w_e_l_c_o_m_e.
+
+     Alex van den Bogaerdt <alex at ergens.op.het.net>
+
+     WWWWhhhhyyyy tttthhhhiiiissss ttttuuuuttttoooorrrriiiiaaaallll ????
+
+     One of the powerful parts of RRDtool is its ability to do
+     all sorts of calculations on the data retrieved from it's
+     databases. However RRDtool's many options and syntax make it
+     difficult for the average user to understand. The manuals
+     are good at explaining what these options do; however they
+     do not (and should not) explain in detail why they are
+     useful. As with my RRDtool tutorial: if you want a simple
+     document in simple language you should read this tutorial.
+     If you are happy with the official documentation, you may
+     find this document too simple or even boring. If you do
+     choose to read this tutorial, I also expect you to have read
+     and fully understand my other tutorial.
+
+     MMMMoooorrrreeee rrrreeeeaaaaddddiiiinnnngggg
+
+     If you have difficulties with the way I try to explain them
+     please read Steve Rader's the _r_p_n_t_u_t_o_r_i_a_l manpage. It may
+     help you understand how this all works.
+
+WWWWhhhhaaaatttt aaaarrrreeee CCCCDDDDEEEEFFFFssss ????
+     When retrieving data from an RRD, you are using a "DEF" to
+     work with that data. Think of it as a variable that changes
+     over time (where time is the x-axis). The value of this
+     variable is what is found in the database at that particular
+     time and you can't do any modifications on it. This is what
+     CDEFs are for: they takes values from DEFs and perform
+     calculations on them.
+
+SSSSyyyynnnnttttaaaaxxxx
+        DEF:var_name_1=some.rrd:ds_name:CF
+        CDEF:var_name_2=RPN_expression
+
+     You first define "var_name_1" to be data collected from data
+     source "ds_name" found in RRD "some.rrd" with consolidation
+     function "CF".
+
+     Assume the ifInOctets SNMP counter is saved in mrtg.rrd as
+     the DS "in".  Then the following DEF defines a variable for
+     the average of that data source:
+
+
+
+24/Oct/1999            Last change: 1.0.13                      1
+
+
+
+
+
+
+rrdtool                                           CDEFTUTORIAL(1)
+
+
+
+        DEF:inbytes=mrtg.rrd:in:AVERAGE
+
+     Say you want to display bits per second (instead of bytes
+     per second as stored in the database.)  You have to define a
+     calculation (hence "CDEF") on variable "inbytes" and use
+     that variable (inbits) instead of the original:
+
+        CDEF:inbits=inbytes,8,*
+
+     It tells to multiply inbytes by eight to get inbits. I'll
+     explain later how this works. In the graphing or printing
+     functions, you can now use inbits where you would use
+     inbytes otherwise.
+
+     Note that variable in the CDEF (inbits) must not be the same
+     as the variable (inbytes) in the DEF!
+
+RRRRPPPPNNNN-eeeexxxxpppprrrreeeessssssssiiiioooonnnnssss
+     RPN is short-hand for Reverse Polish Notation. It works as
+     follows.  You put the variables or numbers on a stack. You
+     also put operations (things-to-do) on the stack and this
+     stack is then processed. The result will be placed on the
+     stack. At the end, there should be exactly one number left:
+     the outcome of the series of operations. If there is not
+     exactly one number left, rrdtool will complain loudly.
+
+     Above multiplication by eight will look like:
+
+     1.  Start with an empty stack
+
+     2.  Put the content of variable inbytes on the stack
+
+     3.  Put the number eight on the stack
+
+     4.  Put the operation multiply on the stack
+
+     5.  Process the stack
+
+     6.  Retrieve the value from the stack and put it in variable
+         inbits
+
+     We will now do an example with real numbers. Suppose the
+     variable inbytes would have value 10, the stack would be:
+
+     1.  ||
+
+     2.  |10|
+
+     3.  |10|8|
+
+     4.  |10|8|*|
+
+
+
+
+24/Oct/1999            Last change: 1.0.13                      2
+
+
+
+
+
+
+rrdtool                                           CDEFTUTORIAL(1)
+
+
+
+     5.  |80|
+
+     6.  ||
+
+     Processing the stack (step 5) will retrieve one value from
+     the stack (from the right at step 4). This is the operation
+     multiply and this takes two values off the stack as input.
+     The result is put back on the stack (the value 80 in this
+     case). For multiplication the order doesn't matter but for
+     other operations like subtraction and division it does.
+     Generally speaking you have the following order:
+
+        y = A - B  -->  y=minus(A,B)  -->  CDEF:y=A,B,-
+
+     This is not very intuitive (at least most people don't think
+     so). For the function _f(A,B) you reverse the position of "f"
+     but you do not reverse the order of the variables.
+
+CCCCoooonnnnvvvveeeerrrrttttiiiinnnngggg yyyyoooouuuurrrr wwwwiiiisssshhhheeeessss ttttoooo RRRRPPPPNNNN
+     First, get a clear picture of what you want to do. Break
+     down the problem in smaller portions until they cannot be
+     split anymore. Then it is rather simple to convert your
+     ideas into RPN.
+
+     Suppose you have several RRDs and would like to add up some
+     counters in them. These could be, for instance, the counters
+     for every WAN link you are monitoring.
+
+     You have:
+
+        router1.rrd with link1in link2in
+        router2.rrd with link1in link2in
+        router3.rrd with link1.in
+
+     Suppose you would like to add up all these counters, except
+     for link2in inside router2.rrd. You need to do:
+
+     (in this example, "router1.rrd:link1in" means the DS link1in
+     inside the RRD router1.rrd)
+
+        router1.rrd:link1in
+        router1.rrd:link2in
+        router2.rrd:link1in
+        router3.rrd:link1in
+        router3.rrd:link2in
+        --------------------   +
+        (outcome of the sum)
+
+     As a mathmatical function, this could be written:
+
+     add(router1.rrd:link1in , router1.rrd:link2in ,
+     router2.rrd:link1in , router3.rrd:link1in ,
+
+
+
+24/Oct/1999            Last change: 1.0.13                      3
+
+
+
+
+
+
+rrdtool                                           CDEFTUTORIAL(1)
+
+
+
+     router3.rrd:link2.in)
+
+     With RRDtool and RPN, first, define the inputs:
+
+        DEF:a=router1.rrd:link1in:AVERAGE
+        DEF:b=router1.rrd:link2in:AVERAGE
+        DEF:c=router2.rrd:link1in:AVERAGE
+        DEF:d=router3.rrd:link1in:AVERAGE
+        DEF:e=router3.rrd:link2in:AVERAGE
+
+     Now, the mathematical function becomes: add(a,b,c,d,e)
+
+     In RPN, there's no operator that sums more than two values
+     so you need to do several additions. You add a and b, add c
+     to the result, add d to the result and add e to the result.
+
+        push a:         a     stack contains the value of a
+        push b and add: b,+   stack contains the result of a+b
+        push c and add: c,+   stack contains the result of a+b+c
+        push d and add: d,+   stack contains the result of a+b+c+d
+        push e and add: e,+   stack contains the result of a+b+c+d+e
+
+     What was calculated here would be written down as:
+
+        ( ( ( (a+b) + c) + d) + e) >
+
+     This is in RPN:  CDEF:result=a,b,+,c,+,d,+,e,+
+
+     This is correct but it can be made more clear to humans. It
+     does not matter if you add a to b and then add c to the
+     result or first add b to c and then add a to the result.
+     This makes it possible to rewrite the RPN into
+     CDEF:result=a,b,c,d,e,+,+,+,+ which is evaluatated
+     differently:
+
+        push value of variable a on the stack: a
+        push value of variable b on the stack: a b
+        push value of variable c on the stack: a b c
+        push value of variable d on the stack: a b c d
+        push value of variable e on the stack: a b c d e
+        push operator + on the stack:          a b c d e +
+        and process it:                        a b c P   (where P == d+e)
+        push operator + on the stack:          a b c P +
+        and process it:                        a b Q     (where Q == c+P)
+        push operator + on the stack:          a b Q +
+        and process it:                        a R       (where R == b+Q)
+        push operator + on the stack:          a R +
+        and process it:                        S         (where S == a+R)
+
+     As you can see the RPN expression a,b,c,d,e,+,+,+,+,+ will
+     evaluate in ((((d+e)+c)+b)+a) and it has the same outcome as
+     a,b,+,c,+,d,+,e,+ According to Steve Rader this is called
+
+
+
+24/Oct/1999            Last change: 1.0.13                      4
+
+
+
+
+
+
+rrdtool                                           CDEFTUTORIAL(1)
+
+
+
+     the commutative law of addition but you may forget this
+     right away, as long as you remember what it represents.
+
+     Now look at an expression that contains a multiplication:
+
+     First in normal math: let result = a+b*c. In this case you
+     can't choose the order yourself, you have to start with the
+     multiplication and then add a to it. You may alter the
+     position of b and c, you may not alter the position of a and
+     b.
+
+     You have to take this in consideration when converting this
+     expression into RPN. Read it as: "Add the outcome of b*c to
+     a" and then it is easy to write the RPN expression:
+     result=a,b,c,*,+ Another expression that would return the
+     same: result=b,c,*,a,+
+
+     In normal math, you may encounter something like "a*(b+c)"
+     and this can also be converted into RPN. The parenthesis
+     just tell you to first add b and c, and then multiply a with
+     the result. Again, now it is easy to write it in RPN:
+     result=a,b,c,+,*. Note that this is very similar to one of
+     the expressions in the previous paragraph, only the
+     multiplication and the addition changed places.
+
+     When you have problems with RPN or when rrdtool is
+     complaining, it's usually a Good Thing to write down the
+     stack on a piece of paper and see what happens. Have the
+     manual ready and pretend to be rrdtool.  Just do all the
+     math by hand to see what happens, I'm sure this will solve
+     most, if not all, problems you encounter.
+
+SSSSoooommmmeeee ssssppppeeeecccciiiiaaaallll nnnnuuuummmmbbbbeeeerrrrssss
+     TTTThhhheeee uuuunnnnkkkknnnnoooowwwwnnnn vvvvaaaalllluuuueeee
+
+     Sometimes collecting your data will fail. This can be very
+     common, especially when querying over busy links. RRDtool
+     can be configured to allow for one (or even more) unknown
+     value and calculate the missing update. You can, for
+     instance, query your device every minute. This is creating
+     one so called PDP or primary data point per minute. If you
+     defined your RRD to contain an RRA that stores 5-minute
+     values, you need five of those PDPs to create one CDP
+     (consolidated data point).  These PDPs can become unknown in
+     two cases:
+
+     1.  The updates are too far apart. This is tuned using the
+         "heartbeat" setting
+
+     2.  The update was set to unknown on purpose by inserting no
+         value (using the template option) or by using "U" as the
+         value to insert.
+
+
+
+24/Oct/1999            Last change: 1.0.13                      5
+
+
+
+
+
+
+rrdtool                                           CDEFTUTORIAL(1)
+
+
+
+     When a CDP is calculated, another mechanism determines if
+     this CDP is valid or not. If there are too many PDPs
+     unknown, the CDP is unknown as well.  This is determined by
+     the xff factor. Please note that one unknown counter update
+     can result in two unknown PDPs! If you only allow for one
+     unknown PDP per CDP, this makes the CDP go unknown!
+
+     Suppose the counter increments with one per second and you
+     retrieve it every minute:
+
+        counter value    resulting rate
+        10000
+        10060            1; (10060-10000)/60 == 1
+        10120            1; (10060-10000)/60 == 1
+        unknown          unknown; you don't know the last value
+        10240            unknown; you don't know the previous value
+        10300            1; (10300-10240)/60 == 1
+
+     If the CDP was to be calculated from the last five updates,
+     it would get two unknown PDPs and three known PDPs. If xff
+     would have been set to 0.5 which by the way is a commonly
+     used factor, the CDP would have a known value of 1. If xff
+     would have been set to 0.2 then the resulting CDP would be
+     unknown.
+
+     You have to decide the proper values for heartbeat, number
+     of PDPs per CDP and the xff factor. As you can see from the
+     previous text they define the behavior of your RRA.
+
+     WWWWoooorrrrkkkkiiiinnnngggg wwwwiiiitttthhhh uuuunnnnkkkknnnnoooowwwwnnnn ddddaaaattttaaaa iiiinnnn yyyyoooouuuurrrr ddddaaaattttaaaabbbbaaaasssseeee
+
+     As you have read in the previous chapter, entries in an RRA
+     can be set to the unknown value. If you do calculations with
+     this type of value, the result has to be unknown too. This
+     means that an expression such as result=a,b,+ will be
+     unknown if either a or b is unknown.  It would be wrong to
+     just ignore the unknown value and return the value of the
+     other parameter. By doing so, you would assume "unknown"
+     means "zero" and this is not true.
+
+     There has been a case where somebody was collecting data for
+     over a year.  A new piece of equipment was installed, a new
+     RRD was created and the scripts were changed to add a
+     counter from the old database and a counter from the new
+     database. The result was disappointing, a large part of the
+     statistics seemed to have vanished mysteriously ...  They of
+     course didn't, values from the old database (known values)
+     were added to values from the new database (unknown values)
+     and the result was unknown.
+
+     In this case, it is fairly reasonable to use a CDEF that
+     alters unknown data into zero. The counters of the device
+
+
+
+24/Oct/1999            Last change: 1.0.13                      6
+
+
+
+
+
+
+rrdtool                                           CDEFTUTORIAL(1)
+
+
+
+     were unknown (after all, it wasn't installed yet!) but you
+     know that the data rate through the device had to be zero
+     (because of the same reason: it was not installed).
+
+     There are some examples further on that make this change.
+
+     IIIInnnnffffiiiinnnniiiittttyyyy
+
+     Infinite data is another form of a special number. It cannot
+     be graphed because by definition you would never reach the
+     infinite value. You could think of positive and negative
+     infinity (I'm not sure if mathematicians will agree)
+     depending on the position relative to zero.
+
+     RRDtool is capable of representing (-not- graphing!)
+     infinity by stopping at its current maximum (for positive
+     infinity) or minimum (for negative infinity) without knowing
+     this maximum (minimum).
+
+     Infinity in rrdtool is mostly used to draw an AREA without
+     knowing its vertical dimensions. You can think of it as
+     drawing an AREA with an infinite height and displaying only
+     the part that is visible in the current graph. This is
+     probably a good way to approximate infinity and it sure
+     allows for some neat tricks. See below for examples.
+
+     WWWWoooorrrrkkkkiiiinnnngggg wwwwiiiitttthhhh uuuunnnnkkkknnnnoooowwwwnnnn ddddaaaattttaaaa aaaannnndddd iiiinnnnffffiiiinnnniiiittttyyyy
+
+     Sometimes you would like to discard unknown data and pretend
+     it is zero (or any other value for that matter) and
+     sometimes you would like to pretend that known data is
+     unknown (to discard known-to-be-wrong data).  This is why
+     CDEFs have support for unknown data. There are also examples
+     available that show unknown data by using infinity.
+
+SSSSoooommmmeeee eeeexxxxaaaammmmpppplllleeeessss
+     EEEExxxxaaaammmmpppplllleeee:::: uuuussssiiiinnnngggg aaaa rrrreeeecccceeeennnnttttllllyyyy ccccrrrreeeeaaaatttteeeedddd RRRRRRRRDDDD
+
+     You are keeping statistics on your router for over a year
+     now. Recently you installed an extra router and you would
+     like to show the combined throughput for these two devices.
+
+     If you just add up the counters from router.rrd and
+     router2.rrd, you will add known data (from router.rrd) to
+     unknown data (from router2.rrd) for the bigger part of your
+     stats. You could solve this in a few ways:
+
+     +o   While creating the new database, fill it with zeros from
+         the start to now.  You have to make the database start
+         at or before the least recent time in the other
+         database.
+
+
+
+
+24/Oct/1999            Last change: 1.0.13                      7
+
+
+
+
+
+
+rrdtool                                           CDEFTUTORIAL(1)
+
+
+
+     +o   Alternately you could use CDEF and alter unknown data to
+         zero.
+
+     Both methods have their pros and cons. The first method is
+     troublesome and if you want to do that you have to figure it
+     out yourself. It is not possible to create a database filled
+     with zeros, you have to put them in on purpose. Implementing
+     the second method is described next:
+
+     What we want is: "if the value is unknown, replace it with
+     zero". This could be writte in pseudo-code as:  if (value is
+     unknown) then (zero) else (value). When reading the rrdgraph
+     manual you notice the "UN" function that returns zero or
+     one. You also notice the "IF" function that takes zero or
+     one as input.
+
+     First look at the "IF" function. It takes three values from
+     the stack, the first value is the decision point, the second
+     value is returned to the stack if the evaluation is "true"
+     and if not, the third value is returned to the stack. We
+     want the "UN" function to decide what happens so we combine
+     those two functions in one CDEF.
+
+     Lets write down the two possible paths for the "IF"
+     function:
+
+        if true  return a
+        if false return b
+
+     In RPN:  result=x,a,b,IF where "x" is either true or false.
+
+     Now we have to fill in "x", this should be the "(value is
+     unknown)" part and this is in RPN:  result=value,UN
+
+     We now combine them: result=value,UN,a,b,IF and when we fill
+     in the appropriate things for "a" and "b" we're finished:
+
+     CDEF:result=value,UN,0,value,IF
+
+     You may want to read Steve Raders RPN guide if you have
+     difficulties with the way I explained this last example.
+
+     If you want to check this RPN expression, just mimic
+     rrdtools behavior:
+
+        For any known value, the expression evaluates as follows:
+        CDEF:result=value,UN,0,value,IF  (value,UN) is not true so it becomes 0
+        CDEF:result=0,0,value,IF         "IF" will return the 3rd value
+        CDEF:result=value                The known value is returned
+
+
+
+
+
+
+24/Oct/1999            Last change: 1.0.13                      8
+
+
+
+
+
+
+rrdtool                                           CDEFTUTORIAL(1)
+
+
+
+        For the unknown value, this happens:
+        CDEF:result=value,UN,0,value,IF  (value,UN) is true so it becomes 1
+        CDEF:result=1,0,value,IF         "IF" sees 1 and returns the 2nd value
+        CDEF:result=0                    Zero is returned
+
+     Of course, if you would like to see another value instead of
+     zero, you can use that other value.
+
+     Eventually, when all unknown data is removed from the RRD,
+     you may want to remove this rule so that unknown data is
+     properly displayed.
+
+     EEEExxxxaaaammmmpppplllleeee:::: bbbbeeeetttttttteeeerrrr hhhhaaaannnnddddlllliiiinnnngggg ooooffff uuuunnnnkkkknnnnoooowwwwnnnn ddddaaaattttaaaa,,,, bbbbyyyy uuuussssiiiinnnngggg ttttiiiimmmmeeee
+
+     Above example has one drawback. If you do log unknown data
+     in your database after installing your new equipment, it
+     will also be translated into zero and therefore you won't
+     see that there was a problem. This is not good and what you
+     really want to do is:
+
+     +o   If there is unknown data, look at the time that this
+         sample was taken
+
+     +o   If the unknown value is before time xxx, make it zero
+
+     +o   If it is after time xxx, leave it as unknown data
+
+     This is doable: you can compare the time that the sample was
+     taken to some known time. Assuming you started to monitor
+     your device on Friday September 17, 00:35:57 MET DST.
+     Translate this time in seconds since 1970-01-01 and it
+     becomes 937521357. If you process unknown values that were
+     received after this time, you want to leave them unknown and
+     if they were "received" before this time, you want to
+     translate them into zero (so you can effectively ignore them
+     while adding them to your other routers counters).
+
+     Translating Friday September 17, 00:35:57 MET DST into
+     937521357 can be done by, for instance, using gnu date:
+
+        date -d "19990917 00:35:57" +%s
+
+     You could also dump the database and see where the data
+     starts to be known. There are several other ways of doing
+     this, just pick one.
+
+     Now we have to create the magic that allows us to process
+     unknown values different depending on the time that the
+     sample was taken.  This is a three step process:
+
+     1.  If the timestamp of the value is after 937521357, leave
+         it as is
+
+
+
+24/Oct/1999            Last change: 1.0.13                      9
+
+
+
+
+
+
+rrdtool                                           CDEFTUTORIAL(1)
+
+
+
+     2.  If the value is a known value, leave it as is
+
+     3.  Change the unknown value into zero.
+
+     Lets look at part one:
+
+         if (true) return the original value
+
+     We rewrite this:
+
+         if (true) return "a"
+         if (false) return "b"
+
+     We need to calculate true or false from step 1. There is a
+     function available that returns the timestamp for the
+     current sample. It is called, how surprisingly, "TIME". This
+     time has to be compared to a constant number, we need "GT".
+     The output of "GT" is true or false and this is good input
+     to "IF". We want "if (time > 937521357) then (return a) else
+     (return b)".
+
+     This process was already described toroughly in the previous
+     chapter so lets do it quick:
+
+        if (x) then a else b
+           where x represents "time>937521357"
+           where a represents the original value
+           where b represents the outcome of the previous example
+
+        time>937521357       --> TIME,937521357,GT
+
+        if (x) then a else b --> x,a,b,IF
+        substitute x         --> TIME,937521357,GT,a,b,IF
+        substitute a         --> TIME,937521357,GT,value,b,IF
+        substitute b         --> TIME,937521357,GT,value,value,UN,0,value,IF,IF
+
+     We end up with:
+     CDEF:result=TIME,937521357,GT,value,value,UN,0,value,IF,IF
+
+     This looks very complex however as you can see it was not
+     too hard to come up with.
+
+     EEEExxxxaaaammmmpppplllleeee:::: PPPPrrrreeeetttteeeennnnddddiiiinnnngggg wwwweeeeiiiirrrrdddd ddddaaaattttaaaa iiiissssnnnn''''tttt tttthhhheeeerrrreeee
+
+     Suppose you have a problem that shows up as huge spikes in
+     your graph.  You know this happens and why so you decide to
+     work around the problem.  Perhaps you're using your network
+     to do a backup at night and by doing so you get almost
+     10mb/s while the rest of your network activity does not
+     produce numbers higher than 100kb/s.
+
+
+
+
+
+24/Oct/1999            Last change: 1.0.13                     10
+
+
+
+
+
+
+rrdtool                                           CDEFTUTORIAL(1)
+
+
+
+     There are two options:
+
+     1.  If the number exceeds 100kb/s it is wrong and you want
+         it masked out by changing it into unknown
+
+     2.  You don't want the graph to show more than 100kb/s
+
+     Pseudo code: if (number > 100) then unknown else number or
+     Pseudo code: if (number > 100) then 100 else number.
+
+     The second "problem" may also be solved by using the rigid
+     option of rrdtool graph, however this has not the same
+     result. In this example you can end up with a graph that
+     does autoscaling. Also, if you use the numbers to display
+     maxima they will be set to 100kb/s.
+
+     We use "IF" and "GT" again. "if (x) then (y) else (z)" is
+     written down as "CDEF:result=x,y,z,IF"; now fill in x, y and
+     z.  For x you fill in "number greater than 100kb/s" becoming
+     "number,100000,GT" (kilo is 1000 and b/s is what we
+     measure!).  The "z" part is "number" in both cases and the
+     "y" part is either "UNKN" for unknown or "100000" for
+     100kb/s.
+
+     The two CDEF expressions would be:
+
+         CDEF:result=number,100000,GT,UNKN,number,IF
+         CDEF:result=number,100000,GT,100000,number,IF
+
+
+     EEEExxxxaaaammmmpppplllleeee:::: YYYYoooouuuu ssssuuuussssppppeeeecccctttt ttttoooo hhhhaaaavvvveeee pppprrrroooobbbblllleeeemmmmssss aaaannnndddd wwwwaaaannnntttt ttttoooo sssseeeeeeee
+     uuuunnnnkkkknnnnoooowwwwnnnn ddddaaaattttaaaa....
+
+     Suppose you add up the number of active users on several
+     terminal servers.  If one of them doesn't give an answer (or
+     an incorrect one) you get "NaN" in the database ("Not a
+     Number") and NaN is evaluated as Unknown.
+
+     In this case, you would like to be alerted to it and the sum
+     of the remaining values is of no value to you.
+
+     It would be something like:
+
+         DEF:users1=location1.rrd:onlineTS1:LAST
+         DEF:users2=location1.rrd:onlineTS2:LAST
+         DEF:users3=location2.rrd:onlineTS1:LAST
+         DEF:users4=location2.rrd:onlineTS2:LAST
+         CDEF:allusers=users1,users2,users3,users4,+,+,+
+
+     If you now plot allusers, unknown data in one of
+     users1..users4 will show up as a gap in your graph. You want
+     to modify this to show a bright red line, not a gap.
+
+
+
+24/Oct/1999            Last change: 1.0.13                     11
+
+
+
+
+
+
+rrdtool                                           CDEFTUTORIAL(1)
+
+
+
+     Define an extra CDEF that is unknown if all is okay and is
+     infinite if there is an unknown value:
+
+         CDEF:wrongdata=allusers,UN,INF,UNKN,IF
+
+     "allusers,UN" will evaluate to either true or false, it is
+     the (x) part of the "IF" function and it checks if allusers
+     is unknown.  The (y) part of the "IF" function is set to
+     "INF" (which means infinity) and the (z) part of the
+     function returns "UNKN".
+
+     The logic is: if (allusers == unknown) then return INF else
+     return UNKN.
+
+     You can now use AREA to display this "wrongdata" in bright
+     red. If it is unknown (because allusers is known) then the
+     red AREA won't show up.  If the value is INF (because
+     allusers is unknown) then the red AREA will be filled in on
+     the graph at that particular time.
+
+        AREA:allusers#0000FF:combined user count
+        AREA:wrongdata#FF0000:unknown data
+
+
+     SSSSaaaammmmeeee eeeexxxxaaaammmmpppplllleeee uuuusssseeeeffffuuuullll wwwwiiiitttthhhh SSSSTTTTAAAACCCCKKKKeeeedddd ddddaaaattttaaaa::::
+
+     If you use stack in the previous example (as I would do)
+     then you don't add up the values. Therefore, there is no
+     relationship between the four values and you don't get a
+     single value to test.  Suppose users3 would be unknown at
+     one point in time: users1 is plotted, users2 is stacked on
+     top of users1, users3 is unknown and therefore nothing
+     happens, users4 is stacked on top of users2.  Add the extra
+     CDEFs anyway and use them to overlay the "normal" graph:
+
+        DEF:users1=location1.rrd:onlineTS1:LAST
+        DEF:users2=location1.rrd:onlineTS2:LAST
+        DEF:users3=location2.rrd:onlineTS1:LAST
+        DEF:users4=location2.rrd:onlineTS2:LAST
+        CDEF:allusers=users1,users2,users3,users4,+,+,+
+        CDEF:wrongdata=allusers,UN,INF,UNKN,IF
+        AREA:users1#0000FF:users at ts1
+        STACK:users2#00FF00:users at ts2
+        STACK:users3#00FFFF:users at ts3
+        STACK:users4#FFFF00:users at ts4
+        AREA:wrongdata#FF0000:unknown data
+
+     If there is unknown data in one of users1..users4, the
+     "wrongdata" AREA will be drawn and because it starts at the
+     X-axis and has infinite height it will effectively overwrite
+     the STACKed parts.
+
+
+
+
+24/Oct/1999            Last change: 1.0.13                     12
+
+
+
+
+
+
+rrdtool                                           CDEFTUTORIAL(1)
+
+
+
+     You could combine the two CDEF lines into one (we don't use
+     "allusers") if you like.  But there are good reasons for
+     writting two CDEFS:
+
+     +o   It improves the readability of the script
+
+     +o   It can be used inside GPRINT to display the total number
+         of users
+
+     If you choose to combine them, you can substitute the
+     "allusers" in the second CDEF with the part after the equal
+     sign from the first line:
+
+        CDEF:wrongdata=users1,users2,users3,users4,+,+,+,UN,INF,UNKN,IF
+
+     If you do so, you won't be able to use these next GPRINTs:
+
+        COMMENT:"Total number of users seen"
+        GPRINT:allusers:MAX:"Maximum: %6.0lf"
+        GPRINT:allusers:MIN:"Minimum: %6.0lf"
+        GPRINT:allusers:AVERAGE:"Average: %6.0lf"
+        GPRINT:allusers:LAST:"Current: %6.0lf\n"
+
+
+TTTThhhheeee eeeexxxxaaaammmmpppplllleeeessss ffffrrrroooommmm tttthhhheeee rrrrrrrrdddd ggggrrrraaaapppphhhh mmmmaaaannnnuuuuaaaallll ppppaaaaggggeeee
+     DDDDeeeeggggrrrreeeeeeeessss CCCCeeeellllcccciiiiuuuussss vvvvssss.... DDDDeeeeggggrrrreeeeeeeessss FFFFaaaahhhhrrrreeeennnnhhhheeeeiiiitttt
+
+        rrdtool graph demo.gif --title="Demo Graph" \
+           DEF:cel=demo.rrd:exhaust:AVERAGE \
+           CDEF:far=cel,32,-,0.55555,* \
+           LINE2:cel#00a000:"D. Celsius" \
+           LINE2:far#ff0000:"D. Fahrenheit\c"
+
+     This example gets the DS called "exhaust" from database
+     "demo.rrd" and puts the values in variable "cel". The CDEF
+     used is evaluated as follows:
+
+        CDEF:far=cel,32,-,0.5555,*
+        1. push variable "cel"
+        2. push 32
+        3. push function "minus" and process it
+           The stack now contains values that are 32 less than "cel"
+        4. push 0.5555
+        5. push function "multiply" and process it
+        6. the resulting value is now "(cel-32)*0.55555"
+
+     Note that if you take the celcius to fahrenheit function you
+     should be doing "5/9*(cel-32)" so 0.55555 is not exactly
+     correct. It is close enough for this purpose and it saves a
+     calculation.
+
+
+
+
+
+24/Oct/1999            Last change: 1.0.13                     13
+
+
+
+
+
+
+rrdtool                                           CDEFTUTORIAL(1)
+
+
+
+     CCCChhhhaaaannnnggggiiiinnnngggg uuuunnnnkkkknnnnoooowwwwnnnn iiiinnnnttttoooo zzzzeeeerrrroooo
+
+        rrdtool graph demo.gif --title="Demo Graph" \
+           DEF:idat1=interface1.rrd:ds0:AVERAGE \
+           DEF:idat2=interface2.rrd:ds0:AVERAGE \
+           DEF:odat1=interface1.rrd:ds1:AVERAGE \
+           DEF:odat2=interface2.rrd:ds1:AVERAGE \
+           CDEF:agginput=idat1,UN,0,idat1,IF,idat2,UN,0,idat2,IF,+,8,* \
+           CDEF:aggoutput=odat1,UN,0,odat1,IF,odat2,UN,0,odat2,IF,+,8,* \
+           AREA:agginput#00cc00:Input Aggregate \
+           LINE1:aggoutput#0000FF:Output Aggregate
+
+     These two CDEFs are built from several functions. It helps
+     to split them when viewing what they do.  Starting with the
+     first CDEF we would get:
+           idat1,UN --> a
+           0        --> b
+           idat1    --> c
+           if (a) then (b) else (c) The result is therefore "0"
+     if it is true that "idat1" equals "UN".  If not, the
+     original value of "idat1" is put back on the stack.  Lets
+     call this answer "d". The process is repeated for the next
+     five items on the stack, it is done the same and will return
+     answer "h". The resulting stack is therefore "d,h".  The
+     expression has been simplified to "d,h,+,8,*" and it will
+     now be easy to see that we add "d" and "h", and multiply the
+     result with eight.
+
+     The end result is that we have added "idat1" and "idat2" and
+     in the process we effectively ignored unknown values. The
+     result is multiplied by eight, most likely to convert
+     bytes/s to bits/s.
+
+     IIIInnnnffffiiiinnnniiiittttyyyy ddddeeeemmmmoooo
+
+        rrdtool graph example.png --title="INF demo" \
+           DEF:val1=some.rrd:ds0:AVERAGE \
+           DEF:val2=some.rrd:ds1:AVERAGE \
+           DEF:val3=some.rrd:ds2:AVERAGE \
+           DEF:val4=other.rrd:ds0:AVERAGE \
+           CDEF:background=val4,POP,TIME,7200,%,3600,LE,INF,UNKN,IF \
+           CDEF:wipeout=val1,val2,val3,val4,+,+,+,UN,INF,UNKN,IF \
+           AREA:background#F0F0F0 \
+           AREA:val1#0000FF:Value1 \
+           STACK:val2#00C000:Value2 \
+           STACK:val3#FFFF00:Value3 \
+           STACK:val4#FFC000:Value4 \
+           AREA:whipeout#FF0000:Unknown
+
+     This demo demonstrates two ways to use infinity. It is a bit
+     tricky to see what happens in the "background" CDEF.
+
+
+
+
+24/Oct/1999            Last change: 1.0.13                     14
+
+
+
+
+
+
+rrdtool                                           CDEFTUTORIAL(1)
+
+
+
+        "val4,POP,TIME,7200,%,3600,LE,INF,UNKN,IF"
+
+     This RPN takes the value of "val4" as input and then
+     immediately removes it from the stack using "POP". The stack
+     is now empty but as a side result we now know the time that
+     this sample was taken.  This time is put on the stack by the
+     "TIME" function.
+
+     "TIME,7200,%" takes the modulo of time and 7200 (which is
+     two hours).  The resulting value on the stack will be a
+     number in the range from 0 to 7199.
+
+     For people who don't know the modulo function: it is the
+     remainder after an integer division. If you divide 16 by 3,
+     the answer would be 5 and the remainder would be 1. So,
+     "16,3,%" returns 1.
+
+     We have the result of "TIME,7200,%" on the stack, lets call
+     this "a". The start of the RPN has become "a,3600,LE" and
+     this checks if "a" is less or equal than "3600". It is true
+     half of the time.  We now have to process the rest of the
+     RPN and this is only a simple "IF" function that returns
+     either "INF" or "UNKN" depending on the time. This is
+     returned to variable "background".
+
+     The second CDEF has been discussed earlyer in this document
+     so we won't do that here.
+
+     Now you can draw the different layers. Start with the
+     background that is either unknown (nothing to see) or
+     infinite (the whole positive part of the graph gets filled).
+     Next you draw the data on top of this background. It will
+     overlay the background. Suppose one of val1..val4 would be
+     unknown, in that case you end up with only three bars
+     stacked on top of each other.  You don't want to see this
+     because the data is only valid when all four variables are
+     valid. This is why you use the second CDEF, it will overlay
+     the data with an AREA so the data cannot be seen anymore.
+
+     If your data can also have negative values you also need to
+     overwrite the other half of your graph. This can be done in
+     a relatively simple way: what you need is the "wipeout"
+     variable and place a negative sign before it:
+     "CDEF:wipeout2=wipeout,-1,*"
+
+     =head1 Out of ideas for now
+
+     This document was created from questions asked by either
+     myself or by other people on the list. Please let me know if
+     you find errors in it or if you have trouble understanding
+     it. If you think there should be an addition, mail me:
+     <alex at ergens.op.het.net>
+
+
+
+24/Oct/1999            Last change: 1.0.13                     15
+
+
+
+
+
+
+rrdtool                                           CDEFTUTORIAL(1)
+
+
+
+     Remember: NNNNoooo ffffeeeeeeeeddddbbbbaaaacccckkkk eeeeqqqquuuuaaaallllssss nnnnoooo cccchhhhaaaannnnggggeeeessss!!!!
+
+SSSSEEEEEEEE AAAALLLLSSSSOOOO
+     The RRDtool manpages
+
+AAAAUUUUTTTTHHHHOOOORRRR
+     Alex van den Bogaerdt <alex at ergens.op.het.net>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+24/Oct/1999            Last change: 1.0.13                     16
+
+
+
+
+
+
+rrdtool                                           CDEFTUTORIAL(1)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+24/Oct/1999            Last change: 1.0.13                     17
+
+
+
+
+
+

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/rrdtool.txt
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/rrdtool.txt	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/rrdtool.txt	Sat Jul 13 21:08:15 2002
@@ -1,240 +1,240 @@
 
 
 
-RRDTOOL(1)                   rrdtool                   RRDTOOL(1)
+rrdtool                                                RRDTOOL(1)
+
 
 
 NNNNAAAAMMMMEEEE
-       rrdtool - round robin database tool
+     rrdtool - round robin database tool
 
 SSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS
-       rrrrrrrrddddttttoooooooollll ---- | _f_u_n_c_t_i_o_n
+     rrrrrrrrddddttttoooooooollll ---- | _f_u_n_c_t_i_o_n
 
 DDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
-       OOOOVVVVEEEERRRRVVVVIIIIEEEEWWWW
+     OOOOVVVVEEEERRRRVVVVIIIIEEEEWWWW
+
+     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 rrrrrrrrddddttttoooooooollll kicks in. It lets you _l_o_g _a_n_d _a_n_a_l_y_z_e the data
+     you gather from all kinds of data-sources (DDDDSSSS). 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.
+
+     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 rrrrrrrrddddttttoooooooollll check the corresponding
+     man page.
+
+     For an introduction to the usage of rrdtool make sure you
+     check the _r_r_d_t_u_t_o_r_i_a_l manpage.
 
-       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 rrrrrrrrddddttttoooooooollll kicks in. It lets you _l_o_g
-       _a_n_d _a_n_a_l_y_z_e the data you gather from all kinds of data-
-       sources (DDDDSSSS). 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.
+     FFFFUUUUNNNNCCCCTTTTIIIIOOOONNNNSSSS
 
-       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 rrrrrrrrddddttttoooooooollll check the
-       corresponding man page.
+     While the man pages talk of command line switches you have
+     to set in order to make rrrrrrrrddddttttoooooooollll work it is important to note
+     that the rrrrrrrrddddttttoooooooollll can be 'remote controlled' through a set of
+     pipes. This saves a considerable amount of startup time when
+     you plan to make rrrrrrrrddddttttoooooooollll do a lot of things quickly. Check
+     the section on the section on _R_e_m_o_t_e _C_o_n_t_r_o_l further down.
 
-       For an introduction to the usage of rrdtool make sure you
-       check the _r_r_d_t_u_t_o_r_i_a_l manpage.
+     ccccrrrreeeeaaaatttteeee  Set up a new Round Robin Database (RRD). Check the
+             _r_r_d_c_r_e_a_t_e manpage.
 
-       FFFFUUUUNNNNCCCCTTTTIIIIOOOONNNNSSSS
+     uuuuppppddddaaaatttteeee  Store new data values into an RRD. Check the
+             _r_r_d_u_p_d_a_t_e manpage.
 
-       While the man pages talk of command line switches you have
-       to set in order to make rrrrrrrrddddttttoooooooollll work it is important to
-       note that the rrrrrrrrddddttttoooooooollll can be 'remote controlled' through a
-       set of pipes. This saves a considerable amount of startup
-       time when you plan to make rrrrrrrrddddttttoooooooollll do a lot of things
-       quickly. Check the section on the section on _R_e_m_o_t_e
-       _C_o_n_t_r_o_l further down.
+     ggggrrrraaaapppphhhh   Create a graph from data stored in one or several
+             RRD. Apart from generating graphs, data can also be
+             extracted to stdout. Check the _r_r_d_g_r_a_p_h manpage.
 
-       ccccrrrreeeeaaaatttteeee  Set up a new Round Robin Database (RRD). Check the
-               _r_r_d_c_r_e_a_t_e manpage.
+     dddduuuummmmpppp    Dump the contents of an RRD in plain ASCII. In
+             connection with restore you can use it to transport
+             an rrd from one architecture to another.  Check the
+             _r_r_d_d_u_m_p manpage.
 
-       uuuuppppddddaaaatttteeee  Store new data values into an RRD. Check the
-               _r_r_d_u_p_d_a_t_e manpage.
 
-       ggggrrrraaaapppphhhh   Create a graph from data stored in one or several
-               RRD. Apart from generating graphs, data can also
-               be extracted to stdout. Check the _r_r_d_g_r_a_p_h
-               manpage.
 
-       dddduuuummmmpppp    Dump the contents of an RRD in plain ASCII. In
-               connection with restore you can use it to
-               transport an rrd from one architecture to another.
+24/Oct/1999            Last change: 1.0.13                      1
 
 
 
-25/Aug/99                     1.0.7                             1
 
 
 
+rrdtool                                                RRDTOOL(1)
 
 
-RRDTOOL(1)                   rrdtool                   RRDTOOL(1)
 
+     rrrreeeessssttttoooorrrreeee Restore an RRD in XML format to a binary rrd ...
+             Check the _r_r_d_r_e_s_t_o_r_e manpage
 
-               Check the _r_r_d_d_u_m_p manpage.
+     ffffeeeettttcccchhhh   Get data for a certain time period from a RRD. The
+             graph function uses fetch to retrieve its data from
+             an rrd. Check the _r_r_d_f_e_t_c_h manpage.
 
-       rrrreeeessssttttoooorrrreeee Restore an RRD in XML format to a binary rrd ...
-               Check the _r_r_d_r_e_s_t_o_r_e manpage
+     ttttuuuunnnneeee    Alter setup of an RRD. Check the _r_r_d_t_u_n_e manpage.
 
-       ffffeeeettttcccchhhh   Get data for a certain time period from a RRD. The
-               graph function uses fetch to retrieve its data
-               from an rrd. Check the _r_r_d_f_e_t_c_h manpage.
+     llllaaaasssstttt    Find last update time of an RRD. Check the _r_r_d_l_a_s_t
+             manpage.
 
-       ttttuuuunnnneeee    Alter setup of an RRD. Check the _r_r_d_t_u_n_e manpage.
+     rrrrrrrrddddrrrreeeessssiiiizzzzeeee
+             Change the size of individual RRAs ... Dangerous!
+             Check the _r_r_d_r_e_s_i_z_e manpage.
 
-       llllaaaasssstttt    Find last update time of an RRD. Check the _r_r_d_l_a_s_t
-               manpage.
+     rrrrrrrrddddccccggggiiii  This is a standalone tool for producing rrd graphs
+             on the fly. Check the _r_r_d_c_g_i manpage.
 
-       rrrrrrrrddddrrrreeeessssiiiizzzzeeee
-               Change the size of individual RRAs ... Dangerous!
-               Check the _r_r_d_r_e_s_i_z_e manpage.
+     HHHHOOOOWWWW DDDDOOOOEEEESSSS RRRRRRRRDDDDTTTTOOOOOOOOLLLL WWWWOOOORRRRKKKK????
 
-       rrrrrrrrddddccccggggiiii  This is a standalone tool for producing rrd graphs
-               on the fly. Check the _r_r_d_c_g_i manpage.
+     Data acquisition
+             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 rrrrrrrrddddttttoooooooollll lets you update the logfile at any
+             time you want. It will automatically interpolate the
+             value of the data-source (DDDDSSSS) 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.
 
-       HHHHOOOOWWWW DDDDOOOOEEEESSSS RRRRRRRRDDDDTTTTOOOOOOOOLLLL WWWWOOOORRRRKKKK????
+     Consolidation
+             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. rrrrrrrrddddttttoooooooollll offers a solution to this of this
+             problem through its data consolidation feature. When
+             setting up an Round Robin Database (RRRRRRRRDDDD), you can
+             define at which interval this consolidation should
+             occur, and what consolidation function (CCCCFFFF)
+             (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 RRRRRRRRDDDD. They will all
+             be maintained on the fly when new data is loaded
 
 
-       Data acquisition
-               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 rrrrrrrrddddttttoooooooollll lets you update the
-               logfile at any time you want. It will
-               automatically interpolate the value of the data-
-               source (DDDDSSSS) 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.
 
-       Consolidation
-               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. rrrrrrrrddddttttoooooooollll offers a solution
-               to this of this problem through its data
-               consolidation feature. When setting up an Round
-               Robin Database (RRRRRRRRDDDD), you can define at which
-               interval this consolidation should occur, and what
-               consolidation function (CCCCFFFF) (average, minimum,
-               maximum, total, last) should be used to build the
-               consolidated values (see rrdcreate). You can
-               define any number of different consolidation
+24/Oct/1999            Last change: 1.0.13                      2
 
 
 
-25/Aug/99                     1.0.7                             2
 
 
 
+rrdtool                                                RRDTOOL(1)
 
 
-RRDTOOL(1)                   rrdtool                   RRDTOOL(1)
 
+             into the RRRRRRRRDDDD.
 
-               setups within one RRRRRRRRDDDD. They will all be maintained
-               on the fly when new data is loaded into the RRRRRRRRDDDD.
+     Round Robin Archives
+             Data values of the same consolidation setup are
+             stored into Round Robin Archives (RRRRRRRRAAAA). This is a
+             very efficient manner to store data for a certain
+             amount of time, while using a known amount of
+             storage space.
 
-       Round Robin Archives
-               Data values of the same consolidation setup are
-               stored into Round Robin Archives (RRRRRRRRAAAA). This is a
-               very efficient manner to store data for a certain
-               amount of time, while using a known amount of
-               storage space.
+             It works like this: If you want to store 1000 values
+             in 5 minute interval, rrrrrrrrddddttttoooooooollll 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 RRRRRRRRAAAAs within a
+             single RRRRRRRRDDDD, 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.
 
-               It works like this: If you want to store 1000
-               values in 5 minute interval, rrrrrrrrddddttttoooooooollll 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 RRRRRRRRAAAAs within a single RRRRRRRRDDDD, 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.
+             The use of RRRRRRRRAAAAs guarantees that the RRRRRRRRDDDD 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 (CCCCFFFF) allows you to store exactly the type
+             of information that actually interests you. (Maximum
+             one minute traffic on the LAN, minimum temperature
+             of the wine cellar, total minutes down time ...)
 
-               The use of RRRRRRRRAAAAs guarantees that the RRRRRRRRDDDD 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 (CCCCFFFF) allows you to store
-               exactly the type of information that actually
-               interests you. (Maximum one minute traffic on the
-               LAN, minimum temperature of the wine cellar, total
-               minutes down time ...)
+     Unknown Data
+             As mentioned earlier, the RRRRRRRRDDDD 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 RRRRRRRRDDDD. Data acquisition may not be possible for
+             one reason or an other. The rrrrrrrrddddttttoooooooollll handles these
+             situations by storing an *_U_N_K_N_O_W_N* value into the
+             database. The value '*_U_N_K_N_O_W_N*' is supported through
+             all the functions of the database. When
+             consolidating the amount of *_U_N_K_N_O_W_N* data is
+             accumulated and when a new consolidated value is
+             ready to be written to its Round Robin Archive (RRRRRRRRAAAA)
+             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 *_U_N_K_N_O_W_N* value will
+             be written to the RRRRRRRRAAAA.
 
-       Unknown Data
-               As mentioned earlier, the RRRRRRRRDDDD 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 RRRRRRRRDDDD. Data acquisition may not be possible
-               for one reason or an other. The rrrrrrrrddddttttoooooooollll handles
-               these situations by storing an _*_U_N_K_N_O_W_N_* value
-               into the database. The value '_*_U_N_K_N_O_W_N_*' is
-               supported through all the functions of the
-               database. When consolidating the amount of
-               _*_U_N_K_N_O_W_N_* data is accumulated and when a new
-               consolidated value is ready to be written to its
-               Round Robin Archive (RRRRRRRRAAAA) 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 _*_U_N_K_N_O_W_N_* value will
-               be written to the RRRRRRRRAAAA.
 
 
 
 
-25/Aug/99                     1.0.7                             3
+24/Oct/1999            Last change: 1.0.13                      3
 
 
 
 
 
-RRDTOOL(1)                   rrdtool                   RRDTOOL(1)
 
+rrdtool                                                RRDTOOL(1)
 
-       Graphing
-               The rrrrrrrrddddttttoooooooollll also allows one to generate reports in
-               numerical and graphical form based on the data
-               stored in one or several RRRRRRRRDDDDs. The graphing
-               feature is fully configurable. Size, color and
-               contents of the graph can be defined freely. Check
-               the _r_r_d_g_r_a_p_h manpage for more information on this.
 
-       RRRREEEEMMMMOOOOTTTTEEEE CCCCOOOONNNNTTTTRRRROOOOLLLL
 
-       When you start rrrrrrrrddddttttoooooooollll with the command line option '----',
-       it waits for input via standard in. With this feature you
-       can improve performance by attaching rrrrrrrrddddttttoooooooollll to another
-       process (mrtg is one example) through a set of pipes. Over
-       the pipes rrrrrrrrddddttttoooooooollll accepts the same arguments as on the
-       command line. When a command is completed, rrdtool will
-       print the string  'OK', followed by timing information of
-       the form uuuu::::_u_s_e_r_t_i_m_e ssss::::_s_y_s_t_e_m_t_i_m_e both values are running
-       totals of seconds since rrdtool was started. If an error
-       occurs, a line of the form 'ERROR: _D_e_s_c_r_i_p_t_i_o_n _o_f _e_r_r_o_r'
-       will be printed. rrrrrrrrddddttttoooooooollll will not abort if possible, but
-       follow the ERROR line with an OK line.
+     Graphing
+             The rrrrrrrrddddttttoooooooollll also allows one to generate reports in
+             numerical and graphical form based on the data
+             stored in one or several RRRRRRRRDDDDs. The graphing feature
+             is fully configurable. Size, color and contents of
+             the graph can be defined freely. Check the _r_r_d_g_r_a_p_h
+             manpage for more information on this.
+
+     RRRREEEEMMMMOOOOTTTTEEEE CCCCOOOONNNNTTTTRRRROOOOLLLL
+
+     When you start rrrrrrrrddddttttoooooooollll with the command line option '----', it
+     waits for input via standard in. With this feature you can
+     improve performance by attaching rrrrrrrrddddttttoooooooollll to another process
+     (mrtg is one example) through a set of pipes. Over the pipes
+     rrrrrrrrddddttttoooooooollll accepts the same arguments as on the command line.
+     When a command is completed, rrdtool will print the string
+     'OK', followed by timing information of the form uuuu::::_u_s_e_r_t_i_m_e
+     ssss::::_s_y_s_t_e_m_t_i_m_e both values are running totals of seconds since
+     rrdtool was started. If an error occurs, a line of the form
+     'ERROR: _D_e_s_c_r_i_p_t_i_o_n _o_f _e_r_r_o_r' will be printed. rrrrrrrrddddttttoooooooollll will
+     not abort if possible, but follow the ERROR line with an OK
+     line.
 
 SSSSEEEEEEEE AAAALLLLSSSSOOOO
-       rrdcreate, rrdupdate, rrdgraph, rrddump, rrdfetch,
-       rrdtune, rrdlast
+     rrdcreate, rrdupdate, rrdgraph, rrddump, rrdfetch, rrdtune,
+     rrdlast
 
 BBBBUUUUGGGGSSSS
-       Bugs ? Features !
+     Bugs ? Features !
 
 AAAAUUUUTTTTHHHHOOOORRRR
-       Tobias Oetiker <oetiker at ee.ethz.ch>
-
+     Tobias Oetiker <oetiker at ee.ethz.ch>
 
 
 
@@ -258,14 +258,14 @@
 
 
 
+24/Oct/1999            Last change: 1.0.13                      4
 
-25/Aug/99                     1.0.7                             4
 
 
 
 
 
-RRDTOOL(1)                   rrdtool                   RRDTOOL(1)
+rrdtool                                                RRDTOOL(1)
 
 
 
@@ -321,10 +321,10 @@
 
 
 
+24/Oct/1999            Last change: 1.0.13                      5
 
 
 
 
-25/Aug/99                     1.0.7                             5
 
 

Added: trunk/orca/packages/rrdtool-1.0.13/doc/rpntutorial.pod
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/rpntutorial.pod	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/rpntutorial.pod	Sat Jul 13 21:08:16 2002
@@ -0,0 +1,198 @@
+=head1 NAME
+
+rpntutorial - Reading RRDTtool RPN Expressions by Steve Rader
+
+=head1 DESCRIPTION
+
+This tutorial should help you get to grips with rrdtool RPN expressions
+as seen in CDEF arguments of rrdtool graph.
+
+=head1 Reading Comparison Operators
+
+The LT, LE, GT, GE and EQ RPN logic operators are not as tricky as
+they appear.  These operators act on the two values on the stack
+preceding them (to the left).  Read these two values on the stack
+from left to right inserting the operator in the middle.  If the
+resulting statement is true, the replace the three values from the
+stack with "1".  If the statement if false, replace the three values
+with "0".
+
+For example think about "2,1,GT".  This RPN expression could be
+read as "is two greater than one?"  The answer to that question is
+"true".  So the three values should be replaced with "1".  Thus the
+RPN expression 2,1,GT evaluates to 1.
+
+Now also consider "2,1,LE".  This RPN expression could be read as "is
+two less than or equal to one?".   The natural response is "no"
+and thus the RPN expression 2,1,LE evaluates to 0. 
+
+=head1 Reading the IF Operator
+
+The IF RPN logic operator can be straightforward also.  The key
+to reading IF operators is to understand that the condition part
+of the traditional "if X than Y else Z" notation has *already*
+been evaluated.  So the IF operator acts on only one value on the
+stack: the third value to the left of the IF value.  The second
+value to the left of the IF corresponds to the true ("Y") branch.
+And the first value to the left of the IF corresponds to the false
+("Z") branch.  Read the RPN expression "X,Y,Z,IF" from left to
+right like so: "if X then Y else Z".
+
+For example, consider "1,10,100,IF".  It looks bizzare to me.
+But when I read "if 1 then 10 else 100" it's crystal clear: 1 is true
+so the answer is 10.  Note that only zero is false; all other values
+are true.  "2,20,200,IF" ("if 2 then 20 else 200") evaluates to 20.
+And "0,1,2,IF" ("if 0 then 1 else 2) evaluates to 2.
+
+
+Notice that none of the above examples really simulate the whole
+"if X then Y else Z" statement.  This is because computer programmers
+read this statement as "if Some Condition then Y else Z".  So it's
+important to be able to read IF operators along with the LT, LE,
+GT, GE and EQ operators.
+
+=head1 Some Examples
+
+While compound expressions can look overly complex, they can be
+considered elegantly simple.  To quickly comprehend RPN expressions,
+you must know the the algorithm for evaluating RPN expressions:
+iterate searches from the left to the right looking for an operator,
+when it's found, apply that operator by popping the operator and some
+number of values (and by definition, not operators) off the stack.
+
+For example, the stack "1,2,3,+,+" gets "2,3,+" evaluated (as "2+3")
+during the first iteration which is replaced by 5.  This results in
+the stack "1,5,+".  Finally, "1,5,+" is evaluated resulting in the
+answer 6.  For convenience sake, it's useful to write this set of
+operations as:
+
+ 1) 1,2,3,+,+    eval is 2,3,+ = 5    result is 1,5,+
+ 2) 1,5,+        eval is 1,5,+ = 6    result is 6
+ 3) 6
+
+Let's use that notation to conviently solve some complex RPN expressions
+with multiple logic operators:
+
+ 1) 20,10,GT,10,20,IF  eval is 20,10,GT = 1     result is 1,10,20,IF
+
+read the eval as pop "20 is greater than 10" so push 1
+ 
+ 2) 1,10,20,IF         eval is 1,10,20,IF = 10  result is 10
+
+read pop "if 1 then 10 else 20" so push 10.  Only 10 is left so
+10 is the answer.
+
+Let's read a complex RPN expression that also has the traditional
+multiplication operator:
+
+ 1) 128,8,*,7000,GT,7000,128,8,*,IF  eval 128,8,*       result is 1024
+ 2) 1024,7000,GT,7000,128,8,*,IF     eval 1024,7000,GT  result is 0
+ 3) 0,128,8,*,IF                     eval 128,8,*       result is 1024
+ 4) 0,7000,1024,IF                                      result is 1024
+
+
+Now let's go back to the first example of multiple logic operators
+but replace the value 20 with the variable "input":
+
+ 1) input,10,GT,10,input,IF  eval is input,10,GT  result is A
+
+Read eval as "if input > 10 then true" and replace "input,10,GT"
+with "A:
+  
+ 2) A,10,input,IF            eval is A,10,input,IF
+
+read "if A then 10 else input".  Now replace A it's verbose
+description and--voila!--you have a easily readable description
+of the expression:
+
+ if input > 10 then 10 else input
+
+Lastly, let's to back the first most complex example and replace
+the value 128 with "input":
+
+ 1) input,8,*,7000,GT,7000,input,8,*,IF  eval input,8,*     result is A
+
+where A is "input * 8"
+
+ 2) A,7000,GT,7000,input,8,*,IF          eval is A,7000,GT  result is B
+
+where B is "if ((input * 8) > 7000) then true"
+
+ 3) B,7000,input,8,*,IF                  eval is input,8,*  result is C
+
+where C is "input * 8"
+
+ 4) B,7000,C,IF
+
+At last we have a readable decoding of the complex RPN expression with
+a variable:
+
+ if ((input * 8) > 7000) then 7000 else (input * 8)
+
+=head1 Exercises
+
+Exercise 1:
+
+Compute "3,2,*,1,+ and "3,2,1,+,*" by hand.  Rewrite them in
+traditional notation.  Explain why they have different answers.
+
+Answer 1:
+
+    3*2+1 = 7 and 3*(2+1) = 9.  These expressions have
+    different answers because the altering of the plus and 
+    times operators alter the order of their evaluation.
+
+
+Exercise 2:
+
+One may be tempted to shorten the expression
+
+ input,8,*,56000,GT,56000,input,*,8,IF
+
+by removing the redundant use of "input,8,*" like so:
+
+ input,56000,GT,56000,input,IF,8,*
+
+Use tradition notation to show these expressions are not the same.
+Write an expression that's equivalent to the first expression but
+uses the LE and DIV operators.
+
+Answer 2:
+
+    if (input <= 56000/8 ) { input*8 } else { 56000 }
+    input,56000,8,DIV,LT,input,8,*,56000,IF
+
+
+Exercise 3:
+
+Briefly explain why traditional mathematic notation requires the
+use of parentheses.  Explain why RPN notation does not require
+the use of parentheses.
+
+Answer 3:
+
+    Traditional mathematic expressions are evaluated by
+    doing multiplication and division first, then addition and
+    subtraction.  Perentences are used to force the evaluation of
+    addition before multiplication (etc).  RPN does not require
+    parentheses because the ordering of objects on the stack
+    can force the evaluation of addition before multiplication.
+
+
+Exercise 4:
+
+Explain why it is desirable for the RRDtool developers to implement
+RPN notation instead of traditional mathematical notation.
+
+Answer 4:
+
+    The algorithm that implements traditional mathematical
+    notation is more complex then algorithm used for RPN.
+    So implementing RPN allowed Tobias Oetiker to write less
+    code!  (The code is also less complex and therefore less
+    likely to have bugs.)
+
+
+=head1 AUTHOR
+
+steve rader E<lt>rader at wiscnet.netE<gt>

Added: trunk/orca/packages/rrdtool-1.0.13/doc/cdeftutorial.pod
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/cdeftutorial.pod	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/cdeftutorial.pod	Sat Jul 13 21:08:16 2002
@@ -0,0 +1,816 @@
+=head1 NAME
+
+cdeftutorial - Alex van den Bogaerdt's CDEF tutorial
+
+=head1 DESCRIPTION
+
+B<You provide a question and I will try to provide an answer in the next
+release>. B<No feedback equals no changes!>
+
+I<Additions to this document are also welcome.>
+
+Alex van den Bogaerdt E<lt>alex at ergens.op.het.netE<gt>
+
+=head2 Why this tutorial ?
+
+One of the powerful parts of RRDtool is its ability to do all sorts
+of calculations on the data retrieved from it's databases. However
+RRDtool's many options and syntax make it difficult for the average
+user to understand. The manuals are good at explaining what these
+options do; however they do not (and should not) explain in detail
+why they are useful. As with my RRDtool tutorial: if you want a
+simple document in simple language you should read this tutorial.
+If you are happy with the official documentation, you may find this
+document too simple or even boring. If you do choose to read this
+tutorial, I also expect you to have read and fully understand my
+other tutorial. 
+
+=head2 More reading
+
+If you have difficulties with the way I try to explain them please read
+Steve Rader's L<rpntutorial>. It may help you understand how this all works.
+
+=head1 What are CDEFs ?
+
+When retrieving data from an RRD, you are using a "DEF" to work with
+that data. Think of it as a variable that changes over time (where
+time is the x-axis). The value of this variable is what is found in
+the database at that particular time and you can't do any
+modifications on it. This is what CDEFs are for: they takes values
+from DEFs and perform calculations on them.
+
+=head1 Syntax
+
+   DEF:var_name_1=some.rrd:ds_name:CF
+   CDEF:var_name_2=RPN_expression
+
+You first define "var_name_1" to be data collected from data source
+"ds_name" found in RRD "some.rrd" with consolidation function "CF".
+
+Assume the ifInOctets SNMP counter is saved in mrtg.rrd as the DS "in".
+Then the following DEF defines a variable for the average of that
+data source:
+
+   DEF:inbytes=mrtg.rrd:in:AVERAGE
+
+Say you want to display bits per second (instead of bytes per second
+as stored in the database.)  You have to define a calculation
+(hence "CDEF") on variable "inbytes" and use that variable (inbits)
+instead of the original:
+
+   CDEF:inbits=inbytes,8,*
+
+It tells to multiply inbytes by eight to get inbits. I'll explain later
+how this works. In the graphing or printing functions, you can now use
+inbits where you would use inbytes otherwise.
+
+Note that variable in the CDEF (inbits) must not be the same as the
+variable (inbytes) in the DEF!
+
+=head1 RPN-expressions
+
+RPN is short-hand for Reverse Polish Notation. It works as follows.
+You put the variables or numbers on a stack. You also put operations
+(things-to-do) on the stack and this stack is then processed. The result
+will be placed on the stack. At the end, there should be exactly one
+number left: the outcome of the series of operations. If there is not
+exactly one number left, rrdtool will complain loudly.
+
+Above multiplication by eight will look like:
+
+=over 4
+
+=item 1.
+
+Start with an empty stack
+
+=item 2.
+
+Put the content of variable inbytes on the stack
+
+=item 3.
+
+Put the number eight on the stack
+
+=item 4.
+
+Put the operation multiply on the stack
+
+=item 5.
+
+Process the stack
+
+=item 6.
+
+Retrieve the value from the stack and put it in variable inbits
+
+=back
+
+We will now do an example with real numbers. Suppose the variable
+inbytes would have value 10, the stack would be:
+
+=over 4
+
+=item 1.
+
+||
+
+=item 2.
+
+|10|
+
+=item 3.
+
+|10|8|
+
+=item 4.
+
+|10|8|*|
+
+=item 5.
+
+|80|
+
+=item 6.
+
+||
+
+=back 
+
+Processing the stack (step 5) will retrieve one value from the stack
+(from the right at step 4). This is the operation multiply and this
+takes two values off the stack as input. The result is put back on the
+stack (the value 80 in this case). For multiplication the order doesn't
+matter but for other operations like subtraction and division it does.
+Generally speaking you have the following order:
+
+   y = A - B  -->  y=minus(A,B)  -->  CDEF:y=A,B,-
+
+This is not very intuitive (at least most people don't think so). For
+the function f(A,B) you reverse the position of "f" but you do not
+reverse the order of the variables. 
+
+=head1 Converting your wishes to RPN
+
+First, get a clear picture of what you want to do. Break down the problem
+in smaller portions until they cannot be split anymore. Then it is rather
+simple to convert your ideas into RPN.
+
+Suppose you have several RRDs and would like to add up some counters in
+them. These could be, for instance, the counters for every WAN link you
+are monitoring.
+
+You have:
+
+   router1.rrd with link1in link2in
+   router2.rrd with link1in link2in
+   router3.rrd with link1.in
+
+Suppose you would like to add up all these counters, except for link2in
+inside router2.rrd. You need to do:
+
+(in this example, "router1.rrd:link1in" means the DS link1in inside the
+RRD router1.rrd)
+
+   router1.rrd:link1in
+   router1.rrd:link2in
+   router2.rrd:link1in
+   router3.rrd:link1in
+   router3.rrd:link2in 
+   --------------------   +
+   (outcome of the sum)
+
+As a mathmatical function, this could be written:
+
+C<add(router1.rrd:link1in , router1.rrd:link2in , router2.rrd:link1in , router3.rrd:link1in , router3.rrd:link2.in)>
+
+With RRDtool and RPN, first, define the inputs:
+
+   DEF:a=router1.rrd:link1in:AVERAGE
+   DEF:b=router1.rrd:link2in:AVERAGE
+   DEF:c=router2.rrd:link1in:AVERAGE
+   DEF:d=router3.rrd:link1in:AVERAGE
+   DEF:e=router3.rrd:link2in:AVERAGE
+
+Now, the mathematical function becomes: C<add(a,b,c,d,e)>
+
+In RPN, there's no operator that sums more than two values so you need
+to do several additions. You add a and b, add c to the result, add d
+to the result and add e to the result.
+
+   push a:         a     stack contains the value of a
+   push b and add: b,+   stack contains the result of a+b
+   push c and add: c,+   stack contains the result of a+b+c
+   push d and add: d,+   stack contains the result of a+b+c+d
+   push e and add: e,+   stack contains the result of a+b+c+d+e
+
+What was calculated here would be written down as:
+
+   ( ( ( (a+b) + c) + d) + e) >
+
+This is in RPN:  C<CDEF:result=a,b,+,c,+,d,+,e,+>
+
+This is correct but it can be made more clear to humans. It does
+not matter if you add a to b and then add c to the result or first
+add b to c and then add a to the result. This makes it possible to
+rewrite the RPN into C<CDEF:result=a,b,c,d,e,+,+,+,+> which is
+evaluatated differently: 
+
+   push value of variable a on the stack: a
+   push value of variable b on the stack: a b
+   push value of variable c on the stack: a b c
+   push value of variable d on the stack: a b c d
+   push value of variable e on the stack: a b c d e
+   push operator + on the stack:          a b c d e +
+   and process it:                        a b c P   (where P == d+e)
+   push operator + on the stack:          a b c P +
+   and process it:                        a b Q     (where Q == c+P)
+   push operator + on the stack:          a b Q +
+   and process it:                        a R       (where R == b+Q)
+   push operator + on the stack:          a R +
+   and process it:                        S         (where S == a+R)
+
+As you can see the RPN expression C<a,b,c,d,e,+,+,+,+,+> will evaluate in
+C<((((d+e)+c)+b)+a)> and it has the same outcome as C<a,b,+,c,+,d,+,e,+> 
+According to Steve Rader this is called the commutative law of addition
+but you may forget this right away, as long as you remember what it
+represents.
+
+Now look at an expression that contains a multiplication:
+
+First in normal math: C<let result = a+b*c>. In this case you can't
+choose the order yourself, you have to start with the multiplication
+and then add a to it. You may alter the position of b and c, you may
+not alter the position of a and b. 
+
+You have to take this in consideration when converting this expression
+into RPN. Read it as: "Add the outcome of b*c to a" and then it is
+easy to write the RPN expression: C<result=a,b,c,*,+>
+Another expression that would return the same: C<result=b,c,*,a,+>
+
+In normal math, you may encounter something like "a*(b+c)" and this
+can also be converted into RPN. The parenthesis just tell you to first
+add b and c, and then multiply a with the result. Again, now it is
+easy to write it in RPN: C<result=a,b,c,+,*>. Note that this is very
+similar to one of the expressions in the previous paragraph, only the
+multiplication and the addition changed places.
+
+When you have problems with RPN or when rrdtool is complaining, it's 
+usually a Good Thing to write down the stack on a piece of paper
+and see what happens. Have the manual ready and pretend to be rrdtool.
+Just do all the math by hand to see what happens, I'm sure this will
+solve most, if not all, problems you encounter.
+
+=head1 Some special numbers
+
+=head2 The unknown value
+
+Sometimes collecting your data will fail. This can be very common,
+especially when querying over busy links. RRDtool can be configured
+to allow for one (or even more) unknown value and calculate the missing
+update. You can, for instance, query your device every minute. This is
+creating one so called PDP or primary data point per minute. If you
+defined your RRD to contain an RRA that stores 5-minute values, you need
+five of those PDPs to create one CDP (consolidated data point).
+These PDPs can become unknown in two cases:
+
+=over 4
+
+=item 1.
+
+The updates are too far apart. This is tuned using the "heartbeat" setting
+
+=item 2.
+
+The update was set to unknown on purpose by inserting no value (using the
+template option) or by using "U" as the value to insert.
+
+=back
+
+When a CDP is calculated, another mechanism determines if this CDP is valid
+or not. If there are too many PDPs unknown, the CDP is unknown as well.
+This is determined by the xff factor. Please note that one unknown counter
+update can result in two unknown PDPs! If you only allow for one unknown
+PDP per CDP, this makes the CDP go unknown!
+
+Suppose the counter increments with one per second and you retrieve it
+every minute:
+
+   counter value    resulting rate
+   10000
+   10060            1; (10060-10000)/60 == 1
+   10120            1; (10060-10000)/60 == 1
+   unknown          unknown; you don't know the last value
+   10240            unknown; you don't know the previous value
+   10300            1; (10300-10240)/60 == 1
+
+If the CDP was to be calculated from the last five updates, it would get
+two unknown PDPs and three known PDPs. If xff would have been set to 0.5
+which by the way is a commonly used factor, the CDP would have a known
+value of 1. If xff would have been set to 0.2 then the resulting CDP
+would be unknown.
+
+You have to decide the proper values for heartbeat, number of PDPs per
+CDP and the xff factor. As you can see from the previous text they define
+the behavior of your RRA.
+
+=head2 Working with unknown data in your database
+
+As you have read in the previous chapter, entries in an RRA can be
+set to the unknown value. If you do calculations with this type of
+value, the result has to be unknown too. This means that an expression
+such as C<result=a,b,+> will be unknown if either a or b is unknown.
+It would be wrong to just ignore the unknown value and return the value
+of the other parameter. By doing so, you would assume "unknown" means "zero"
+and this is not true.
+
+There has been a case where somebody was collecting data for over a year.
+A new piece of equipment was installed, a new RRD was created and the
+scripts were changed to add a counter from the old database and a counter
+from the new database. The result was disappointing, a large part of
+the statistics seemed to have vanished mysteriously ...
+They of course didn't, values from the old database (known values) were
+added to values from the new database (unknown values) and the result was
+unknown.
+
+In this case, it is fairly reasonable to use a CDEF that alters unknown
+data into zero. The counters of the device were unknown (after all, it
+wasn't installed yet!) but you know that the data rate through the device
+had to be zero (because of the same reason: it was not installed).
+
+There are some examples further on that make this change.
+
+=head2 Infinity
+
+Infinite data is another form of a special number. It cannot be graphed
+because by definition you would never reach the infinite value. You could
+think of positive and negative infinity (I'm not sure if mathematicians
+will agree) depending on the position relative to zero.
+
+RRDtool is capable of representing (-not- graphing!) infinity by stopping
+at its current maximum (for positive infinity) or minimum (for negative
+infinity) without knowing this maximum (minimum).
+
+Infinity in rrdtool is mostly used to draw an AREA without knowing its
+vertical dimensions. You can think of it as drawing an AREA with an
+infinite height and displaying only the part that is visible in the
+current graph. This is probably a good way to approximate infinity
+and it sure allows for some neat tricks. See below for examples.
+
+=head2 Working with unknown data and infinity
+
+Sometimes you would like to discard unknown data and pretend it is zero
+(or any other value for that matter) and sometimes you would like to
+pretend that known data is unknown (to discard known-to-be-wrong data).
+This is why CDEFs have support for unknown data. There are also examples
+available that show unknown data by using infinity.
+
+=head1 Some examples
+
+=head2 Example: using a recently created RRD
+
+You are keeping statistics on your router for over a year now. Recently
+you installed an extra router and you would like to show the combined
+throughput for these two devices.
+
+If you just add up the counters from router.rrd and router2.rrd, you
+will add known data (from router.rrd) to unknown data (from router2.rrd) for
+the bigger part of your stats. You could solve this in a few ways:
+
+=over 4
+
+=item *
+
+While creating the new database, fill it with zeros from the start to now.
+You have to make the database start at or before the least recent time in
+the other database.
+
+=item *
+
+Alternately you could use CDEF and alter unknown data to zero.
+
+=back
+
+Both methods have their pros and cons. The first method is troublesome and
+if you want to do that you have to figure it out yourself. It is not
+possible to create a database filled with zeros, you have to put them in
+on purpose. Implementing the second method is described next:
+
+What we want is: "if the value is unknown, replace it with zero". This
+could be writte in pseudo-code as:  if (value is unknown) then (zero)
+else (value). When reading the rrdgraph manual you notice the "UN"
+function that returns zero or one. You also notice the "IF" function
+that takes zero or one as input.
+
+First look at the "IF" function. It takes three values from the stack,
+the first value is the decision point, the second value is returned to
+the stack if the evaluation is "true" and if not, the third value is
+returned to the stack. We want the "UN" function to decide what happens
+so we combine those two functions in one CDEF.
+
+Lets write down the two possible paths for the "IF" function:
+
+   if true  return a
+   if false return b
+
+In RPN:  C<result=x,a,b,IF> where "x" is either true or false.
+
+Now we have to fill in "x", this should be the "(value is unknown)" part
+and this is in RPN:  C<result=value,UN>
+
+We now combine them: C<result=value,UN,a,b,IF> and when we fill in the
+appropriate things for "a" and "b" we're finished:
+
+C<CDEF:result=value,UN,0,value,IF>
+
+You may want to read Steve Raders RPN guide if you have difficulties
+with the way I explained this last example.
+
+If you want to check this RPN expression, just mimic rrdtools behavior:
+
+   For any known value, the expression evaluates as follows:
+   CDEF:result=value,UN,0,value,IF  (value,UN) is not true so it becomes 0
+   CDEF:result=0,0,value,IF         "IF" will return the 3rd value
+   CDEF:result=value                The known value is returned
+
+   For the unknown value, this happens:
+   CDEF:result=value,UN,0,value,IF  (value,UN) is true so it becomes 1
+   CDEF:result=1,0,value,IF         "IF" sees 1 and returns the 2nd value
+   CDEF:result=0                    Zero is returned
+
+Of course, if you would like to see another value instead of zero, you
+can use that other value.
+
+Eventually, when all unknown data is removed from the RRD, you may want
+to remove this rule so that unknown data is properly displayed.
+
+=head2 Example: better handling of unknown data, by using time
+
+Above example has one drawback. If you do log unknown data in
+your database after installing your new equipment, it will also be
+translated into zero and therefore you won't see that there was a
+problem. This is not good and what you really want to do is:
+
+=over 4
+
+=item *
+
+If there is unknown data, look at the time that this sample was taken
+
+=item *
+
+If the unknown value is before time xxx, make it zero
+
+=item *
+
+If it is after time xxx, leave it as unknown data
+
+=back
+
+This is doable: you can compare the time that the sample was taken
+to some known time. Assuming you started to monitor your device on
+Friday September 17, 00:35:57 MET DST. Translate this time in seconds
+since 1970-01-01 and it becomes 937521357. If you process unknown values
+that were received after this time, you want to leave them unknown and
+if they were "received" before this time, you want to translate them
+into zero (so you can effectively ignore them while adding them to your
+other routers counters).
+
+Translating Friday September 17, 00:35:57 MET DST into 937521357 can
+be done by, for instance, using gnu date:
+
+   date -d "19990917 00:35:57" +%s
+
+You could also dump the database and see where the data starts to be
+known. There are several other ways of doing this, just pick one.
+
+Now we have to create the magic that allows us to process unknown
+values different depending on the time that the sample was taken.
+This is a three step process:
+
+=over 4
+
+=item 1.
+
+If the timestamp of the value is after 937521357, leave it as is
+
+=item 2.
+
+If the value is a known value, leave it as is
+
+=item 3.
+
+Change the unknown value into zero.
+
+=back
+
+Lets look at part one:
+
+    if (true) return the original value
+
+We rewrite this:
+
+    if (true) return "a"
+    if (false) return "b"
+
+We need to calculate true or false from step 1. There is a function
+available that returns the timestamp for the current sample. It is
+called, how surprisingly, "TIME". This time has to be compared to
+a constant number, we need "GT". The output of "GT" is true or false
+and this is good input to "IF". We want "if (time > 937521357) then
+(return a) else (return b)".
+
+This process was already described toroughly in the previous chapter
+so lets do it quick:
+
+   if (x) then a else b
+      where x represents "time>937521357"
+      where a represents the original value
+      where b represents the outcome of the previous example
+      
+   time>937521357       --> TIME,937521357,GT
+
+   if (x) then a else b --> x,a,b,IF
+   substitute x         --> TIME,937521357,GT,a,b,IF
+   substitute a         --> TIME,937521357,GT,value,b,IF
+   substitute b         --> TIME,937521357,GT,value,value,UN,0,value,IF,IF
+
+We end up with:
+C<CDEF:result=TIME,937521357,GT,value,value,UN,0,value,IF,IF>
+
+This looks very complex however as you can see it was not too hard to
+come up with.
+
+=head2 Example: Pretending weird data isn't there
+
+Suppose you have a problem that shows up as huge spikes in your graph.
+You know this happens and why so you decide to work around the problem.
+Perhaps you're using your network to do a backup at night and by doing
+so you get almost 10mb/s while the rest of your network activity does
+not produce numbers higher than 100kb/s.
+
+There are two options:
+
+=over 4
+
+=item 1.
+
+If the number exceeds 100kb/s it is wrong and you want it masked out
+by changing it into unknown
+
+=item 2.
+
+You don't want the graph to show more than 100kb/s
+
+=back
+
+Pseudo code: if (number > 100) then unknown else number
+or
+Pseudo code: if (number > 100) then 100 else number.
+
+The second "problem" may also be solved by using the rigid option of
+rrdtool graph, however this has not the same result. In this example
+you can end up with a graph that does autoscaling. Also, if you use
+the numbers to display maxima they will be set to 100kb/s.
+
+We use "IF" and "GT" again. "if (x) then (y) else (z)" is written
+down as "CDEF:result=x,y,z,IF"; now fill in x, y and z.
+For x you fill in "number greater than 100kb/s" becoming
+"number,100000,GT" (kilo is 1000 and b/s is what we measure!).
+The "z" part is "number" in both cases and the "y" part is either
+"UNKN" for unknown or "100000" for 100kb/s.
+
+The two CDEF expressions would be:
+
+    CDEF:result=number,100000,GT,UNKN,number,IF
+    CDEF:result=number,100000,GT,100000,number,IF
+
+=head2 Example: You suspect to have problems and want to see unknown data.
+
+Suppose you add up the number of active users on several terminal servers.
+If one of them doesn't give an answer (or an incorrect one) you get "NaN"
+in the database ("Not a Number") and NaN is evaluated as Unknown.
+
+In this case, you would like to be alerted to it and the sum of the
+remaining values is of no value to you.
+
+It would be something like:
+
+    DEF:users1=location1.rrd:onlineTS1:LAST
+    DEF:users2=location1.rrd:onlineTS2:LAST
+    DEF:users3=location2.rrd:onlineTS1:LAST
+    DEF:users4=location2.rrd:onlineTS2:LAST
+    CDEF:allusers=users1,users2,users3,users4,+,+,+
+
+If you now plot allusers, unknown data in one of users1..users4 will
+show up as a gap in your graph. You want to modify this to show a
+bright red line, not a gap.
+
+Define an extra CDEF that is unknown if all is okay and is infinite if
+there is an unknown value:
+
+    CDEF:wrongdata=allusers,UN,INF,UNKN,IF
+
+"allusers,UN" will evaluate to either true or false, it is the (x) part
+of the "IF" function and it checks if allusers is unknown.
+The (y) part of the "IF" function is set to "INF" (which means infinity)
+and the (z) part of the function returns "UNKN".
+
+The logic is: if (allusers == unknown) then return INF else return UNKN.
+
+You can now use AREA to display this "wrongdata" in bright red. If it
+is unknown (because allusers is known) then the red AREA won't show up.
+If the value is INF (because allusers is unknown) then the red AREA will
+be filled in on the graph at that particular time.
+
+   AREA:allusers#0000FF:combined user count
+   AREA:wrongdata#FF0000:unknown data
+
+=head2 Same example useful with STACKed data:
+
+If you use stack in the previous example (as I would do) then you don't
+add up the values. Therefore, there is no relationship between the
+four values and you don't get a single value to test.
+Suppose users3 would be unknown at one point in time: users1 is plotted,
+users2 is stacked on top of users1, users3 is unknown and therefore
+nothing happens, users4 is stacked on top of users2.
+Add the extra CDEFs anyway and use them to overlay the "normal" graph:
+
+   DEF:users1=location1.rrd:onlineTS1:LAST
+   DEF:users2=location1.rrd:onlineTS2:LAST
+   DEF:users3=location2.rrd:onlineTS1:LAST
+   DEF:users4=location2.rrd:onlineTS2:LAST
+   CDEF:allusers=users1,users2,users3,users4,+,+,+
+   CDEF:wrongdata=allusers,UN,INF,UNKN,IF
+   AREA:users1#0000FF:users at ts1
+   STACK:users2#00FF00:users at ts2
+   STACK:users3#00FFFF:users at ts3
+   STACK:users4#FFFF00:users at ts4
+   AREA:wrongdata#FF0000:unknown data
+
+If there is unknown data in one of users1..users4, the "wrongdata" AREA
+will be drawn and because it starts at the X-axis and has infinite height
+it will effectively overwrite the STACKed parts.
+
+You could combine the two CDEF lines into one (we don't use "allusers")
+if you like.  But there are good reasons for writting two CDEFS:
+
+=over 4
+
+=item *
+
+It improves the readability of the script
+
+=item *
+
+It can be used inside GPRINT to display the total number of users
+
+=back
+
+If you choose to combine them, you can substitute the "allusers" in the
+second CDEF with the part after the equal sign from the first line:
+
+   CDEF:wrongdata=users1,users2,users3,users4,+,+,+,UN,INF,UNKN,IF
+
+If you do so, you won't be able to use these next GPRINTs:
+
+   COMMENT:"Total number of users seen"
+   GPRINT:allusers:MAX:"Maximum: %6.0lf"
+   GPRINT:allusers:MIN:"Minimum: %6.0lf"
+   GPRINT:allusers:AVERAGE:"Average: %6.0lf"
+   GPRINT:allusers:LAST:"Current: %6.0lf\n"
+
+=head1 The examples from the rrd graph manual page
+
+=head2 Degrees Celcius vs. Degrees Fahrenheit
+
+   rrdtool graph demo.gif --title="Demo Graph" \
+      DEF:cel=demo.rrd:exhaust:AVERAGE \
+      CDEF:far=cel,32,-,0.55555,* \
+      LINE2:cel#00a000:"D. Celsius" \
+      LINE2:far#ff0000:"D. Fahrenheit\c"
+
+This example gets the DS called "exhaust" from database "demo.rrd"
+and puts the values in variable "cel". The CDEF used is evaluated
+as follows:
+
+   CDEF:far=cel,32,-,0.5555,*
+   1. push variable "cel"
+   2. push 32
+   3. push function "minus" and process it
+      The stack now contains values that are 32 less than "cel"
+   4. push 0.5555
+   5. push function "multiply" and process it
+   6. the resulting value is now "(cel-32)*0.55555"
+
+Note that if you take the celcius to fahrenheit function you should
+be doing "5/9*(cel-32)" so 0.55555 is not exactly correct. It is close
+enough for this purpose and it saves a calculation.
+
+=head2 Changing unknown into zero
+
+   rrdtool graph demo.gif --title="Demo Graph" \
+      DEF:idat1=interface1.rrd:ds0:AVERAGE \
+      DEF:idat2=interface2.rrd:ds0:AVERAGE \
+      DEF:odat1=interface1.rrd:ds1:AVERAGE \
+      DEF:odat2=interface2.rrd:ds1:AVERAGE \
+      CDEF:agginput=idat1,UN,0,idat1,IF,idat2,UN,0,idat2,IF,+,8,* \
+      CDEF:aggoutput=odat1,UN,0,odat1,IF,odat2,UN,0,odat2,IF,+,8,* \
+      AREA:agginput#00cc00:Input Aggregate \
+      LINE1:aggoutput#0000FF:Output Aggregate
+
+These two CDEFs are built from several functions. It helps to
+split them when viewing what they do.
+Starting with the first CDEF we would get:
+      idat1,UN --> a
+      0        --> b
+      idat1    --> c
+      if (a) then (b) else (c)
+The result is therefore "0" if it is true that "idat1" equals "UN".
+If not, the original value of "idat1" is put back on the stack.
+Lets call this answer "d". The process is repeated for the next
+five items on the stack, it is done the same and will return answer
+"h". The resulting stack is therefore "d,h".
+The expression has been simplified to "d,h,+,8,*" and it will now be
+easy to see that we add "d" and "h", and multiply the result with eight.
+
+The end result is that we have added "idat1" and "idat2" and in the
+process we effectively ignored unknown values. The result is multiplied
+by eight, most likely to convert bytes/s to bits/s.
+
+=head2 Infinity demo
+
+   rrdtool graph example.png --title="INF demo" \
+      DEF:val1=some.rrd:ds0:AVERAGE \
+      DEF:val2=some.rrd:ds1:AVERAGE \
+      DEF:val3=some.rrd:ds2:AVERAGE \
+      DEF:val4=other.rrd:ds0:AVERAGE \
+      CDEF:background=val4,POP,TIME,7200,%,3600,LE,INF,UNKN,IF \
+      CDEF:wipeout=val1,val2,val3,val4,+,+,+,UN,INF,UNKN,IF \
+      AREA:background#F0F0F0 \
+      AREA:val1#0000FF:Value1 \
+      STACK:val2#00C000:Value2 \
+      STACK:val3#FFFF00:Value3 \
+      STACK:val4#FFC000:Value4 \
+      AREA:whipeout#FF0000:Unknown
+
+This demo demonstrates two ways to use infinity. It is a bit tricky
+to see what happens in the "background" CDEF.
+
+   "val4,POP,TIME,7200,%,3600,LE,INF,UNKN,IF"
+
+This RPN takes the value of "val4" as input and then immediately
+removes it from the stack using "POP". The stack is now empty but
+as a side result we now know the time that this sample was taken.
+This time is put on the stack by the "TIME" function.
+
+"TIME,7200,%" takes the modulo of time and 7200 (which is two hours).
+The resulting value on the stack will be a number in the range from
+0 to 7199.
+
+For people who don't know the modulo function: it is the remainder
+after an integer division. If you divide 16 by 3, the answer would
+be 5 and the remainder would be 1. So, "16,3,%" returns 1.
+
+We have the result of "TIME,7200,%" on the stack, lets call this
+"a". The start of the RPN has become "a,3600,LE" and this checks
+if "a" is less or equal than "3600". It is true half of the time.
+We now have to process the rest of the RPN and this is only a simple
+"IF" function that returns either "INF" or "UNKN" depending on the
+time. This is returned to variable "background".
+
+The second CDEF has been discussed earlyer in this document so we
+won't do that here.
+
+Now you can draw the different layers. Start with the background
+that is either unknown (nothing to see) or infinite (the whole
+positive part of the graph gets filled).
+Next you draw the data on top of this background. It will overlay
+the background. Suppose one of val1..val4 would be unknown, in that
+case you end up with only three bars stacked on top of each other.
+You don't want to see this because the data is only valid when all
+four variables are valid. This is why you use the second CDEF, it
+will overlay the data with an AREA so the data cannot be seen anymore.
+
+If your data can also have negative values you also need to overwrite
+the other half of your graph. This can be done in a relatively simple
+way: what you need is the "wipeout" variable and place a negative
+sign before it:  "CDEF:wipeout2=wipeout,-1,*"
+    
+=head1 Out of ideas for now
+
+This document was created from questions asked by either myself or
+by other people on the list. Please let me know if you find errors
+in it or if you have trouble understanding it. If you think there
+should be an addition, mail me: E<lt>alex at ergens.op.het.netE<gt>
+
+Remember: B<No feedback equals no changes!>
+
+=head1 SEE ALSO
+
+The RRDtool manpages
+
+=head1 AUTHOR
+
+Alex van den Bogaerdt
+E<lt>alex at ergens.op.het.netE<gt>

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/rrdupdate.txt
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/rrdupdate.txt	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/rrdupdate.txt	Sat Jul 13 21:08:16 2002
@@ -1,94 +1,94 @@
 
 
 
-RRDUPDATE(1)                 rrdtool                 RRDUPDATE(1)
+rrdtool                                              RRDUPDATE(1)
+
 
 
 NNNNAAAAMMMMEEEE
-       rrdtool update - Store a new set of values into the rrd
+     rrdtool update - Store a new set of values into the rrd
 
 SSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS
-       rrrrrrrrddddttttoooooooollll uuuuppppddddaaaatttteeee _f_i_l_e_n_a_m_e [--------tttteeeemmmmppppllllaaaatttteeee|----tttt _d_s_-_n_a_m_e[::::_d_s_-
-       _n_a_m_e]...]  NNNN|_t_i_m_e_s_t_a_m_p::::_v_a_l_u_e[::::_v_a_l_u_e...]
-       [_t_i_m_e_s_t_a_m_p::::_v_a_l_u_e[::::_v_a_l_u_e...] ...]
+     rrrrrrrrddddttttoooooooollll uuuuppppddddaaaatttteeee _f_i_l_e_n_a_m_e [--------tttteeeemmmmppppllllaaaatttteeee|----tttt _d_s-_n_a_m_e[::::_d_s-_n_a_m_e]...]
+     NNNN|_t_i_m_e_s_t_a_m_p::::_v_a_l_u_e[::::_v_a_l_u_e...]
+     [_t_i_m_e_s_t_a_m_p::::_v_a_l_u_e[::::_v_a_l_u_e...] ...]
 
 DDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
-       The uuuuppppddddaaaatttteeee function feeds new data values into an RRRRRRRRDDDD. The
-       data gets time aligned according to the properties of the
-       RRRRRRRRDDDD to which the data is written.
-
-       _f_i_l_e_n_a_m_e
-               The name of the RRRRRRRRDDDD you want to update.
-
-       --------tttteeeemmmmppppllllaaaatttteeee|----tttt _d_s_-_n_a_m_e[::::_d_s_-_n_a_m_e]...
-               by default, the update function expects the data
-               input in the order, the data sources are defined
-               in the RRD. This is not very error resistant, as
-               you might be sending the wrong data into a RRD.
-
-               The template switch allows you to specify which
-               data sources you are going to update and in which
-               order. If the data sources specified in the
-               template are not available in the rrd file, the
-               update process will abort with an error message.
-
-       NNNN|_t_i_m_e_s_t_a_m_p::::_v_a_l_u_e[::::_v_a_l_u_e...]
-               The data used for updating the RRD was acquired at
-               a certain time. This time can either be defined in
-               seconds since 1970-01-01. Or by using the letter
-               'N' the update time is set to be the current time.
-               Negative time values are subtracted from the
-               current time.  Getting the timing right to the
-               second is especially important when you are
-               working with data-sources of type CCCCOOOOUUUUNNNNTTTTEEEERRRR, DDDDEEEERRRRIIIIVVVVEEEE
-               or AAAABBBBSSSSOOOOLLLLUUUUTTTTEEEE.
-
-               The remaining elements of the argument are DS
-               updates. The order of this list is the same as the
-               order the data sources were defined in the rra.
-               If there is no data for a certain data-source, the
-               letter UUUU (eg. N:0.1:U:1) can be defined.
-
-               The format of the value acquired from the data
-               source is dependent of the data source type
-               chosen. Normally it will be numeric, but the data
-               acquisition modules my impose their very own
-               parsing of this parameter as long as the colon (::::)
-               remains the data source value separator.
+     The uuuuppppddddaaaatttteeee function feeds new data values into an RRRRRRRRDDDD. The
+     data gets time aligned according to the properties of the
+     RRRRRRRRDDDD to which the data is written.
 
-EEEEXXXXAAAAMMMMPPPPLLLLEEEE
-       rrdtool update demo1.rrd N:3.44:3.15:U:23
+     _f_i_l_e_n_a_m_e
+             The name of the RRRRRRRRDDDD you want to update.
 
+     --------tttteeeemmmmppppllllaaaatttteeee|-tttt _d_s-_n_a_m_e[::::_d_s-_n_a_m_e]...
+             by default, the update function expects the data
+             input in the order, the data sources are defined in
+             the RRD. This is not very error resistant, as you
+             might be sending the wrong data into a RRD.
 
+             The template switch allows you to specify which data
+             sources you are going to update and in which order.
+             If the data sources specified in the template are
+             not available in the rrd file, the update process
+             will abort with an error message.
 
-9/Aug/99                      1.0.7                             1
+     NNNN|_t_i_m_e_s_t_a_m_p::::_v_a_l_u_e[::::_v_a_l_u_e...]
+             The data used for updating the RRD was acquired at a
+             certain time. This time can either be defined in
+             seconds since 1970-01-01. Or by using the letter 'N'
+             the update time is set to be the current time.
+             Negative time values are subtracted from the current
+             time.  Getting the timing right to the second is
+             especially important when you are working with
+             data-sources of type CCCCOOOOUUUUNNNNTTTTEEEERRRR, DDDDEEEERRRRIIIIVVVVEEEE or AAAABBBBSSSSOOOOLLLLUUUUTTTTEEEE.
 
+             The remaining elements of the argument are DS
+             updates. The order of this list is the same as the
+             order the data sources were defined in the rra.  If
+             there is no data for a certain data-source, the
+             letter UUUU (eg. N:0.1:U:1) can be defined.
 
+             The format of the value acquired from the data
+             source is dependent of the data source type chosen.
+             Normally it will be numeric, but the data
+             acquisition modules my impose their very own parsing
+             of this parameter as long as the colon (::::) remains
+             the data source value separator.
 
 
 
-RRDUPDATE(1)                 rrdtool                 RRDUPDATE(1)
 
 
-       Update the database file demo1.rrd with 3 known and one
-       _*_U_N_K_N_O_W_N_* value. Use the current time as the update time.
+24/Oct/1999            Last change: 1.0.13                      1
 
-       rrdtool update demo2.rrd 887457267:U 887457521:22
-       88745790:2.7
 
-       Update the database file demo2.rrd which expects data from
-       a single data-source, three times. First with an _*_U_N_K_N_O_W_N_*
-       value then with two normal readings. The update interval
-       seems to be around 300 seconds.
 
-AAAAUUUUTTTTHHHHOOOORRRR
-       Tobias Oetiker <oetiker at ee.ethz.ch>
 
 
 
+rrdtool                                              RRDUPDATE(1)
 
 
 
+EEEEXXXXAAAAMMMMPPPPLLLLEEEE
+     rrdtool update demo1.rrd N:3.44:3.15:U:23
+
+     Update the database file demo1.rrd with 3 known and one
+     *_U_N_K_N_O_W_N* value. Use the current time as the update time.
+
+     rrdtool update demo2.rrd 887457267:U 887457521:22
+     88745790:2.7
+
+     Update the database file demo2.rrd which expects data from a
+     single data-source, three times. First with an *_U_N_K_N_O_W_N*
+     value then with two normal readings. The update interval
+     seems to be around 300 seconds.
+
+AAAAUUUUTTTTHHHHOOOORRRR
+     Tobias Oetiker <oetiker at ee.ethz.ch>
+
+
 
 
 
@@ -126,7 +126,7 @@
 
 
 
+24/Oct/1999            Last change: 1.0.13                      2
 
-9/Aug/99                      1.0.7                             2
 
 

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/Makefile.am
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/Makefile.am	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/Makefile.am	Sat Jul 13 21:08:16 2002
@@ -9,8 +9,8 @@
 CLEANFILES = *.1 *.html *.txt *-dircache *.pm
 
 POD = rrdtool.pod rrdlast.pod rrdcreate.pod rrdupdate.pod \
-	rrdgraph.pod  bin_dec_hex.pod rrdfetch.pod \
-	rrdrestore.pod rrddump.pod rrdtune.pod rrdresize.pod \
+	cdeftutorial.pod rpntutorial.pod rrdgraph.pod  bin_dec_hex.pod \
+	rrdfetch.pod rrdrestore.pod rrddump.pod rrdtune.pod rrdresize.pod \
 	rrdcgi.pod rrdtutorial.pod
 
 PMP = RRDs.pm RRDp.pm

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/rrdrestore.txt
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/rrdrestore.txt	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/rrdrestore.txt	Sat Jul 13 21:08:17 2002
@@ -1,33 +1,33 @@
 
 
 
-RRDRESTORE(1)                rrdtool                RRDRESTORE(1)
+rrdtool                                             RRDRESTORE(1)
+
 
 
 NNNNAAAAMMMMEEEE
-       rrdtool restore - restore the contents of an RRRRRRRRDDDD from its
-       XML dump format
+     rrdtool restore - restore the contents of an RRRRRRRRDDDD from its
+     XML dump format
 
 SSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS
-       rrrrrrrrddddttttoooooooollll rrrreeeessssttttoooorrrreeee _f_i_l_e_n_a_m_e_._x_m_l _f_i_l_e_n_a_m_e_._r_r_d [--------rrrraaaannnnggggeeee----
-       cccchhhheeeecccckkkk|----rrrr]
+     rrrrrrrrddddttttoooooooollll rrrreeeessssttttoooorrrreeee _f_i_l_e_n_a_m_e._x_m_l _f_i_l_e_n_a_m_e._r_r_d [--------rrrraaaannnnggggeeee----cccchhhheeeecccckkkk|----rrrr]
 
 DDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
-       The rrrreeeessssttttoooorrrreeee function reads the XML representation of an
-       RRD and converts it into the native RRRRRRRRDDDD format.
+     The rrrreeeessssttttoooorrrreeee function reads the XML representation of an RRD
+     and converts it into the native RRRRRRRRDDDD format.
 
-       _f_i_l_e_n_a_m_e_._x_m_l
-               The name of the XXXXMMMMLLLL you want to restore.
+     _f_i_l_e_n_a_m_e._x_m_l
+             The name of the XXXXMMMMLLLL you want to restore.
 
-       _f_i_l_e_n_a_m_e_._r_r_d
-               The name of the RRRRRRRRDDDD to restore.
+     _f_i_l_e_n_a_m_e._r_r_d
+             The name of the RRRRRRRRDDDD to restore.
 
-       --------rrrraaaannnnggggeeee----cccchhhheeeecccckkkk|----rrrr
-               Make sure the values in the RRAs do not exceed the
-               limits defined for the different datasources.
+     --------rrrraaaannnnggggeeee----cccchhhheeeecccckkkk|-rrrr
+             Make sure the values in the RRAs do not exceed the
+             limits defined for the different datasources.
 
 AAAAUUUUTTTTHHHHOOOORRRR
-       Tobias Oetiker <oetiker at ee.ethz.ch>
+     Tobias Oetiker <oetiker at ee.ethz.ch>
 
 
 
@@ -60,7 +60,7 @@
 
 
 
+24/Oct/1999            Last change: 1.0.13                      1
 
-20/Aug/99                     1.0.7                             1
 
 

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/rrdresize.html
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/rrdresize.html	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/rrdresize.html	Sat Jul 13 21:08:17 2002
@@ -1,11 +1,10 @@
-    <HTML> 
-	<HEAD> 
-	    <TITLE>resize - alters the size of an RRA.
+<HTML>
+<HEAD>
+<TITLE>rrdresize</TITLE>
+<LINK REV="made" HREF="mailto:karrer at zinal.ee.ethz.ch">
+</HEAD>
 
-</TITLE> 
-	</HEAD>
-
-	<BODY>
+<BODY>
 
 <!-- INDEX BEGIN -->
 <!--
@@ -22,105 +21,64 @@
 <!-- INDEX END -->
 
 <P>
-<H1><A NAME="NAME">NAME
-
-</A></H1>
-rrdtool resize - alters the size of an RRA.
-
-
+<H1><A NAME="NAME">NAME</A></H1>
 <P>
+rrdtool resize - alters the size of an RRA.
 
 <P>
 <HR>
-<H1><A NAME="SYNOPSIS">SYNOPSIS
-
-</A></H1>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
 <STRONG>rrdtool</STRONG>  <STRONG>resize</STRONG>  <EM>filename</EM>  <EM>rra-num</EM>    <STRONG>GROW</STRONG><EM>|</EM><STRONG>SHRINK</STRONG>  <EM>rows</EM>
 
 
 
-
-<P>
-
 <P>
 <HR>
-<H1><A NAME="DESCRIPTION">DESCRIPTION
-
-</A></H1>
-The <STRONG>resize</STRONG> function is used to modify the number of rows in an <STRONG>RRA</STRONG>.
-
-
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
 <P>
+The <STRONG>resize</STRONG> function is used to modify the number of rows in an <STRONG>RRA</STRONG>.
 
 <DL>
-<DT><STRONG><A NAME="item_filename">filename 
-
-</A></STRONG><DD>
+<DT><STRONG><A NAME="item_filename">filename</A></STRONG><DD>
+<P>
 the name of the <STRONG>RRD</STRONG> you want to alter.
 
-
+<DT><STRONG><A NAME="item_rra">rra-num</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_rra">rra-num 
-
-</A></STRONG><DD>
 the <STRONG>RRA</STRONG> you want to alter. You can find the number using <STRONG>rrdtool dump</STRONG>.
 
-
+<DT><STRONG><A NAME="item_GROW">GROW</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_GROW">GROW 
-
-</A></STRONG><DD>
 used if you want to add extra rows to an RRA. The extra rows will be
 inserted as the rows that are oldest.
 
-
+<DT><STRONG><A NAME="item_SHRINK">SHRINK</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_SHRINK">SHRINK 
-
-</A></STRONG><DD>
 used if you want to remove rows from an RRA. The rows that will be removed
 are the oldest rows.
 
-
+<DT><STRONG><A NAME="item_rows">rows</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_rows">rows 
-
-</A></STRONG><DD>
 the number of rows you want to add or remove.
 
-
-<P>
-
 </DL>
 <P>
 <HR>
-<H1><A NAME="NOTES">NOTES
-
-</A></H1>
+<H1><A NAME="NOTES">NOTES</A></H1>
+<P>
 It is possible to abuse this tool and get strange results by first removing
 some rows and then reinsert the same amount (effectively clearing them to
 be Unknown). You may thus end up with unknown data in one RRA while at the
 same timestamp this data is available in another RRA.
 
-
-<P>
-
 <P>
 <HR>
-<H1><A NAME="AUTHOR">AUTHOR
-
-</A></H1>
-Alex van den Bogaerdt <A
-HREF="MAILTO:<alex at ergens.op.het.net>"><alex at ergens.op.het.net></A>
-
-
+<H1><A NAME="AUTHOR">AUTHOR</A></H1>
 <P>
+Alex van den Bogaerdt &lt;<A
+HREF="mailto:alex at ergens.op.het.net">alex at ergens.op.het.net</A>&gt;
 
-</DL>
-    </BODY>
+</BODY>
 
-    </HTML>
+</HTML>

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/rrdcgi.html
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/rrdcgi.html	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/rrdcgi.html	Sat Jul 13 21:08:17 2002
@@ -1,11 +1,10 @@
-    <HTML> 
-	<HEAD> 
-	    <TITLE>rrdcgi - create web pages containing RRD graphs based on templates
+<HTML>
+<HEAD>
+<TITLE>rrdcgi</TITLE>
+<LINK REV="made" HREF="mailto:karrer at zinal.ee.ethz.ch">
+</HEAD>
 
-</TITLE> 
-	</HEAD>
-
-	<BODY>
+<BODY>
 
 <!-- INDEX BEGIN -->
 <!--
@@ -22,27 +21,23 @@
 		<LI><A HREF="#Pass_3">Pass 3</A>
 	</UL>
 
-	<LI><A HREF="#EXAMPLE">EXAMPLE</A>
+	<LI><A HREF="#EXAMPLE_1">EXAMPLE 1</A>
 	<LI><A HREF="#EXAMPLE_2">EXAMPLE 2</A>
+	<LI><A HREF="#EXAMPLE_3">EXAMPLE 3</A>
 	<LI><A HREF="#AUTHOR">AUTHOR</A>
 </UL>
 -->
 <!-- INDEX END -->
 
 <P>
-<H1><A NAME="NAME">NAME
-
-</A></H1>
-rrdcgi - create web pages containing RRD graphs based on templates
-
-
+<H1><A NAME="NAME">NAME</A></H1>
 <P>
+rrdcgi - create web pages containing RRD graphs based on templates
 
 <P>
 <HR>
-<H1><A NAME="SYNOPSIS">SYNOPSIS
-
-</A></H1>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
 #!/path/to/<STRONG>rrdcgi</STRONG> 
  
 [<STRONG>--goodfor</STRONG>|<STRONG>-g</STRONG>&nbsp;<EM>seconds</EM>]
@@ -53,169 +48,127 @@
 
 
 
-
-<P>
-
 <P>
 <HR>
-<H1><A NAME="DESCRIPTION">DESCRIPTION
-
-</A></H1>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
 <STRONG>rrdcgi</STRONG> is a sort of very limited script interpreter. Its purpose is to run as a
 cgi-program and parse a web page template containing special
 &lt;RRD:: tags. <STRONG>rrdcgi</STRONG> will interpret and act according to these tags. In the end it will printout
 a web page including the necessary CGI headers.
 
-
 <P>
-
 <STRONG>rrdcgi</STRONG> parses the contents of the template in 2 steps. In each step it looks only
 for a subset of tags. This allows to nest tags. 
 
-
 <P>
-
 The argument parser uses the same semantics as you are used from your c
 shell.
 
-
-<P>
-
 <DL>
-<DT><STRONG><A NAME="item__goodfor_g">--goodfor|-g seconds
-
-</A></STRONG><DD>
-Specify the number of seconds this page should remain valid. This will
-prompt the rrdcgi to output a Last-Modified and a Expire header.
-
-
+<DT><STRONG><A NAME="item__filter">--filter</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__filter">--filter
-
-</A></STRONG><DD>
 Assume that rrdcgi is being run as a filter and not as a cgi.
 
-
+<DT><STRONG><A NAME="item__refresh_r">--refresh|-r</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__refresh_r">--refresh|-r
-
-</A></STRONG><DD>
 If the <STRONG>--goodfor</STRONG> flag is specified, then <STRONG>--refresh</STRONG> will cause rrdcgi to output a Refresh header with the value of the <STRONG>--goodfor</STRONG> value.
 
-
-<P>
-
 </DL>
 <P>
 <HR>
-<H2><A NAME="Pass_1">Pass 1
-
-</A></H2>
+<H2><A NAME="Pass_1">Pass 1</A></H2>
 <DL>
-<DT><STRONG><A NAME="item_RRD">RRD::CV name
-
-</A></STRONG><DD>
+<DT><STRONG><A NAME="item_RRD">RRD::CV name</A></STRONG><DD>
+<P>
 Inserts the CGI variable of the given name.
 
-
+<DT><STRONG><A NAME="item_RRD">RRD::CV::QUOTE name</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_RRD">RRD::CV::QUOTE name
-
-</A></STRONG><DD>
 Inserts the CGI variable of the given name but quotes it, ready for use as
 an argument in another RRD:: tag. So even when there are spaces in the
 value of the CGI variable it will still be considered as one argument.
 
-
+<DT><STRONG><A NAME="item_RRD">RRD::CV::PATH name</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_RRD">RRD::CV::PATH name
-
-</A></STRONG><DD>
 Inserts the CGI variable of the given name, quotes it and makes sure the it
 starts neither with a '/' nor contains '..'. This is to make sure that no
 problematic pathnames can be introduced through the CGI interface.
 
-
-<P>
-
 </DL>
 <P>
 <HR>
-<H2><A NAME="Pass_2">Pass 2
-
-</A></H2>
+<H2><A NAME="Pass_2">Pass 2</A></H2>
 <DL>
-<DT><STRONG><A NAME="item_RRD">RRD::INCLUDE filename
+<DT><STRONG><A NAME="item_RRD">RRD::GOODFOR seconds</A></STRONG><DD>
+<P>
+Specify the number of seconds this page should remain valid. This will
+prompt the rrdcgi to output a Last-Modified, an Expire and if the number of
+seconds is <EM>negative</EM> a Refresh headers.
 
-</A></STRONG><DD>
+<DT><STRONG><A NAME="item_RRD">RRD::INCLUDE filename</A></STRONG><DD>
+<P>
 Include the contents of the given file into the page returned from the cgi
 
+<DT><STRONG><A NAME="item_RRD">RRD::SETENV variable value</A></STRONG><DD>
+<P>
+If you want to present your graphs in another time zone than your own, you
+could use
+
+<P>
+<PRE> &lt;RRD::SETENV TZ UTC&gt;
+</PRE>
+<P>
+to make sure everything is presented in Universal Time. Note that the
+values permitted to TZ depend on your OS.
 
+<DT><STRONG><A NAME="item_RRD">RRD::TIME::LAST rrd-file strftime-format</A></STRONG><DD>
 <P>
+This gets replaced by the last modification time of the selected RRD. The
+time is <EM>strftime</EM>-formated with the string specified in the second argument.
+
+<DT><STRONG><A NAME="item_RRD">RRD::TIME::NOW strftime-format</A></STRONG><DD>
+<P>
+This gets replaced by the current time of day. The time is <EM>strftime</EM>-formated with the string specified in the argument.
 
 </DL>
 <P>
 <HR>
-<H2><A NAME="Pass_3">Pass 3
-
-</A></H2>
+<H2><A NAME="Pass_3">Pass 3</A></H2>
 <DL>
-<DT><STRONG><A NAME="item_RRD">RRD::GRAPH rrdgraph arguments
-
-</A></STRONG><DD>
+<DT><STRONG><A NAME="item_RRD">RRD::GRAPH rrdgraph arguments</A></STRONG><DD>
+<P>
 This tag creates the RRD graph defined in its argument and then gets
 replaced by an appropriate &lt;IMG&gt; tag referring to the graph. The <STRONG>--lazy</STRONG> option in RRD graph can be used to make sure that graphs are only
 regenerated when they are out of date. The arguments to the <STRONG>RRD::GRAPH</STRONG> tag work as described in the <STRONG>rrdgraph</STRONG> manual page.
 
-
 <P>
-
 Use the <STRONG>--lazy</STRONG> option in your RRD::GRAPH tags, to reduce the load on your server. This
 option makes sure that graphs are only regenerated when the old ones are
 out of date.
 
-
 <P>
-
 If you do not specify your own <STRONG>--imginfo</STRONG> format, the following will be used:
 
-
 <P>
-
 <PRE> &lt;IMG SRC=&quot;%s&quot; WIDTH=&quot;%lu&quot; HEIGHT=&quot;%lu&quot;&gt;
 </PRE>
-
 <P>
-
 Note that <CODE>%s</CODE> stands for the filename part of the graph
 generated, all directories given in the GIF file argument will get dropped.
 
-
+<DT><STRONG><A NAME="item_RRD">RRD::PRINT number</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_RRD">RRD::PRINT number
-
-</A></STRONG><DD>
 If the preceding  <STRONG>RRD::GRAPH</STRONG> tag contained and <STRONG>PRINT</STRONG> arguments, then you can access their output with this tag. The <EM>number</EM> argument refers to the number of the <STRONG>PRINT</STRONG> argument. This first <STRONG>PRINT</STRONG> has <EM>number</EM> 0.
 
-
-<P>
-
 </DL>
 <P>
 <HR>
-<H1><A NAME="EXAMPLE">EXAMPLE
-
-</A></H1>
+<H1><A NAME="EXAMPLE_1">EXAMPLE 1</A></H1>
+<P>
 The example below creates a web pages with a single RRD graph.
 
-
 <P>
-
 <PRE> #!/usr/local/bin/rrdcgi
  &lt;HTML&gt;
  &lt;HEAD&gt;&lt;TITLE&gt;RRDCGI Demo&lt;/TITLE&gt;&lt;/HEAD&gt;
@@ -226,28 +179,20 @@
           DEF:cel=demo.rrd:exhaust:AVERAGE
           LINE2:cel#00a000:&quot;D. Celsius&quot;&gt;
 </PRE>
-
 <P>
-
 <PRE> &lt;/P&gt;
  &lt;/BODY&gt;
  &lt;/HTML&gt;
 </PRE>
-
-<P>
-
 <P>
 <HR>
-<H1><A NAME="EXAMPLE_2">EXAMPLE 2
-
-</A></H1>
+<H1><A NAME="EXAMPLE_2">EXAMPLE 2</A></H1>
+<P>
 This script is slightly more elaborate, it allows you to run it from a form
 which sets RRD_NAME. RRD_NAME is then used to select which RRD you want to
 use a source for your graph.
 
-
 <P>
-
 <PRE> #!/usr/local/bin/rrdcgi
  &lt;HTML&gt;
  &lt;HEAD&gt;&lt;TITLE&gt;RRDCGI Demo&lt;/TITLE&gt;&lt;/HEAD&gt;
@@ -264,29 +209,49 @@
           DEF:cel=&lt;RRD::CV::PATH RRD_NAME&gt;.rrd:exhaust:AVERAGE
           LINE2:cel#00a000:&quot;D. Celsius&quot;&gt;
 </PRE>
-
 <P>
-
 <PRE> &lt;/P&gt;
  &lt;/BODY&gt;
  &lt;/HTML&gt;
 </PRE>
-
-<P>
-
 <P>
 <HR>
-<H1><A NAME="AUTHOR">AUTHOR
+<H1><A NAME="EXAMPLE_3">EXAMPLE 3</A></H1>
+<P>
+This example shows how to handle the case where the RRD, graphs and
+cgi-bins are seperate directories
 
-</A></H1>
-Tobias Oetiker &lt;<A HREF="MAILTO:oetiker at ee.ethz.ch">oetiker at ee.ethz.ch</A>&gt;
+<P>
+<PRE> #!/.../bin/rrdcgi
+ &lt;HTML&gt;
+ &lt;HEAD&gt;&lt;TITLE&gt;RRDCGI Demo&lt;/TITLE&gt;&lt;/HEAD&gt;
+ &lt;BODY&gt;
+ &lt;H1&gt;RRDCGI test Page&lt;/H1&gt;
+ &lt;RRD::GRAPH
+  /.../web/gifs/testhvt.gif
+  --imginfo '&lt;IMG SRC=/.../gifs/%s WIDTH=%lu HEIGHT=%lu &gt;'
+  --lazy --start -1d --end now
+  DEF:http_src=/.../rrds/test.rrd:http_src:AVERAGE
+  AREA:http_src#00ff00:http_src
+ &gt;
+ &lt;/BODY&gt;
+ &lt;/HTML&gt;
+</PRE>
+<P>
+Note 1: Replace /.../ with the relevant directories
 
+<P>
+Note 2: The SRC=/.../gifs should be paths from the view of the
+webserver/browser
 
+<P>
+<HR>
+<H1><A NAME="AUTHOR">AUTHOR</A></H1>
+<P>
+Tobias Oetiker &lt;<A HREF="mailto:oetiker at ee.ethz.ch">oetiker at ee.ethz.ch</A>&gt;
 
 
-<P>
 
-</DL>
-    </BODY>
+</BODY>
 
-    </HTML>
+</HTML>

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/RRDs.html
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/RRDs.html	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/RRDs.html	Sat Jul 13 21:08:17 2002
@@ -1,11 +1,10 @@
-    <HTML> 
-	<HEAD> 
-	    <TITLE>RRDs - Access rrdtool as a shared module
+<HTML>
+<HEAD>
+<TITLE>RRDs</TITLE>
+<LINK REV="made" HREF="mailto:karrer at zinal.ee.ethz.ch">
+</HEAD>
 
-</TITLE> 
-	</HEAD>
-
-	<BODY>
+<BODY>
 
 <!-- INDEX BEGIN -->
 <!--
@@ -28,20 +27,15 @@
 <!-- INDEX END -->
 
 <P>
-<H1><A NAME="NAME">NAME
-
-</A></H1>
-RRDs - Access rrdtool as a shared module
-
-
+<H1><A NAME="NAME">NAME</A></H1>
 <P>
+RRDs - Access rrdtool as a shared module
 
 <P>
 <HR>
-<H1><A NAME="SYNOPSIS">SYNOPSIS
-
-</A></H1>
-<PRE>  use RRDs::ext
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE>  use RRDs;
   RRDs::error
   RRDs::last ...
   RRDs::create ...
@@ -50,143 +44,99 @@
   RRDs::fetch ...
   RRDs::tune ...
 </PRE>
-
-<P>
-
 <P>
 <HR>
-<H1><A NAME="DESCRIPTION">DESCRIPTION
-
-</A></H1>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
 <P>
 <HR>
-<H2><A NAME="Calling_Sequence">Calling Sequence
-
-</A></H2>
+<H2><A NAME="Calling_Sequence">Calling Sequence</A></H2>
+<P>
 This module accesses rrdtool functionality directly from within perl. The
 arguments to the functions listed in the SYNOPSIS are explained in the
 regular rrdtool documentation. The commandline call
 
-
 <P>
-
 <PRE> rrdtool update mydemo.rrd N:12:13
 </PRE>
-
 <P>
-
 gets turned into
 
-
 <P>
-
-<PRE> RRDs::update qw(mydemo.rrd N:12:13);
+<PRE> RRDs::update (&quot;mydemo.rrd&quot;, &quot;N:12:13&quot;);
 </PRE>
-
-<P>
-
 <P>
 <HR>
-<H2><A NAME="Error_Handling">Error Handling
-
-</A></H2>
+<H2><A NAME="Error_Handling">Error Handling</A></H2>
+<P>
 The RRD functions will not abort your program even when they can not make
 sense out of the arguments you fed them. There are two ways to determine if
 an error has occured.
 
-
 <P>
-
 First the every function will return the value -1 if an error occured.
 Second, the function RRDs::error can be called to get the error message
 from the last function call. If RRDs::error does not return an error then
 the previous function has completed its task succesfully.
 
-
 <P>
-
-<PRE> RRDs::update qw(mydemo.rrd N:12:13);
+<PRE> use RRDs;
+ RRDs::update (&quot;mydemo.rrd&quot;,&quot;N:12:13&quot;);
  my $ERR=RRDs::error;
  die &quot;ERROR while updating mydemo.rrd: $ERR\n&quot; if $ERR;
 </PRE>
-
-<P>
-
 <P>
 <HR>
-<H2><A NAME="Return_Values">Return Values
-
-</A></H2>
-The functions RRDs::last, RRDs::graph and RRDs::fetchgive return their
-findigs.
-
-
+<H2><A NAME="Return_Values">Return Values</A></H2>
 <P>
+The functions RRDs::last, RRDs::graph and RRDs::fetch return their
+findings.
 
+<P>
 RRDs::last returns a single INTEGER representing the last update time.
 
-
 <P>
-
 <PRE> $lastupdate = RRDs::last ...
 </PRE>
-
 <P>
-
 RRDs::graph returns an pointer to an ARRAY containing the x-size and y-size
 of the created gif and results of the PRINT arguments.
 
-
 <P>
-
 <PRE> ($averages,$xsize,$ysize) = RRDs::graph ...
  print &quot;Gifsize: ${xsize}x${ysize}\n&quot;;
  print &quot;Averages: &quot;, (join &quot;, &quot;, @$averages);
 </PRE>
-
 <P>
-
 RRDs::fetch is the most complex of the pack regarding return values. There
 are 4 values. Two normal integers, a pointer to an array and a pointer to a
 array of pointers.
 
-
 <P>
-
-<PRE> my ($start,$step,$names,$data) = RRDs::fetch ... 
- print &quot;Start:        &quot;.localtime($start).&quot;\n&quot;; 
- print &quot;Stepsize:     $step seconds\n&quot;; 
- print &quot;Column Names: &quot;.join (&quot;, &quot;, @$names).&quot;\n&quot;;
- print &quot;Date:\n&quot;;
- foreach my $line (@$array){
-      print &quot;&quot;.localtime($start),&quot;   &quot;;
-      $start += $step; 
-      foreach my $val (@$line) {                
-           printf &quot;%12.1f&quot;, $val;
-      }
-      print &quot;\n&quot;;
- }
+<PRE>  my ($start,$step,$names,$data) = RRDs::fetch ... 
+  print &quot;Start:       &quot;, scalar localtime($start), &quot; ($start)\n&quot;;
+  print &quot;Step size:   $step seconds\n&quot;;
+  print &quot;DS names:    &quot;, join (&quot;, &quot;, @$names).&quot;\n&quot;;
+  print &quot;Data points: &quot;, $#$data + 1, &quot;\n&quot;;
+  print &quot;Data:\n&quot;;
+  foreach my $line (@$data) {
+    print &quot;  &quot;, scalar localtime($start), &quot; ($start) &quot;;
+    $start += $step;
+    foreach my $val (@$line) {
+      printf &quot;%12.1f &quot;, $val;
+    }
+    print &quot;\n&quot;;
+  }
 </PRE>
-
 <P>
-
 See the examples directory for more ways to use this extension.
 
-
-<P>
-
 <P>
 <HR>
-<H1><A NAME="AUTHOR">AUTHOR
-
-</A></H1>
-Tobias Oetiker <A
-HREF="MAILTO:<oeitker at ee.ethy.ch>"><oeitker at ee.ethy.ch></A>
-
-
+<H1><A NAME="AUTHOR">AUTHOR</A></H1>
 <P>
+Tobias Oetiker &lt;<A
+HREF="mailto:oeitker at ee.ethy.ch">oeitker at ee.ethy.ch</A>&gt;
 
-</DL>
-    </BODY>
+</BODY>
 
-    </HTML>
+</HTML>

Modified: trunk/orca/packages/rrdtool-1.0.13/doc/rrdcreate.html
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/doc/rrdcreate.html	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/doc/rrdcreate.html	Sat Jul 13 21:08:18 2002
@@ -1,11 +1,10 @@
-    <HTML> 
-	<HEAD> 
-	    <TITLE>create - Set up a new Round Robin Database
+<HTML>
+<HEAD>
+<TITLE>rrdcreate</TITLE>
+<LINK REV="made" HREF="mailto:karrer at zinal.ee.ethz.ch">
+</HEAD>
 
-</TITLE> 
-	</HEAD>
-
-	<BODY>
+<BODY>
 
 <!-- INDEX BEGIN -->
 <!--
@@ -22,19 +21,14 @@
 <!-- INDEX END -->
 
 <P>
-<H1><A NAME="NAME">NAME
-
-</A></H1>
-rrdtool create - Set up a new Round Robin Database
-
-
+<H1><A NAME="NAME">NAME</A></H1>
 <P>
+rrdtool create - Set up a new Round Robin Database
 
 <P>
 <HR>
-<H1><A NAME="SYNOPSIS">SYNOPSIS
-
-</A></H1>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
 <STRONG>rrdtool</STRONG>  <STRONG>create</STRONG>  <EM>filename</EM> 
  
 [<STRONG>--start</STRONG>|<STRONG>-b</STRONG>&nbsp;<EM>start&nbsp;time</EM>] 
@@ -47,179 +41,143 @@
 
 
 
-
-<P>
-
 <P>
 <HR>
-<H1><A NAME="DESCRIPTION">DESCRIPTION
-
-</A></H1>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
 The create function of the RRDtool lets you set up new Round Robin Database
 (<STRONG>RRD</STRONG>) files. The file is created at its final, full size and filled with <EM>*UNKNOWN*</EM> data.
 
-
-<P>
-
 <DL>
-<DT><STRONG><A NAME="item_filename">filename
-
-</A></STRONG><DD>
+<DT><STRONG><A NAME="item_filename">filename</A></STRONG><DD>
+<P>
 The name of the <STRONG>RRD</STRONG> you want to create. <STRONG>RRD</STRONG> files should end with the extension <EM>.rrd</EM>. However, <STRONG>rrdtool</STRONG> will accept any filename.
 
-
+<DT><STRONG><A NAME="item__start_b">--start|-b start time (default: now - 10s)</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__start_b">--start|-b start time (default: now - 10s)
-
-</A></STRONG><DD>
 Specifies the time in seconds since 1970-01-01 UTC when the first value
 should be added to the <STRONG>RRD</STRONG>. <STRONG>rrdtool</STRONG> will not accept any data timed before or at the time specified.
 
-
 <P>
-
 See also AT-STYLE TIME SPECIFICATION section in the
 <EM>rrdfetch</EM> documentation for more ways to specify time.
 
-
+<DT><STRONG><A NAME="item__step_s">--step|-s step (default: 300 seconds)</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item__step_s">--step|-s step (default: 300 seconds)
-
-</A></STRONG><DD>
 Specifies the base interval in seconds with which data will be fed into the <STRONG>RRD</STRONG>.
 
-
+<DT><STRONG><A NAME="item_DS">DS:ds-name:DST:heartbeat:min:max</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_DS">DS:ds-name:DST:heartbeat:min:max
-
-</A></STRONG><DD>
 A single <STRONG>RRD</STRONG> can accept input from several data sources (<STRONG>DS</STRONG>). (e.g. Incoming and Outgoing traffic on a specific communication line).
 With the <STRONG>DS</STRONG> configuration option you must define some basic properties of each data
 source you want to use to feed the <STRONG>RRD</STRONG>.
 
-
 <P>
-
 <EM>ds-name</EM> is the name you will use to reference this particular data source from an <STRONG>RRD</STRONG>. A <EM>ds-name</EM> must be 1 to 19 characters long in the characters [a-zA-Z0-9_].
 
+<P>
+<EM>DST</EM> defines the Data Source Type. It can be one of the following:
 
+<DL>
+<DT><STRONG><A NAME="item_GAUGE">GAUGE</A></STRONG><DD>
 <P>
+is for things like temperatures or number of people in a room or value of a
+RedHat share.
 
-<EM>DST</EM> defines the Data Source Type. It can be one of the following:
-<STRONG>GAUGE</STRONG> this is for things like temperatures or number of people in a room. <STRONG>COUNTER</STRONG> is for continuous incrementing counters like the InOctets counter in a
+<DT><STRONG><A NAME="item_COUNTER">COUNTER</A></STRONG><DD>
+<P>
+is for continuous incrementing counters like the InOctets counter in a
 router. The <STRONG>COUNTER</STRONG> data source assumes that the counter never decreases, except when a counter
 overflows. The update function takes the overflow into account. The counter
-is stored as a per-second rate. <STRONG>DERIVE</STRONG> will store the the derivative of the line going from the last to the
-current value of the data source. This can be useful for gauges, for
-example, to measure the rate of people entering or leaving a room. <STRONG>ABSOLUTE</STRONG> is for counters which get reset upon reading.
-
+is stored as a per-second rate. When the counter overflows, RRDtool checks
+if the overflow happened at the 32bit or 64bit border and acts accordingly
+by adding an appropriate value to the result.
 
+<DT><STRONG><A NAME="item_DERIVE">DERIVE</A></STRONG><DD>
 <P>
+will store the the derivative of the line going from the last to the
+current value of the data source. This can be useful for gauges, for
+example, to measure the rate of people entering or leaving a room.
+Internally, derive works exaclty like COUNTER but without overflow checks.
+So if your counter does not reset at 32 or 64 bit you might want to use
+DERIVE and combine it with a MIN value of 0.
+
+<DT><STRONG><A NAME="item_ABSOLUTE">ABSOLUTE</A></STRONG><DD>
+<P>
+is for counters which get reset upon reading. This is used for fast
+counters which tend to overflow. So instead of reading them normally you
+reset them after every read to make sure you have a maximal time available
+before the next overflow.
 
+</DL>
+<P>
 <EM>heartbeat</EM> defines the maximum number of seconds that may pass between two updates of
 this data source before the value of the data source is assumed to be <EM>*UNKNOWN*</EM>.
 
-
 <P>
-
 <EM>min</EM> and <EM>max</EM> are optional entries defining the expected range of the data supplied by
 this data source. If <EM>min</EM> and/or <EM>max</EM> are defined, any value outside the defined range will be regarded as
 <EM>*UNKNOWN*</EM>. If you do not know or care about min and max, set them to U for unknown.
 Note that min and max always refer to the processed values of the DS. For a
 traffic-<STRONG>COUNTER</STRONG> type DS this would be the max and min data-rate expected from the device.
 
-
 <P>
-
 <EM>If information on minimal/maximal expected values is available,
 always set the min and/or max properties. This will help RRDtool in
 doing a simple sanity check on the data supplied when running update.</EM>
 
 
 
-
+<DT><STRONG><A NAME="item_RRA">RRA:CF:xff:steps:rows</A></STRONG><DD>
 <P>
-
-<DT><STRONG><A NAME="item_RRA">RRA:CF:xff:steps:rows
-
-</A></STRONG><DD>
 The purpose of an <STRONG>RRD</STRONG> is to store data in the round robin archives (<STRONG>RRA</STRONG>). An archive consists of a number of data values from all the defined
 data-sources (<STRONG>DS</STRONG>) and is defined with an <STRONG>RRA</STRONG> line.
 
-
 <P>
-
 When data is entered into an <STRONG>RRD</STRONG>, it is first fit into time slots of the length defined with the <STRONG>-s</STRONG> option becoming a <EM>primary data point</EM>.
 
-
 <P>
-
 The data is also consolidated with the consolidation function (<EM>CF</EM>) of the archive. The following consolidation functions are defined:
 <STRONG>AVERAGE</STRONG>, <STRONG>MIN</STRONG>, <STRONG>MAX</STRONG>, <STRONG>LAST</STRONG>.
 
-
 <P>
-
 <EM>xff</EM> The xfiles factor defines what part of a consolidation interval may be made
-up from <EM>*UNKNOWN*</EM> data while the consolidated value is sill regarded as known.
-
+up from <EM>*UNKNOWN*</EM> data while the consolidated value is still regarded as known.
 
 <P>
-
 <EM>steps</EM> defines how many of these <EM>primary data points</EM> are used to build a <EM>consolidated data point</EM> which then goes into the archive.
 
-
 <P>
-
 <EM>rows</EM> defines how many generations of data values are kept in an <STRONG>RRA</STRONG>.
 
-
-<P>
-
 </DL>
 <P>
 <HR>
-<H1><A NAME="EXAMPLE">EXAMPLE
-
-</A></H1>
+<H1><A NAME="EXAMPLE">EXAMPLE</A></H1>
+<P>
 <CODE>rrdtool create temperature.rrd --step 300 DS:temp:GAUGE:600:-273:5000
 RRA:AVERAGE:0.5:1:1200 RRA:MIN:0.5:12:2400 RRA:MAX:0.5:12:2400
 RRA:AVERAGE:0.5:12:2400</CODE>
 
 
 
-
 <P>
-
 This sets up an <STRONG>RRD</STRONG> called <EM>temperature.rrd</EM> which accepts one temperature value every 300 seconds. If no new data is
 supplied for more than 600 seconds, the temperature becomes <EM>*UNKNOWN*</EM>. The minimum acceptable value is -273 and the maximum is 5000.
 
-
 <P>
-
 A few archives areas are also defined. The first stores the temperatures
 supplied for 100 hours (1200 * 300 seconds = 100 hours). The second RRA
 stores the minimum temperature recorded over every hour (12 * 300 seconds =
 1 hour), for 100 days (2400 hours). The third and the fourth RRA's do the
 same with the for the maximum and average temperature, respectively.
 
-
-<P>
-
 <P>
 <HR>
-<H1><A NAME="AUTHOR">AUTHOR
-
-</A></H1>
-Tobias Oetiker &lt;<A HREF="MAILTO:oetiker at ee.ethz.ch">oetiker at ee.ethz.ch</A>&gt;
-
-
+<H1><A NAME="AUTHOR">AUTHOR</A></H1>
 <P>
+Tobias Oetiker &lt;<A HREF="mailto:oetiker at ee.ethz.ch">oetiker at ee.ethz.ch</A>&gt;
 
-</DL>
-    </BODY>
+</BODY>
 
-    </HTML>
+</HTML>

Modified: trunk/orca/packages/rrdtool-1.0.13/perl-shared/t/base.t
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/perl-shared/t/base.t	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/perl-shared/t/base.t	Sat Jul 13 21:08:18 2002
@@ -125,14 +125,14 @@
           "LINE3:calc#00ff44:Line 3",
           "LINE3:epsilon#000000:Line 4",
           "HRULE:1500#ff8800:Horizontal Line at 1500",
-          "PRINT:alpha:AVERAGE:Average Alpha %1.2f",
-          "PRINT:alpha:MIN:Min Alpha %1.2f %s",
-          "PRINT:alpha:MIN:Min Alpha %1.2f",
-          "PRINT:alpha:MAX:Max Alpha %1.2f",
-          "GPRINT:calc:AVERAGE:Average calc %1.2f %s",
-          "GPRINT:calc:AVERAGE:Average calc %1.2f",
-          "GPRINT:calc:MAX:Max calc %1.2f",
-          "GPRINT:calc:MIN:Min calc %1.2f",
+          "PRINT:alpha:AVERAGE:Average Alpha %1.2lf",
+          "PRINT:alpha:MIN:Min Alpha %1.2lf %s",
+          "PRINT:alpha:MIN:Min Alpha %1.2lf",
+          "PRINT:alpha:MAX:Max Alpha %1.2lf",
+          "GPRINT:calc:AVERAGE:Average calc %1.2lf %s",
+          "GPRINT:calc:AVERAGE:Average calc %1.2lf",
+          "GPRINT:calc:MAX:Max calc %1.2lf",
+          "GPRINT:calc:MIN:Min calc %1.2lf",
           "VRULE:".($now-3600)."#008877:60 Minutes ago",
           "VRULE:".($now-7200)."#008877:120 Minutes ago";
 

Modified: trunk/orca/packages/rrdtool-1.0.13/perl-shared/RRDs.xs
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/perl-shared/RRDs.xs	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/perl-shared/RRDs.xs	Sat Jul 13 21:08:18 2002
@@ -11,14 +11,27 @@
 #endif
 
 #include "../src/rrd_tool.h"
-
+#ifndef PL_na
+#define PL_na na
+#endif
 #define rrdcode(name) \
 		argv = (char **) malloc((items+1)*sizeof(char *));\
 		argv[0] = "dummy";\
-		for (i = 0; i < items; i++) argv[i+1] = (char *) SvPV(ST(i),na);\
+		for (i = 0; i < items; i++) { \
+		    char *handle=argv[i+1] = (char *) SvPV(ST(i),PL_na);\
+		    /* actually copy the data to make sure possible modifications \
+		       on the argv data does not backfire into perl */ \
+		    argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char)); \
+		    strcpy(argv[i+1],handle); \
+ 	        } \
 		optind=0; opterr=0; \
 		rrd_clear_error();\
-		RETVAL=name(items+1,argv); free(argv);\
+		RETVAL=name(items+1,argv); \
+		for (i=0; i < items; i++) {\
+		    free(argv[i+1]);\
+		} \
+		free(argv);\
+		\
 		if (rrd_get_error() != NULL) XSRETURN_UNDEF;
 
 
@@ -87,6 +100,19 @@
 		RETVAL
 
 
+int
+rrd_tune(...)
+	PROTOTYPE: @	
+	PREINIT:
+        int i;
+	char **argv;
+	CODE:
+		rrdcode(rrd_tune);
+       	        RETVAL = 1;
+	OUTPUT:
+		RETVAL
+
+
 void
 rrd_graph(...)
 	PROTOTYPE: @	
@@ -98,10 +124,20 @@
 	PPCODE:
 		argv = (char **) malloc((items+1)*sizeof(char *));
 		argv[0] = "dummy";
-		for (i = 0; i < items; i++) argv[i+1] = (char *) SvPV(ST(i),na);
+		for (i = 0; i < items; i++) { 
+		    char *handle=argv[i+1] = (char *) SvPV(ST(i),PL_na);
+		    /* actually copy the data to make sure possible modifications
+		       on the argv data does not backfire into perl */ 
+		    argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char));
+		    strcpy(argv[i+1],handle);
+ 	        }
 		optind=0; opterr=0; 
 		rrd_clear_error();
-		rrd_graph(items+1,argv,&calcpr,&xsize,&ysize); free(argv);
+		rrd_graph(items+1,argv,&calcpr,&xsize,&ysize); 
+		for (i=0; i < items; i++) {
+		    free(argv[i+1]);
+		}
+		free(argv);
 
 		if (rrd_test_error()) {
 			if(calcpr)
@@ -135,11 +171,20 @@
 	PPCODE:
 		argv = (char **) malloc((items+1)*sizeof(char *));
 		argv[0] = "dummy";
-		for (i = 0; i < items; i++) argv[i+1] = (char *) SvPV(ST(i),na);
+		for (i = 0; i < items; i++) { 
+		    char *handle=argv[i+1] = (char *) SvPV(ST(i),PL_na);
+		    /* actually copy the data to make sure possible modifications
+		       on the argv data does not backfire into perl */ 
+		    argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char));
+		    strcpy(argv[i+1],handle);
+ 	        }
 		optind=0; opterr=0; 
 		rrd_clear_error();
 		rrd_fetch(items+1,argv,&start,&end,&step,&ds_cnt,&ds_namv,&data); 
 		if (rrd_test_error()) XSRETURN_UNDEF;
+		for (i=0; i < items; i++) {
+		    free(argv[i+1]);
+		}
 		free(argv);
 		/* convert the ds_namv into perl format */
 		names=newAV();
@@ -164,19 +209,6 @@
 		PUSHs(sv_2mortal(newRV_noinc((SV*)names)));
 		PUSHs(sv_2mortal(newRV_noinc((SV*)retar)));
 
-int
-rrd_tune(...)
-	PROTOTYPE: @	
-	PREINIT:
-        int i;
-	char **argv;
-	CODE:
-		rrdcode(rrd_tune);
-       	        RETVAL = 1;
-	OUTPUT:
-		RETVAL
-
-
 
 
 

Modified: trunk/orca/packages/rrdtool-1.0.13/perl-shared/RRDs.pm
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/perl-shared/RRDs.pm	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/perl-shared/RRDs.pm	Sat Jul 13 21:08:18 2002
@@ -7,7 +7,7 @@
 
 require DynaLoader;
 
-$VERSION = 1.000072;
+$VERSION = 1.000131;
 
 bootstrap RRDs $VERSION;
 
@@ -20,7 +20,7 @@
 
 =head1 SYNOPSIS
 
-  use RRDs::ext
+  use RRDs;
   RRDs::error
   RRDs::last ...
   RRDs::create ...
@@ -41,7 +41,7 @@
 
 gets turned into
 
- RRDs::update qw(mydemo.rrd N:12:13);
+ RRDs::update ("mydemo.rrd", "N:12:13");
 
 =head2 Error Handling
 
@@ -54,14 +54,15 @@
 from the last function call. If RRDs::error does not return an error
 then the previous function has completed its task succesfully.
 
- RRDs::update qw(mydemo.rrd N:12:13);
+ use RRDs;
+ RRDs::update ("mydemo.rrd","N:12:13");
  my $ERR=RRDs::error;
  die "ERROR while updating mydemo.rrd: $ERR\n" if $ERR;
 
 =head2 Return Values
 
-The functions RRDs::last, RRDs::graph and RRDs::fetchgive return their
-findigs.
+The functions RRDs::last, RRDs::graph and RRDs::fetch return their
+findings.
 
 RRDs::last returns a single INTEGER representing the last update time.
 
@@ -78,19 +79,20 @@
 4 values. Two normal integers, a pointer to an array and a pointer to a
 array of pointers.
 
- my ($start,$step,$names,$data) = RRDs::fetch ... 
- print "Start:        ".localtime($start)."\n"; 
- print "Stepsize:     $step seconds\n"; 
- print "Column Names: ".join (", ", @$names)."\n";
- print "Date:\n";
- foreach my $line (@$array){
-      print "".localtime($start),"   ";
-      $start += $step; 
-      foreach my $val (@$line) {		
-           printf "%12.1f", $val;
-      }
-      print "\n";
- }
+  my ($start,$step,$names,$data) = RRDs::fetch ... 
+  print "Start:       ", scalar localtime($start), " ($start)\n";
+  print "Step size:   $step seconds\n";
+  print "DS names:    ", join (", ", @$names)."\n";
+  print "Data points: ", $#$data + 1, "\n";
+  print "Data:\n";
+  foreach my $line (@$data) {
+    print "  ", scalar localtime($start), " ($start) ";
+    $start += $step;
+    foreach my $val (@$line) {
+      printf "%12.1f ", $val;
+    }
+    print "\n";
+  }
 
 See the examples directory for more ways to use this extension.
 

Modified: trunk/orca/packages/rrdtool-1.0.13/CHANGES
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/CHANGES	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/CHANGES	Sat Jul 13 21:08:19 2002
@@ -1,8 +1,218 @@
-CangeLog for RRDtool 1.0.x
---------------------------
+ChangeLog for RRDtool 1.0.x
+---------------------------
 - bugfix, + enhancement, * contrib, = RELEASE
 ---------------------------------------------
 
+= 1.0.13 2000/02/13 -- Tobi
+
+- 2000/02/13 -- Tobi
+  restored rrd_tool.h ... got zeroed during the last distro process ...
+
+= 1.0.12 2000/02/12 -- Tobi
+
+* 2000/02/12 -- Rainer Nagel <rainer at roka.net>
+  contributed rrdfetchnames for getting names of an rrd
+
++ 2000/02/12 -- Tobi
+  more documentation on COUNTER/ABSOLUTE/GAUGE ....
+
++ 2000/02/12 -- Tobi
+  added try time to build process
+
+- 2000/02/11 -- Philippe.Simonet at swisscom.com
+  NT thinks 0 > NaN || 0 < NaN == ture ... fied rrd_update.c accordingly
+
+- 2000/02/09 -- Tobi
+  added FPMASK and SIG8 fixes to rrd_cgi ... will prevent it from sig FPE crashes
+  on FreeBSD and others ...
+
++ 2000/02/08 -- Tobi
+  Improved \g by giving it the ability to squash empty %s
+  return values
+
+= 1.0.11 2000/02/06 -- Tobi
+
++ 2000/02/06 -- Tobi
+  added formating marker '\g' to rrd_graph to remove
+  the spacing between two items printed into the graph
+  
+- 2000/02/06 -- Tobi
+  make sure rrd_graph --lazy does not get confused by broken
+  images.
+
+- 2000/02/06 -- Tobi
+  applie range check to values supplied to update and not
+  to pdp values
+
+- 2000/02/06 -- Tobi
+  fixed rpn parser to allow variable names like nantuket
+
++ 2000/01/14 -- hendrik visage <hvisage at is.co.za>
+  another example for rrdcgi manpage
+
+* 2000/02/06 -- Bert Driehuis <driehuis at playbeing.org>
+  contrib script to kill spikes from rrd dump
+
+- 2000/02/06 -- steve rader <rader at teak.wiscnet.net>
+  fixed 'fetch' example in the RRDs manpage
+
+* 2000/01/10 -- Selena M Brewington <smbrewin at ichips.intel.com>
+  contributed add_ds a perl script for adding new ds es to existing rrds
+
+* 2000/01/10 -- steve rader <rader at teak.wiscnet.net>
+  contributed rrdlastds script ... pulling current values from an rrd
+
+- 2000/02/06 -- Tobi
+  --goodfor and --refresh did not work for rrdcgi as the arguments never got
+  passed on. Introduced <RRD::GOODFOR x> command in rrdcgi language to
+  fix this problem
+
+- 2000/02/06 -- Tobi
+  using - as input did not work for rrd_restore ... 
+
+- 2000/01/26 -- Tobi
+  pass name of the c compile to the perl build along with the CFLAGS
+
+- 2000/01/26 -- Tobi
+  Removed special provisions for HPUX from rrd_format ... this might actually help HPUX to get
+  the NaN problems fixed
+
+- 2000/01/24 -- Tobi
+  in rrd_graph the data consolidation routine was initializing the with 0 instead of DNAN
+  this led to rather log MIN values 
+
+= 1.0.10 2000/01/07 -- Tobi
+
+- 2000/01/07 -- Bill Fenner <fenner at research.att.com>
+  The Update Bug solved ... rrdtool was in violation of the ANSI
+  C standard (7.9.5.3) by issuing a fwrite immediately after an
+  fread without fseek inbetween
+
++ 2000/01/03 -- Tobi
+  added <RRD::TIME::NOW function to rrdcgi
+
+- 2000/01/03 -- Tobi
+  added documentation for <RRD::SETENV to rrdcgi.pod
+
+- 2000/01/03 -- steve rader <rader at teak.wiscnet.net>
+  better explanation of lower and upper limit for rrdgraph
+
+- 2000/01/03 -- Tobi
+  fixed PRINT commands in example scripts
+
+- 2000/01/03 -- Tobi
+  to test -fPIC actually RUN a program ..
+
+= 1.0.9 1999/12/25 -- Tobi
+
+- 1999/12/14 -- Tobi
+  use -fPIC when compiling and if the compiuler does not mind ... some platforms
+  have issues with the RRDs package otherwhise ...
+
+- 1999/12/11 -- Tobi
+  improved format check in rrd_graph
+
+* 1999/11/30 -- Damien Miller <djm at mindrot.org>
+  rrdproc tool ... run linux interface stats straight from proc into rrdtool
+
+= 1.0.8 1999/11/24 -- Tobi
+
+- 1999/11/15 -- thomas.erskine at crc.ca
+  veryfy G?PRINT format strings before executing them ...
+
+- 1999/11/14 -- Tobi
+  the perl-module (RRDs.xs) does now strcpy its arguments. This fixes some
+  stray problems where the rrdtool code was modifying argv values (eg.
+  update --template) and thus backfired into perl proper.
+
+- 1999/11/12 -- Valient Gough <vgough at amazon.com>
+  define STDC in zlib/zconf.h ... rrdtool needs it anyway and
+  without STDC there will be no prototypes which will be a big
+  problem for less tolerant compilers ... does any sensible c compiler
+  not understand prototypes today?
+
+- 1999/11/04 -- Ian Freislich <iang at uunet.co.za>
+  better formatting with large values for rrdtool fetch
+
+- 1999/11/04 -- Paul E. Erkkila <pee at frontiernet.net>                                            
+  made RRDs work on lates perl betas as well as current ones na -> PL_na
+
+- 1999/11/03 -- Tobi & Alex van den Bogaerdt <alex at slot.hollandcasino.nl>
+  fix for autoscaling problems with UNKNOWN values 
+
+- 1999/11/02 -- Tobi
+  rrdcgi was unable to parse two tags running into each other
+  if they were of exactly the same type
+ 
+- 1999/11/02 -- Tobi
+  moved check for FINITE function on acconfig and configure.in
+  so that it can use isinf even if it has to be defined first.
+
+- 1999/10/26 -- Fidelis Assis <fidelis at embratel.net.br>
+  modified gd string functions to use unsigned char  
+
+- 1999/10/24 -- Tobi
+  added test for float.h to configure
+
+- 1999/10/24 -- Tobi
+  Fixed version reporting with rrdtool help
+- 1999/10/24 -- Tobi, Blair Zajac <bzajac at geostaff.com> and Tobias Weingartner <weingart at cs.ualberta.ca>
+  use vsnprintf in rrd_error (max buffer raised to 4096
+
+- 1999/10/24 -- Tobi, Blair Zajac <bzajac at geostaff.com> and Tobias Weingartner <weingart at cs.ualberta.ca>
+  use MAXPATH to determ max path length for filenames in rrd_graph and rrd_open
+
+- 1999/10/24 -- Stefan Mueller <s.mueller at computer.org>
+  better HPUX portability
+
+- 1999/10/24 -- Steve Harris <steveh at wesley.com.au>, Ulrich Schilling <schilling at netz.uni-essen.de>, Joel Becker <jlbec at raleigh.ibm.com>, REIBENSCHUH Alfred <alfred.reibenschuh at it-austria.com>
+  better AIX portability
+
+- 1999/10/24 -- Tobi
+  Fixed PRINT 1 bug in rrdcgi
+
+- 1999/10/24 -- Tobi
+  Removed remaining LZW code from our version of gd
+
+* 1999/10/04 -- steve rader <rader at teak.wiscnet.net>
+  contributed rpntutorial
+
++ 1999/10/04 -- steve rader <rader at teak.wiscnet.net> + Tobi
+  RRD::TIME::LAST function for rrdcgi
+
+- 1999/10/04 -- Bryan Mawhinney <bryanm at is.co.za>
+  improved wording in rrdgraph.pod
+
+* 1999/10/02 -- Alex with help of Steve Rader and others
+  added CDEF tutorial
+
++ 1999/10/02 -- Steve + Alex
+  Large amount of fixes to rrdtutorial.pod, thanks Steve!
+
+- 1999/09/30 -- tobi
+  fixed --template option in update ... for good this time ?
+
++ 1999/09/30 -- steveh at wesley.com.au, Ulrich Schilling <hrz240 at hrz.uni-essen.de>
+  first go at makeing it work on AIX
+
++ 1999/09/30 -- Bill Fenner <fenner at research.att.com>
+  disable fpmask was not propagated to perl module build ...
+
++ 1999/09/30 -- Bill Fenner <fenner at research.att.com>
+  added PREV function to CDEF language ... 
+
++ 1999/09/30 -- Paul Joslin <Paul.Joslin at sdrc.com>
+  first go at makeing it work on HPUX 10.20
+
++ 1999/09/30 -- Daniel S. Riley <dsr at mail.lns.cornell.edu> and Larry Leszczynski <larryl at furph.com> and Clive Lilley <clive at lilley31.freeserve.co.uk>
+  first go at makeing it work on OSF1 4.0e
+
+- 1999/09/30 -- Bill Fenner <fenner at research.att.com>
+  make sure a filename is supplied in rrd_graph ... 
+
+- 1999/09/30 -- Blair Zajac <bzajac at geostaff.com>
+  Makefile fixes for perl module cleaning and installing in site-perl
+
 = 1.0.7 1999/08/27 -- Tobi
 
 - 1999/08/27 -- bdowling at noc.faxnet.net
@@ -72,7 +282,7 @@
   Fixed CDEF parser ... it should now be fine with a,-1,*
 
 - 1999/08/14 -- Tobi
-  Updated rrdgraph manpage to be in line with the changes I made to alexs
+  Updated rrdgraph manpage to be in line with the changes I made to alex's
   INF patch when integrating it ... sorry alex
 
 

Modified: trunk/orca/packages/rrdtool-1.0.13/COPYRIGHT
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/COPYRIGHT	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/COPYRIGHT	Sat Jul 13 21:08:19 2002
@@ -16,6 +16,5 @@
  more details.
 
  You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc., 675
- Mass Ave, Cambridge, MA 02139, USA. 
-
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA

Modified: trunk/orca/packages/rrdtool-1.0.13/COPYING
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/COPYING	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/COPYING	Sat Jul 13 21:08:19 2002
@@ -2,7 +2,7 @@
 		       Version 2, June 1991
 
  Copyright (C) 1989, 1991 Free Software Foundation, Inc.
-                          675 Mass Ave, Cambridge, MA 02139, USA
+ 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
  Everyone is permitted to copy and distribute verbatim copies
  of this license document, but changing it is not allowed.
 

Modified: trunk/orca/packages/rrdtool-1.0.13/libpng-1.0.3/Makefile.in
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/libpng-1.0.3/Makefile.in	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/libpng-1.0.3/Makefile.in	Sat Jul 13 21:08:19 2002
@@ -119,7 +119,7 @@
 
 DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
 
-TAR = tar
+TAR = gtar
 GZIP_ENV = --best
 SOURCES = $(librrd_png_la_SOURCES)
 OBJECTS = $(librrd_png_la_OBJECTS)

Modified: trunk/orca/packages/rrdtool-1.0.13/Makefile.am
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/Makefile.am	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/Makefile.am	Sat Jul 13 21:08:20 2002
@@ -1,5 +1,5 @@
 ## Process this file with automake to produce Makefile.in
-
+RSYNC = rsync --rsh=ssh
 # build the following subdirectories
 SUBDIRS = cgilib-0.4 config gd1.3 zlib-1.1.3 libpng-1.0.3 src doc examples contrib
 
@@ -34,13 +34,13 @@
 
 # rules for building the perl module
 perl_piped: perl-piped/Makefile
-	cd perl-piped && $(MAKE)  OPTIMIZE="$(CFLAGS)"
+	cd perl-piped && $(MAKE)  OPTIMIZE="$(CFLAGS)" CC="$(CC)"
 
 perl-piped/Makefile: perl-piped/Makefile.PL
 	cd perl-piped && $(PERL) Makefile.PL
 
 perl_shared: perl-shared/Makefile
-	cd perl-shared && $(MAKE) OPTIMIZE="$(CFLAGS)"
+	cd perl-shared && $(MAKE) OPTIMIZE="$(CFLAGS)" CC="$(CC)"
 
 perl-shared/Makefile: perl-shared/Makefile.PL
 	cd perl-shared && $(PERL) Makefile.PL
@@ -59,24 +59,27 @@
 
 to-docs: to-versync
 	(cd doc && $(MAKE) clean && $(MAKE))
+
 #to-autoconf
 to-versync: 
 	perl -i -p -e '"$(VERSION)" =~ /(\d+)\.(\d+)\.(\d+)/; $$v=sprintf("%1d.%02d0%02d1" ,$${1},$${2},$${3}); s|VERSION\s*=\s*[\d.]+|VERSION = $$v|' perl-*/RRD?.pm
-	perl -i -p -e 's|RRDtool\s+\d+\.\d+\.\d+|RRDtool $(VER)|' src/*.[ch]
+	perl -i -p -e 's|RRDtool\s+\d+\.\d+\.\d+ |RRDtool $(VERSION) |' src/*.[ch]
 
 to-dist: to-docs dist
 	mv $(PACKAGE)-$(VERSION).tar.gz archive
 
 to-scp: to-dist
-	scp CHANGES oetiker at tardis.ee.ethz.ch:/home/oetiker/public_html/webtools/rrdtool/pub/
-	scp archive/$(PACKAGE)-$(VERSION).tar.gz oetiker at tardis.ee.ethz.ch:/home/oetiker/public_html/webtools/rrdtool/pub/$(ARCHIVE)
-	scp CHANGES tobi at ipn.caida.org:/ipn/web/Tools/RRDtool/pub/
-	scp archive/$(PACKAGE)-$(VERSION).tar.gz tobi at ipn.caida.org:/ipn/web/Tools/RRDtool/pub/
+	$(RSYNC) CHANGES  archive/$(PACKAGE)-$(VERSION).tar.gz oetiker at tardis.ee.ethz.ch:/home/oetiker/public_html/webtools/rrdtool/pub/
+	$(RSYNC) CHANGES archive/$(PACKAGE)-$(VERSION).tar.gz tobi at ipn.caida.org:/ipn/web/Tools/RRDtool/pub/
 
-site-perl-inst:
+site-perl-inst: site-perl-install
+
+site-perl-install: perl-piped/Makefile perl-shared/Makefile
 	cd perl-piped && $(MAKE) install
 	cd perl-shared && $(MAKE) install
 
 clean-local:
-	cd perl-piped && $(MAKE) clean
-	cd perl-shared && $(MAKE) clean
+	cd perl-piped && test -f Makefile && $(MAKE) clean || true
+	cd perl-shared && test -f Makefile && $(MAKE) clean || true
+
+##END##

Modified: trunk/orca/packages/rrdtool-1.0.13/gd1.3/gd.h
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/gd1.3/gd.h	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/gd1.3/gd.h	Sat Jul 13 21:08:20 2002
@@ -101,8 +101,8 @@
 int gdImageBoundsSafe(gdImagePtr im, int x, int y);
 void gdImageChar(gdImagePtr im, gdFontPtr f, int x, int y, int c, int color);
 void gdImageCharUp(gdImagePtr im, gdFontPtr f, int x, int y, int c, int color);
-void gdImageString(gdImagePtr im, gdFontPtr f, int x, int y, char *s, int color);
-void gdImageStringUp(gdImagePtr im, gdFontPtr f, int x, int y, char *s, int color);
+void gdImageString(gdImagePtr im, gdFontPtr f, int x, int y, unsigned char *s, int color);
+void gdImageStringUp(gdImagePtr im, gdFontPtr f, int x, int y, unsigned char *s, int color);
 void gdImageString16(gdImagePtr im, gdFontPtr f, int x, int y, unsigned short *s, int color);
 void gdImageStringUp16(gdImagePtr im, gdFontPtr f, int x, int y, unsigned short *s, int color);
 

Modified: trunk/orca/packages/rrdtool-1.0.13/gd1.3/README.rrdtool
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/gd1.3/README.rrdtool	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/gd1.3/README.rrdtool	Sat Jul 13 21:08:20 2002
@@ -1,2 +1,2 @@
 This version of gd has been included with rrdtool, the lucida fonts have been
-added for the benefit of rrdtool
+added for the benefit of rrdtool and all LZW code has been removed ...

Modified: trunk/orca/packages/rrdtool-1.0.13/gd1.3/Makefile.in
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/gd1.3/Makefile.in	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/gd1.3/Makefile.in	Sat Jul 13 21:08:20 2002
@@ -114,7 +114,7 @@
 
 DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
 
-TAR = tar
+TAR = gtar
 GZIP_ENV = --best
 SOURCES = $(librrd_gd_la_SOURCES)
 OBJECTS = $(librrd_gd_la_OBJECTS)

Modified: trunk/orca/packages/rrdtool-1.0.13/gd1.3/gd.c
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/gd1.3/gd.c	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/gd1.3/gd.c	Sat Jul 13 21:08:21 2002
@@ -477,7 +477,7 @@
 }
 
 void gdImageString(gdImagePtr im, gdFontPtr f, 
-	int x, int y, char *s, int color)
+	int x, int y, unsigned char *s, int color)
 {
 	int i;
 	int l;
@@ -489,7 +489,7 @@
 }
 
 void gdImageStringUp(gdImagePtr im, gdFontPtr f, 
-	int x, int y, char *s, int color)
+	int x, int y, unsigned char *s, int color)
 {
 	int i;
 	int l;
@@ -1554,478 +1554,8 @@
 } GifScreen;
 #endif
 
-static struct {
-       int     transparent;
-       int     delayTime;
-       int     inputFlag;
-       int     disposal;
-} Gif89 = { -1, -1, -1, 0 };
-
-static int ReadColorMap (FILE *fd, int number, unsigned char (*buffer)[256]);
-static int DoExtension (FILE *fd, int label, int *Transparent);
-static int GetDataBlock (FILE *fd, unsigned char *buf);
-static int GetCode (FILE *fd, int code_size, int flag);
-static int LWZReadByte (FILE *fd, int flag, int input_code_size);
-static void ReadImage (gdImagePtr im, FILE *fd, int len, int height, unsigned char (*cmap)[256], int interlace, int ignore);
-
 int ZeroDataBlock;
 
-gdImagePtr
-gdImageCreateFromGif(FILE *fd)
-{
-       int imageNumber;
-       int BitPixel;
-       int ColorResolution;
-       int Background;
-       int AspectRatio;
-       int Transparent = (-1);
-       unsigned char   buf[16];
-       unsigned char   c;
-       unsigned char   ColorMap[3][MAXCOLORMAPSIZE];
-       unsigned char   localColorMap[3][MAXCOLORMAPSIZE];
-       int             imw, imh;
-       int             useGlobalColormap;
-       int             bitPixel;
-       int             imageCount = 0;
-       char            version[4];
-       gdImagePtr im = 0;
-       ZeroDataBlock = FALSE;
-
-       imageNumber = 1;
-       if (! ReadOK(fd,buf,6)) {
-		return 0;
-	}
-       if (strncmp((char *)buf,"GIF",3) != 0) {
-		return 0;
-	}
-       strncpy(version, (char *)buf + 3, 3);
-       version[3] = '\0';
-
-       if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) {
-		return 0;
-	}
-       if (! ReadOK(fd,buf,7)) {
-		return 0;
-	}
-       BitPixel        = 2<<(buf[4]&0x07);
-       ColorResolution = (int) (((buf[4]&0x70)>>3)+1);
-       Background      = buf[5];
-       AspectRatio     = buf[6];
-
-       if (BitSet(buf[4], LOCALCOLORMAP)) {    /* Global Colormap */
-               if (ReadColorMap(fd, BitPixel, ColorMap)) {
-			return 0;
-		}
-       }
-       for (;;) {
-               if (! ReadOK(fd,&c,1)) {
-                       return 0;
-               }
-               if (c == ';') {         /* GIF terminator */
-                       int i;
-                       if (imageCount < imageNumber) {
-                               return 0;
-                       }
-                       /* Terminator before any image was declared! */
-                       if (!im) {
-                              return 0;
-                       }
-		       /* Check for open colors at the end, so
-                          we can reduce colorsTotal and ultimately
-                          BitsPerPixel */
-                       for (i=((im->colorsTotal-1)); (i>=0); i--) {
-                               if (im->open[i]) {
-                                       im->colorsTotal--;
-                               } else {
-                                       break;
-                               }
-                       } 
-                       return im;
-               }
-
-               if (c == '!') {         /* Extension */
-                       if (! ReadOK(fd,&c,1)) {
-                               return 0;
-                       }
-                       DoExtension(fd, c, &Transparent);
-                       continue;
-               }
-
-               if (c != ',') {         /* Not a valid start character */
-                       continue;
-               }
-
-               ++imageCount;
-
-               if (! ReadOK(fd,buf,9)) {
-	               return 0;
-               }
-
-               useGlobalColormap = ! BitSet(buf[8], LOCALCOLORMAP);
-
-               bitPixel = 1<<((buf[8]&0x07)+1);
-
-               imw = LM_to_uint(buf[4],buf[5]);
-               imh = LM_to_uint(buf[6],buf[7]);
-	       if (!(im = gdImageCreate(imw, imh))) {
-			 return 0;
-	       }
-               im->interlace = BitSet(buf[8], INTERLACE);
-               if (! useGlobalColormap) {
-                       if (ReadColorMap(fd, bitPixel, localColorMap)) { 
-                                 return 0;
-                       }
-                       ReadImage(im, fd, imw, imh, localColorMap, 
-                                 BitSet(buf[8], INTERLACE), 
-                                 imageCount != imageNumber);
-               } else {
-                       ReadImage(im, fd, imw, imh,
-                                 ColorMap, 
-                                 BitSet(buf[8], INTERLACE), 
-                                 imageCount != imageNumber);
-               }
-               if (Transparent != (-1)) {
-                       gdImageColorTransparent(im, Transparent);
-               }	   
-       }
-}
-
-static int
-ReadColorMap(FILE *fd, int number, unsigned char (*buffer)[256])
-{
-       int             i;
-       unsigned char   rgb[3];
-
-
-       for (i = 0; i < number; ++i) {
-               if (! ReadOK(fd, rgb, sizeof(rgb))) {
-                       return TRUE;
-               }
-               buffer[CM_RED][i] = rgb[0] ;
-               buffer[CM_GREEN][i] = rgb[1] ;
-               buffer[CM_BLUE][i] = rgb[2] ;
-       }
-
-
-       return FALSE;
-}
-
-static int
-DoExtension(FILE *fd, int label, int *Transparent)
-{
-       static unsigned char     buf[256];
-
-       switch (label) {
-       case 0xf9:              /* Graphic Control Extension */
-               (void) GetDataBlock(fd, (unsigned char*) buf);
-               Gif89.disposal    = (buf[0] >> 2) & 0x7;
-               Gif89.inputFlag   = (buf[0] >> 1) & 0x1;
-               Gif89.delayTime   = LM_to_uint(buf[1],buf[2]);
-               if ((buf[0] & 0x1) != 0)
-                       *Transparent = buf[3];
-
-               while (GetDataBlock(fd, (unsigned char*) buf) != 0)
-                       ;
-               return FALSE;
-       default:
-               break;
-       }
-       while (GetDataBlock(fd, (unsigned char*) buf) != 0)
-               ;
-
-       return FALSE;
-}
-
-static int
-GetDataBlock_(FILE *fd, unsigned char *buf)
-{
-       unsigned char   count;
-
-       if (! ReadOK(fd,&count,1)) {
-               return -1;
-       }
-
-       ZeroDataBlock = count == 0;
-
-       if ((count != 0) && (! ReadOK(fd, buf, count))) {
-               return -1;
-       }
-
-       return count;
-}
-
-static int
-GetDataBlock(FILE *fd, unsigned char *buf)
-{
- int rv;
- int i;
-
- rv = GetDataBlock_(fd,buf);
- if (VERBOSE)
-  { printf("[GetDataBlock returning %d",rv);
-    if (rv > 0)
-     { printf(":");
-       for (i=0;i<rv;i++) printf(" %02x",buf[i]);
-     }
-    printf("]\n");
-  }
- return(rv);
-}
-
-static int
-GetCode_(FILE *fd, int code_size, int flag)
-{
-       static unsigned char    buf[280];
-       static int              curbit, lastbit, done, last_byte;
-       int                     i, j, ret;
-       unsigned char           count;
-
-       if (flag) {
-               curbit = 0;
-               lastbit = 0;
-               done = FALSE;
-               return 0;
-       }
-
-       if ( (curbit+code_size) >= lastbit) {
-               if (done) {
-                       if (curbit >= lastbit) {
-                                /* Oh well */
-                       }                        
-                       return -1;
-               }
-               buf[0] = buf[last_byte-2];
-               buf[1] = buf[last_byte-1];
-
-               if ((count = GetDataBlock(fd, &buf[2])) == 0)
-                       done = TRUE;
-
-               last_byte = 2 + count;
-               curbit = (curbit - lastbit) + 16;
-               lastbit = (2+count)*8 ;
-       }
-
-       ret = 0;
-       for (i = curbit, j = 0; j < code_size; ++i, ++j)
-               ret |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j;
-
-       curbit += code_size;
-       return ret;
-}
-
-static int
-GetCode(FILE *fd, int code_size, int flag)
-{
- int rv;
-
- rv = GetCode_(fd,code_size,flag);
- if (VERBOSE) printf("[GetCode(,%d,%d) returning %d]\n",code_size,flag,rv);
- return(rv);
-}
-
-static int
-LWZReadByte_(FILE *fd, int flag, int input_code_size)
-{
-       static int      fresh = FALSE;
-       int             code, incode;
-       static int      code_size, set_code_size;
-       static int      max_code, max_code_size;
-       static int      firstcode, oldcode;
-       static int      clear_code, end_code;
-       static int      table[2][(1<< MAX_LWZ_BITS)];
-       static int      stack[(1<<(MAX_LWZ_BITS))*2], *sp;
-       register int    i;
-
-       if (flag) {
-               set_code_size = input_code_size;
-               code_size = set_code_size+1;
-               clear_code = 1 << set_code_size ;
-               end_code = clear_code + 1;
-               max_code_size = 2*clear_code;
-               max_code = clear_code+2;
-
-               GetCode(fd, 0, TRUE);
-               
-               fresh = TRUE;
-
-               for (i = 0; i < clear_code; ++i) {
-                       table[0][i] = 0;
-                       table[1][i] = i;
-               }
-               for (; i < (1<<MAX_LWZ_BITS); ++i)
-                       table[0][i] = table[1][0] = 0;
-
-               sp = stack;
-
-               return 0;
-       } else if (fresh) {
-               fresh = FALSE;
-               do {
-                       firstcode = oldcode =
-                               GetCode(fd, code_size, FALSE);
-               } while (firstcode == clear_code);
-               return firstcode;
-       }
-
-       if (sp > stack)
-               return *--sp;
-
-       while ((code = GetCode(fd, code_size, FALSE)) >= 0) {
-               if (code == clear_code) {
-                       for (i = 0; i < clear_code; ++i) {
-                               table[0][i] = 0;
-                               table[1][i] = i;
-                       }
-                       for (; i < (1<<MAX_LWZ_BITS); ++i)
-                               table[0][i] = table[1][i] = 0;
-                       code_size = set_code_size+1;
-                       max_code_size = 2*clear_code;
-                       max_code = clear_code+2;
-                       sp = stack;
-                       firstcode = oldcode =
-                                       GetCode(fd, code_size, FALSE);
-                       return firstcode;
-               } else if (code == end_code) {
-                       int             count;
-                       unsigned char   buf[260];
-
-                       if (ZeroDataBlock)
-                               return -2;
-
-                       while ((count = GetDataBlock(fd, buf)) > 0)
-                               ;
-
-                       if (count != 0)
-                       return -2;
-               }
-
-               incode = code;
-
-               if (code >= max_code) {
-                       *sp++ = firstcode;
-                       code = oldcode;
-               }
-
-               while (code >= clear_code) {
-                       *sp++ = table[1][code];
-                       if (code == table[0][code]) {
-                               /* Oh well */
-                       }
-                       code = table[0][code];
-               }
-
-               *sp++ = firstcode = table[1][code];
-
-               if ((code = max_code) <(1<<MAX_LWZ_BITS)) {
-                       table[0][code] = oldcode;
-                       table[1][code] = firstcode;
-                       ++max_code;
-                       if ((max_code >= max_code_size) &&
-                               (max_code_size < (1<<MAX_LWZ_BITS))) {
-                               max_code_size *= 2;
-                               ++code_size;
-                       }
-               }
-
-               oldcode = incode;
-
-               if (sp > stack)
-                       return *--sp;
-       }
-       return code;
-}
-
-static int
-LWZReadByte(FILE *fd, int flag, int input_code_size)
-{
- int rv;
-
- rv = LWZReadByte_(fd,flag,input_code_size);
- if (VERBOSE) printf("[LWZReadByte(,%d,%d) returning %d]\n",flag,input_code_size,rv);
- return(rv);
-}
-
-static void
-ReadImage(gdImagePtr im, FILE *fd, int len, int height, unsigned char (*cmap)[256], int interlace, int ignore)
-{
-       unsigned char   c;      
-       int             v;
-       int             xpos = 0, ypos = 0, pass = 0;
-       int i;
-       /* Stash the color map into the image */
-       for (i=0; (i<gdMaxColors); i++) {
-               im->red[i] = cmap[CM_RED][i];	
-               im->green[i] = cmap[CM_GREEN][i];	
-               im->blue[i] = cmap[CM_BLUE][i];	
-               im->open[i] = 1;
-       }
-       /* Many (perhaps most) of these colors will remain marked open. */
-       im->colorsTotal = gdMaxColors;
-       /*
-       **  Initialize the Compression routines
-       */
-       if (! ReadOK(fd,&c,1)) {
-               return; 
-       }
-       if (LWZReadByte(fd, TRUE, c) < 0) {
-               return;
-       }
-
-       /*
-       **  If this is an "uninteresting picture" ignore it.
-       */
-       if (ignore) {
-               while (LWZReadByte(fd, FALSE, c) >= 0)
-                       ;
-               return;
-       }
-
-       while ((v = LWZReadByte(fd,FALSE,c)) >= 0 ) {
-               /* This how we recognize which colors are actually used. */
-               if (im->open[v]) {
-                       im->open[v] = 0;
-               }
-               gdImageSetPixel(im, xpos, ypos, v);
-               ++xpos;
-               if (xpos == len) {
-                       xpos = 0;
-                       if (interlace) {
-                               switch (pass) {
-                               case 0:
-                               case 1:
-                                       ypos += 8; break;
-                               case 2:
-                                       ypos += 4; break;
-                               case 3:
-                                       ypos += 2; break;
-                               }
-
-                               if (ypos >= height) {
-                                       ++pass;
-                                       switch (pass) {
-                                       case 1:
-                                               ypos = 4; break;
-                                       case 2:
-                                               ypos = 2; break;
-                                       case 3:
-                                               ypos = 1; break;
-                                       default:
-                                               goto fini;
-                                       }
-                               }
-                       } else {
-                               ++ypos;
-                       }
-               }
-               if (ypos >= height)
-                       break;
-       }
-
-fini:
-       if (LWZReadByte(fd,FALSE,c)>=0) {
-               /* Ignore extra */
-       }
-}
 
 void gdImageRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
 {

Modified: trunk/orca/packages/rrdtool-1.0.13/examples/Makefile.in
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/examples/Makefile.in	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/examples/Makefile.in	Sat Jul 13 21:08:21 2002
@@ -98,7 +98,7 @@
 
 DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
 
-TAR = tar
+TAR = gtar
 GZIP_ENV = --best
 all: all-redirect
 .SUFFIXES:

Modified: trunk/orca/packages/rrdtool-1.0.13/examples/piped-demo.pl.in
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/examples/piped-demo.pl.in	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/examples/piped-demo.pl.in	Sat Jul 13 21:08:21 2002
@@ -80,12 +80,12 @@
         "AREA:alpha#0022e9:Alpha",
         "STACK:beta#00b871:Beta",
         "STACK:calc#ff0091:Calc\\j",
-	"PRINT:alpha:AVERAGE:'Average Alpha\\: %1.2f %S'",
-	"PRINT:alpha:MIN:'Min Alpha\\: %1.2f %S'",
-	"PRINT:alpha:MAX:'Max Alpha\\: %1.2f %S'",
-	"GPRINT:calc:AVERAGE:'Average calc\\: %1.2f %S\\r'",
-	"GPRINT:calc:MIN:'Min calc\\: %1.2f %S'",
-	"GPRINT:calc:MAX:'Max calc\\: %1.2f %S'",
+	"PRINT:alpha:AVERAGE:'Average Alpha\\: %1.2lf %S'",
+	"PRINT:alpha:MIN:'Min Alpha\\: %1.2lf %S'",
+	"PRINT:alpha:MAX:'Max Alpha\\: %1.2lf %S'",
+	"GPRINT:calc:AVERAGE:'Average calc\\: %1.2lf %S\\r'",
+	"GPRINT:calc:MIN:'Min calc\\: %1.2lf %S'",
+	"GPRINT:calc:MAX:'Max calc\\: %1.2lf %S'",
         "VRULE:".($now-3600)."#008877:'60 Minutes ago'",
         "COMMENT:'\\s'",
         "COMMENT:'Graph created on: ".localtime(time())."\\c'";

Modified: trunk/orca/packages/rrdtool-1.0.13/examples/shared-demo.pl.in
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/examples/shared-demo.pl.in	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/examples/shared-demo.pl.in	Sat Jul 13 21:08:22 2002
@@ -128,19 +128,19 @@
           "DEF:epsilon=$RRD:e:AVERAGE",
           "CDEF:calc=alpha,beta,+,2,/,100,*,102,/",
           "AREA:alpha#0022e9:Short",
-          "GPRINT:calc:MAX:Max calc %1.2f",
+          "GPRINT:calc:MAX:Max calc %1.2lf",
           "STACK:beta#00b871:Demo Text",
-          "GPRINT:calc:AVERAGE:Average calc %1.2f",
+          "GPRINT:calc:AVERAGE:Average calc %1.2lf",
           "STACK:beta#0ad871:Demo Text 2",
           "LINE1:gamma#ff0000:Line 1",
           "LINE2:delta#888800:Line 2",
           "LINE3:calc#00ff44:Line 3",
           "LINE3:epsilon#000000:Line 4",
           "HRULE:1500#ff8800:Horizontal Line at 1500",
-          "PRINT:alpha:AVERAGE:Average Alpha %1.2f",
-          "PRINT:alpha:MIN:Min Alpha %1.2f",
-          "PRINT:alpha:MAX:Max Alpha %1.2f",
-          "GPRINT:calc:MIN:Min calc %1.2f",
+          "PRINT:alpha:AVERAGE:Average Alpha %1.2lf",
+          "PRINT:alpha:MIN:Min Alpha %1.2lf",
+          "PRINT:alpha:MAX:Max Alpha %1.2lf",
+          "GPRINT:calc:MIN:Min calc %1.2lf",
           "VRULE:".($now-3600)."#008877:60 Minutes ago",
           "VRULE:".($now-7200)."#008877:120 Minutes ago";
 

Modified: trunk/orca/packages/rrdtool-1.0.13/examples/cgi-demo.cgi.in
==============================================================================
--- trunk/orca/packages/rrdtool-1.0.13/examples/cgi-demo.cgi.in	(original)
+++ trunk/orca/packages/rrdtool-1.0.13/examples/cgi-demo.cgi.in	Sat Jul 13 21:08:22 2002
@@ -14,7 +14,7 @@
 <P><RRD::GRAPH cgi-demo1.gif 
 	    --lower-limit 0
 	    --start 'end-10h'
-	    --title "Graph in Localtime"
+	    --title "Graph in Localtime <RRD::TIME::NOW %c>"
             DEF:alpha=shared-demo.rrd:a:AVERAGE
             DEF:beta=shared-demo.rrd:b:AVERAGE
             AREA:alpha#0022e9:"Trees on Mars"




More information about the Orca-checkins mailing list