Index: collections/trunk/cic-hcap/bin/script/download-all-images.pl
===================================================================
--- collections/trunk/cic-hcap/bin/script/download-all-images.pl	(revision 14139)
+++ collections/trunk/cic-hcap/bin/script/download-all-images.pl	(revision 14139)
@@ -0,0 +1,62 @@
+BEGIN {
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+
+use strict;
+use util;
+
+
+my $source_directory = "Z:\\";
+my $target_directory = "C:\\mdewsnip\\CIC\\Images.new\\";
+
+
+sub main
+{
+    # Find all the files in the source directory
+    if (!opendir(DIR, $source_directory)) {
+	die "Error: Couldn't read directory $source_directory\n";
+    }
+    my @directory_files = readdir(DIR);
+    closedir(DIR);
+
+    foreach my $directory_file (@directory_files) {
+	next if ($directory_file eq "." || $directory_file eq "..");
+
+	my $directory_file_path = &util::filename_cat($source_directory, $directory_file);
+	print "$directory_file_path ";
+	if (-f $directory_file_path) {
+	    print "(File)\n";
+	}
+	else {
+	    print "(Directory)\n";
+	    my $images_revised_directory = &util::filename_cat($directory_file_path, "images REVISED");
+	    if (-e $images_revised_directory) {
+		&copy_directory_to_local_drive($images_revised_directory);
+	    }
+	}
+    }
+}
+
+
+sub copy_directory_to_local_drive
+{
+    my ($directory_file_path) = (@_);
+
+    my $destination_file_path = $directory_file_path;
+    my $source_directory_regexp = $source_directory;
+    $source_directory_regexp =~ s/\\/\\\\/g;
+    $destination_file_path =~ s/^$source_directory_regexp/$target_directory/;
+    print " Destination: $destination_file_path\n";
+
+    my $destination_directory_path = $destination_file_path;
+    $destination_directory_path =~ s/[^\\]+$//;
+    if (!-e $destination_directory_path) {
+        &util::mk_all_dir($destination_directory_path);
+    }
+
+    &util::cp_r($directory_file_path, $destination_directory_path);
+}
+
+
+main(@ARGV);
Index: collections/trunk/cic-hcap/bin/script/download-new-images.pl
===================================================================
--- collections/trunk/cic-hcap/bin/script/download-new-images.pl	(revision 14139)
+++ collections/trunk/cic-hcap/bin/script/download-new-images.pl	(revision 14139)
@@ -0,0 +1,92 @@
+BEGIN {
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+
+use strict;
+use util;
+
+
+my $source_directory = "Z:\\";
+my $target_directory = "C:\\mdewsnip\\CIC\\Images\\";
+
+
+sub main
+{
+    # Find all the files in the source directory
+    if (!opendir(DIR, $source_directory)) {
+	die "Error: Couldn't read directory $source_directory\n";
+    }
+    my @directory_files = readdir(DIR);
+    closedir(DIR);
+
+    foreach my $directory_file (@directory_files) {
+	next if ($directory_file eq "." || $directory_file eq "..");
+
+	open(LOG, ">>log.txt");
+
+	my $directory_file_path = &util::filename_cat($source_directory, $directory_file);
+	print LOG "$directory_file_path ";
+	if (-f $directory_file_path) {
+	    print LOG "(File)\n";
+	}
+	else {
+	    print LOG "(Directory)\n";
+	    my $images_revised_directory = &util::filename_cat($directory_file_path, "images REVISED");
+	    if (-e $images_revised_directory) {
+		&copy_directory_to_local_drive($images_revised_directory);
+	    }
+	}
+
+	close(LOG);
+    }
+}
+
+
+sub copy_directory_to_local_drive
+{
+    my ($source_directory_path) = (@_);
+
+    my $target_directory_path = $source_directory_path;
+    my $source_directory_regexp = $source_directory;
+    $source_directory_regexp =~ s/\\/\\\\/g;
+    $target_directory_path =~ s/^$source_directory_regexp/$target_directory/;
+    if (!-e $target_directory_path) {
+	print LOG " Creating new folder $target_directory_path!\n";
+        &util::mk_all_dir($target_directory_path);
+    }
+
+    # Find all the files in this directory
+    if (!opendir(DIR, $source_directory_path)) {
+	die "Error: Couldn't read directory $source_directory_path\n";
+    }
+    my @source_directory_files = readdir(DIR);
+    closedir(DIR);
+
+    foreach my $source_directory_file (@source_directory_files) {
+	next if ($source_directory_file eq "." || $source_directory_file eq ".." || $source_directory_file eq "Thumbs.db");
+
+	print LOG "  $source_directory_file ";
+
+	my $source_directory_file_path = $source_directory_path . "\\" . $source_directory_file;
+	my $target_directory_file_path = $target_directory_path . "\\" . $source_directory_file; 
+
+	# File doesn't exist locally, so is new
+	if (!-f $target_directory_file_path) {
+	    print LOG "(New file, copying...)\n";
+	    &util::cp($source_directory_file_path, $target_directory_file_path);
+	}
+	# File exists locally but file has changed
+	elsif ((-s $source_directory_file_path) != (-s $target_directory_file_path)) {
+	    print LOG "(File changed, copying...)\n";
+	    &util::cp($source_directory_file_path, $target_directory_file_path);
+	}
+	# File is unchanged, so ignore
+	else {
+	    print LOG "(Unchanged)\n";
+	}
+    }
+}
+
+
+main(@ARGV);
Index: collections/trunk/cic-hcap/bin/windows/perl/lib/DBI.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/lib/DBI.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/lib/DBI.pm	(revision 14139)
@@ -0,0 +1,7223 @@
+# $Id$
+# vim: ts=8:sw=4
+#
+# Copyright (c) 1994-2004  Tim Bunce  Ireland
+#
+# See COPYRIGHT section in pod text below for usage and distribution rights.
+#
+
+require 5.006_00;
+
+BEGIN {
+$DBI::VERSION = "1.48"; # ==> ALSO update the version in the pod text below!
+}
+
+=head1 NAME
+
+DBI - Database independent interface for Perl
+
+=head1 SYNOPSIS
+
+  use DBI;
+
+  @driver_names = DBI->available_drivers;
+  @data_sources = DBI->data_sources($driver_name, \%attr);
+
+  $dbh = DBI->connect($data_source, $username, $auth, \%attr);
+
+  $rv  = $dbh->do($statement);
+  $rv  = $dbh->do($statement, \%attr);
+  $rv  = $dbh->do($statement, \%attr, @bind_values);
+
+  $ary_ref  = $dbh->selectall_arrayref($statement);
+  $hash_ref = $dbh->selectall_hashref($statement, $key_field);
+
+  $ary_ref  = $dbh->selectcol_arrayref($statement);
+  $ary_ref  = $dbh->selectcol_arrayref($statement, \%attr);
+
+  @row_ary  = $dbh->selectrow_array($statement);
+  $ary_ref  = $dbh->selectrow_arrayref($statement);
+  $hash_ref = $dbh->selectrow_hashref($statement);
+
+  $sth = $dbh->prepare($statement);
+  $sth = $dbh->prepare_cached($statement);
+
+  $rc = $sth->bind_param($p_num, $bind_value);
+  $rc = $sth->bind_param($p_num, $bind_value, $bind_type);
+  $rc = $sth->bind_param($p_num, $bind_value, \%attr);
+
+  $rv = $sth->execute;
+  $rv = $sth->execute(@bind_values);
+  $rv = $sth->execute_array(\%attr, ...);
+
+  $rc = $sth->bind_col($col_num, \$col_variable);
+  $rc = $sth->bind_columns(@list_of_refs_to_vars_to_bind);
+
+  @row_ary  = $sth->fetchrow_array;
+  $ary_ref  = $sth->fetchrow_arrayref;
+  $hash_ref = $sth->fetchrow_hashref;
+
+  $ary_ref  = $sth->fetchall_arrayref;
+  $ary_ref  = $sth->fetchall_arrayref( $slice, $max_rows );
+
+  $hash_ref = $sth->fetchall_hashref( $key_field );
+
+  $rv  = $sth->rows;
+
+  $rc  = $dbh->begin_work;
+  $rc  = $dbh->commit;
+  $rc  = $dbh->rollback;
+
+  $quoted_string = $dbh->quote($string);
+
+  $rc  = $h->err;
+  $str = $h->errstr;
+  $rv  = $h->state;
+
+  $rc  = $dbh->disconnect;
+
+I<The synopsis above only lists the major methods and parameters.>
+
+
+=head2 GETTING HELP
+
+If you have questions about DBI, or DBD driver modules, you can get
+help from the I<dbi-users@perl.org> mailing list.  You can get help
+on subscribing and using the list by emailing I<dbi-users-help@perl.org>.
+
+(To help you make the best use of the dbi-users mailing list,
+and any other lists or forums you may use, I I<strongly>
+recommend that you read "How To Ask Questions The Smart Way"
+by Eric Raymond: L<http://www.catb.org/~esr/faqs/smart-questions.html>)
+
+The DBI home page at L<http://dbi.perl.org/> is always worth a visit
+and includes an FAQ and links to other resources.
+
+Before asking any questions, reread this document, consult the
+archives and read the DBI FAQ. The archives are listed
+at the end of this document and on the DBI home page.
+An FAQ is installed as a L<DBI::FAQ> module so
+you can read it by executing C<perldoc DBI::FAQ>.
+However the DBI::FAQ module is currently (2004) outdated relative
+to the online FAQ on the DBI home page.
+
+This document often uses terms like I<references>, I<objects>,
+I<methods>.  If you're not familar with those terms then it would
+be a good idea to read at least the following perl manuals first:
+L<perlreftut>, L<perldsc>, L<perllol>, and L<perlboot>.
+
+Please note that Tim Bunce does not maintain the mailing lists or the
+web page (generous volunteers do that).  So please don't send mail
+directly to him; he just doesn't have the time to answer questions
+personally. The I<dbi-users> mailing list has lots of experienced
+people who should be able to help you if you need it. If you do email
+Tim he's very likely to just forward it to the mailing list.
+
+=head2 NOTES
+
+This is the DBI specification that corresponds to the DBI version 1.48.
+
+The DBI is evolving at a steady pace, so it's good to check that
+you have the latest copy.
+
+The significant user-visible changes in each release are documented
+in the L<DBI::Changes> module so you can read them by executing
+C<perldoc DBI::Changes>.
+
+Some DBI changes require changes in the drivers, but the drivers
+can take some time to catch up. Newer versions of the DBI have
+added features that may not yet be supported by the drivers you
+use.  Talk to the authors of your drivers if you need a new feature
+that's not yet supported.
+
+Features added after DBI 1.21 (February 2002) are marked in the
+text with the version number of the DBI release they first appeared in.
+
+Extensions to the DBI API often use the C<DBIx::*> namespace.
+See L</Naming Conventions and Name Space>. DBI extension modules
+can be found at L<http://search.cpan.org/search?mode=module&query=DBIx>.
+And all modules related to the DBI can be found at
+L<http://search.cpan.org/search?query=DBI&mode=all>.
+
+=cut
+
+# The POD text continues at the end of the file.
+
+
+package DBI;
+
+use Carp();
+use DynaLoader ();
+use Exporter ();
+
+BEGIN {
+@ISA = qw(Exporter DynaLoader);
+
+# Make some utility functions available if asked for
+@EXPORT    = ();		    # we export nothing by default
+@EXPORT_OK = qw(%DBI %DBI_methods hash); # also populated by export_ok_tags:
+%EXPORT_TAGS = (
+   sql_types => [ qw(
+	SQL_GUID
+	SQL_WLONGVARCHAR
+	SQL_WVARCHAR
+	SQL_WCHAR
+	SQL_BIT
+	SQL_TINYINT
+	SQL_LONGVARBINARY
+	SQL_VARBINARY
+	SQL_BINARY
+	SQL_LONGVARCHAR
+	SQL_UNKNOWN_TYPE
+	SQL_ALL_TYPES
+	SQL_CHAR
+	SQL_NUMERIC
+	SQL_DECIMAL
+	SQL_INTEGER
+	SQL_SMALLINT
+	SQL_FLOAT
+	SQL_REAL
+	SQL_DOUBLE
+	SQL_DATETIME
+	SQL_DATE
+	SQL_INTERVAL
+	SQL_TIME
+	SQL_TIMESTAMP
+	SQL_VARCHAR
+	SQL_BOOLEAN
+	SQL_UDT
+	SQL_UDT_LOCATOR
+	SQL_ROW
+	SQL_REF
+	SQL_BLOB
+	SQL_BLOB_LOCATOR
+	SQL_CLOB
+	SQL_CLOB_LOCATOR
+	SQL_ARRAY
+	SQL_ARRAY_LOCATOR
+	SQL_MULTISET
+	SQL_MULTISET_LOCATOR
+	SQL_TYPE_DATE
+	SQL_TYPE_TIME
+	SQL_TYPE_TIMESTAMP
+	SQL_TYPE_TIME_WITH_TIMEZONE
+	SQL_TYPE_TIMESTAMP_WITH_TIMEZONE
+	SQL_INTERVAL_YEAR
+	SQL_INTERVAL_MONTH
+	SQL_INTERVAL_DAY
+	SQL_INTERVAL_HOUR
+	SQL_INTERVAL_MINUTE
+	SQL_INTERVAL_SECOND
+	SQL_INTERVAL_YEAR_TO_MONTH
+	SQL_INTERVAL_DAY_TO_HOUR
+	SQL_INTERVAL_DAY_TO_MINUTE
+	SQL_INTERVAL_DAY_TO_SECOND
+	SQL_INTERVAL_HOUR_TO_MINUTE
+	SQL_INTERVAL_HOUR_TO_SECOND
+	SQL_INTERVAL_MINUTE_TO_SECOND
+   ) ],
+   sql_cursor_types => [ qw(
+	 SQL_CURSOR_FORWARD_ONLY
+	 SQL_CURSOR_KEYSET_DRIVEN
+	 SQL_CURSOR_DYNAMIC
+	 SQL_CURSOR_STATIC
+	 SQL_CURSOR_TYPE_DEFAULT
+   ) ], # for ODBC cursor types
+   utils     => [ qw(
+	neat neat_list $neat_maxlen dump_results looks_like_number
+	data_string_diff data_string_desc data_diff
+   ) ],
+   profile   => [ qw(
+	dbi_profile dbi_profile_merge dbi_time
+   ) ], # notionally "in" DBI::Profile and normally imported from there
+);
+
+$DBI::dbi_debug = 0;
+$DBI::neat_maxlen = 400;
+
+# If you get an error here like "Can't find loadable object ..."
+# then you haven't installed the DBI correctly. Read the README
+# then install it again.
+if ( $ENV{DBI_PUREPERL} ) {
+    eval { bootstrap DBI } if       $ENV{DBI_PUREPERL} == 1;
+    require DBI::PurePerl  if $@ or $ENV{DBI_PUREPERL} >= 2;
+    $DBI::PurePerl ||= 0; # just to silence "only used once" warnings
+}
+else {
+    bootstrap DBI;
+}
+
+$EXPORT_TAGS{preparse_flags} = [ grep { /^DBIpp_\w\w_/ } keys %{__PACKAGE__."::"} ];
+
+Exporter::export_ok_tags(keys %EXPORT_TAGS);
+
+}
+
+# Alias some handle methods to also be DBI class methods
+for (qw(trace_msg set_err parse_trace_flag parse_trace_flags)) {
+  no strict;
+  *$_ = \&{"DBD::_::common::$_"};
+}
+
+use strict;
+
+DBI->trace(split /=/, $ENV{DBI_TRACE}, 2) if $ENV{DBI_TRACE};
+
+$DBI::connect_via = "connect";
+
+# check if user wants a persistent database connection ( Apache + mod_perl )
+if ($INC{'Apache/DBI.pm'} && $ENV{MOD_PERL}) {
+    $DBI::connect_via = "Apache::DBI::connect";
+    DBI->trace_msg("DBI connect via $DBI::connect_via in $INC{'Apache/DBI.pm'}\n");
+}
+
+%DBI::installed_drh = ();  # maps driver names to installed driver handles
+
+# Setup special DBI dynamic variables. See DBI::var::FETCH for details.
+# These are dynamically associated with the last handle used.
+tie $DBI::err,    'DBI::var', '*err';    # special case: referenced via IHA list
+tie $DBI::state,  'DBI::var', '"state';  # special case: referenced via IHA list
+tie $DBI::lasth,  'DBI::var', '!lasth';  # special case: return boolean
+tie $DBI::errstr, 'DBI::var', '&errstr'; # call &errstr in last used pkg
+tie $DBI::rows,   'DBI::var', '&rows';   # call &rows   in last used pkg
+sub DBI::var::TIESCALAR{ my $var = $_[1]; bless \$var, 'DBI::var'; }
+sub DBI::var::STORE    { Carp::croak("Can't modify \$DBI::${$_[0]} special variable") }
+
+{   # used to catch DBI->{Attrib} mistake
+    sub DBI::DBI_tie::TIEHASH { bless {} }
+    sub DBI::DBI_tie::STORE   { Carp::carp("DBI->{$_[1]} is invalid syntax (you probably want \$h->{$_[1]})");}
+    *DBI::DBI_tie::FETCH = \&DBI::DBI_tie::STORE;
+}
+tie %DBI::DBI => 'DBI::DBI_tie';
+
+# --- Driver Specific Prefix Registry ---
+
+my $dbd_prefix_registry = {
+  ad_      => { class => 'DBD::AnyData',	},
+  ado_     => { class => 'DBD::ADO',		},
+  amzn_    => { class => 'DBD::Amazon',		},
+  best_    => { class => 'DBD::BestWins',	},
+  csv_     => { class => 'DBD::CSV',		},
+  db2_     => { class => 'DBD::DB2',		},
+  dbi_     => { class => 'DBI',			},
+  dbm_     => { class => 'DBD::DBM',		},
+  df_      => { class => 'DBD::DF',		},
+  f_       => { class => 'DBD::File',		},
+  file_    => { class => 'DBD::TextFile',	},
+  ib_      => { class => 'DBD::InterBase',	},
+  ing_     => { class => 'DBD::Ingres',		},
+  ix_      => { class => 'DBD::Informix',	},
+  jdbc_    => { class => 'DBD::JDBC',		},
+  msql_    => { class => 'DBD::mSQL',		},
+  mysql_   => { class => 'DBD::mysql',		},
+  mx_      => { class => 'DBD::Multiplex',	},
+  nullp_   => { class => 'DBD::NullP',		},
+  odbc_    => { class => 'DBD::ODBC',		},
+  ora_     => { class => 'DBD::Oracle',		},
+  pg_      => { class => 'DBD::Pg',		},
+  proxy_   => { class => 'DBD::Proxy',		},
+  rdb_     => { class => 'DBD::RDB',		},
+  sapdb_   => { class => 'DBD::SAP_DB',		},
+  solid_   => { class => 'DBD::Solid',		},
+  sponge_  => { class => 'DBD::Sponge',		},
+  sql_     => { class => 'SQL::Statement',	},
+  syb_     => { class => 'DBD::Sybase',		},
+  tdat_    => { class => 'DBD::Teradata',	},
+  tmpl_    => { class => 'DBD::Template',	},
+  tmplss_  => { class => 'DBD::TemplateSS',	},
+  tuber_   => { class => 'DBD::Tuber',		},
+  uni_     => { class => 'DBD::Unify',		},
+  xbase_   => { class => 'DBD::XBase',		},
+  xl_      => { class => 'DBD::Excel',		},
+  yaswi_   => { class => 'DBD::Yaswi',		},
+};
+
+sub dump_dbd_registry {
+    require Data::Dumper;
+    local $Data::Dumper::Sortkeys=1;
+    local $Data::Dumper::Indent=1;
+    print Data::Dumper->Dump([$dbd_prefix_registry], [qw($dbd_prefix_registry)]);
+}
+
+# --- Dynamically create the DBI Standard Interface
+
+my $keeperr = { O=>0x0004 };
+
+%DBI::DBI_methods = ( # Define the DBI interface methods per class:
+
+    common => {		# Interface methods common to all DBI handle classes
+	'DESTROY'	=> $keeperr,
+	'CLEAR'  	=> $keeperr,
+	'EXISTS' 	=> $keeperr,
+	'FETCH'		=> { O=>0x0404 },
+	'FIRSTKEY'	=> $keeperr,
+	'NEXTKEY'	=> $keeperr,
+	'STORE'		=> { O=>0x0418 | 0x4 },
+	_not_impl	=> undef,
+	can		=> { O=>0x0100 }, # special case, see dispatch
+	debug 	 	=> { U =>[1,2,'[$debug_level]'],	O=>0x0004 }, # old name for trace
+	dump_handle 	=> { U =>[1,3,'[$message [, $level]]'],	O=>0x0004 },
+	err		=> $keeperr,
+	errstr		=> $keeperr,
+	state		=> $keeperr,
+	func	   	=> { O=>0x0006	},
+	parse_trace_flag   => { U =>[2,2,'$name'],	O=>0x0404, T=>8 },
+	parse_trace_flags  => { U =>[2,2,'$flags'],	O=>0x0404, T=>8 },
+	private_data	=> { U =>[1,1],			O=>0x0004 },
+	set_err		=> { U =>[3,6,'$err, $errmsg [, $state, $method, $rv]'], O=>0x0010 },
+	trace		=> { U =>[1,3,'[$trace_level, [$filename]]'],	O=>0x0004 },
+	trace_msg	=> { U =>[2,3,'$message_text [, $min_level ]' ],	O=>0x0004, T=>8 },
+	swap_inner_handle => { U =>[2,3,'$h [, $allow_reparent ]'] },
+    },
+    dr => {		# Database Driver Interface
+	'connect'  =>	{ U =>[1,5,'[$db [,$user [,$passwd [,\%attr]]]]'], H=>3 },
+	'connect_cached'=>{U=>[1,5,'[$db [,$user [,$passwd [,\%attr]]]]'], H=>3 },
+	'disconnect_all'=>{ U =>[1,1], O=>0x0800 },
+	data_sources => { U =>[1,2,'[\%attr]' ], O=>0x0800 },
+	default_user => { U =>[3,4,'$user, $pass [, \%attr]' ] },
+    },
+    db => {		# Database Session Class Interface
+	data_sources	=> { U =>[1,2,'[\%attr]' ], O=>0x0200 },
+	take_imp_data	=> { U =>[1,1], },
+	clone   	=> { U =>[1,1,''] },
+	connected   	=> { O=>0x0100 },
+	begin_work   	=> { U =>[1,2,'[ \%attr ]'], O=>0x0400 },
+	commit     	=> { U =>[1,1], O=>0x0480|0x0800 },
+	rollback   	=> { U =>[1,1], O=>0x0480|0x0800 },
+	'do'       	=> { U =>[2,0,'$statement [, \%attr [, @bind_params ] ]'], O=>0x3200 },
+	last_insert_id	=> { U =>[5,6,'$catalog, $schema, $table_name, $field_name [, \%attr ]'], O=>0x2800 },
+	preparse    	=> {  }, # XXX
+	prepare    	=> { U =>[2,3,'$statement [, \%attr]'],                    O=>0x2200 },
+	prepare_cached	=> { U =>[2,4,'$statement [, \%attr [, $if_active ] ]'],   O=>0x2200 },
+	selectrow_array	=> { U =>[2,0,'$statement [, \%attr [, @bind_params ] ]'], O=>0x2000 },
+	selectrow_arrayref=>{U =>[2,0,'$statement [, \%attr [, @bind_params ] ]'], O=>0x2000 },
+	selectrow_hashref=>{ U =>[2,0,'$statement [, \%attr [, @bind_params ] ]'], O=>0x2000 },
+	selectall_arrayref=>{U =>[2,0,'$statement [, \%attr [, @bind_params ] ]'], O=>0x2000 },
+	selectall_hashref=>{ U =>[3,0,'$statement, $keyfield [, \%attr [, @bind_params ] ]'], O=>0x2000 },
+	selectcol_arrayref=>{U =>[2,0,'$statement [, \%attr [, @bind_params ] ]'], O=>0x2000 },
+	ping       	=> { U =>[1,1], O=>0x0404 },
+	disconnect 	=> { U =>[1,1], O=>0x0400|0x0800 },
+	quote      	=> { U =>[2,3, '$string [, $data_type ]' ], O=>0x0430 },
+	quote_identifier=> { U =>[2,6, '$name [, ...] [, \%attr ]' ],    O=>0x0430 },
+	rows       	=> $keeperr,
+
+	tables          => { U =>[1,6,'$catalog, $schema, $table, $type [, \%attr ]' ], O=>0x2200 },
+	table_info      => { U =>[1,6,'$catalog, $schema, $table, $type [, \%attr ]' ],	O=>0x2200|0x0800 },
+	column_info     => { U =>[5,6,'$catalog, $schema, $table, $column [, \%attr ]'],O=>0x2200|0x0800 },
+	primary_key_info=> { U =>[4,5,'$catalog, $schema, $table [, \%attr ]' ],	O=>0x2200|0x0800 },
+	primary_key     => { U =>[4,5,'$catalog, $schema, $table [, \%attr ]' ],	O=>0x2200 },
+	foreign_key_info=> { U =>[7,8,'$pk_catalog, $pk_schema, $pk_table, $fk_catalog, $fk_schema, $fk_table [, \%attr ]' ], O=>0x2200|0x0800 },
+	type_info_all	=> { U =>[1,1], O=>0x2200|0x0800 },
+	type_info	=> { U =>[1,2,'$data_type'], O=>0x2200 },
+	get_info	=> { U =>[2,2,'$info_type'], O=>0x2200|0x0800 },
+    },
+    st => {		# Statement Class Interface
+	bind_col	=> { U =>[3,4,'$column, \\$var [, \%attr]'] },
+	bind_columns	=> { U =>[2,0,'\\$var1 [, \\$var2, ...]'] },
+	bind_param	=> { U =>[3,4,'$parameter, $var [, \%attr]'] },
+	bind_param_inout=> { U =>[4,5,'$parameter, \\$var, $maxlen, [, \%attr]'] },
+	execute		=> { U =>[1,0,'[@args]'], O=>0x1040 },
+
+	bind_param_array  => { U =>[3,4,'$parameter, $var [, \%attr]'] },
+	bind_param_inout_array => { U =>[4,5,'$parameter, \\@var, $maxlen, [, \%attr]'] },
+	execute_array     => { U =>[2,0,'\\%attribs [, @args]'],         O=>0x1040 },
+	execute_for_fetch => { U =>[2,3,'$fetch_sub [, $tuple_status]'], O=>0x1040 },
+
+	fetch    	  => undef, # alias for fetchrow_arrayref
+	fetchrow_arrayref => undef,
+	fetchrow_hashref  => undef,
+	fetchrow_array    => undef,
+	fetchrow   	  => undef, # old alias for fetchrow_array
+
+	fetchall_arrayref => { U =>[1,3, '[ $slice [, $max_rows]]'] },
+	fetchall_hashref  => { U =>[2,2,'$key_field'] },
+
+	blob_read  =>	{ U =>[4,5,'$field, $offset, $len [, \\$buf [, $bufoffset]]'] },
+	blob_copy_to_file => { U =>[3,3,'$field, $filename_or_handleref'] },
+	dump_results => { U =>[1,5,'$maxfieldlen, $linesep, $fieldsep, $filehandle'] },
+	more_results => { U =>[1,1] },
+	finish     => 	{ U =>[1,1] },
+	cancel     => 	{ U =>[1,1], O=>0x0800 },
+	rows       =>	$keeperr,
+
+	_get_fbav	=> undef,
+	_set_fbav	=> { T=>6 },
+    },
+);
+
+while ( my ($class, $meths) = each %DBI::DBI_methods ) {
+    while ( my ($method, $info) = each %$meths ) {
+	my $fullmeth = "DBI::${class}::$method";
+	DBI->_install_method($fullmeth, 'DBI.pm', $info);
+    }
+}
+
+{
+    package DBI::common;
+    @DBI::dr::ISA = ('DBI::common');
+    @DBI::db::ISA = ('DBI::common');
+    @DBI::st::ISA = ('DBI::common');
+}
+
+# End of init code
+
+
+END {
+    return unless defined &DBI::trace_msg; # return unless bootstrap'd ok
+    local ($!,$?);
+    DBI->trace_msg("    -- DBI::END\n", 2);
+    # Let drivers know why we are calling disconnect_all:
+    $DBI::PERL_ENDING = $DBI::PERL_ENDING = 1;	# avoid typo warning
+    DBI->disconnect_all() if %DBI::installed_drh;
+}
+
+
+sub CLONE {
+    my $olddbis = $DBI::_dbistate;
+    _clone_dbis() unless $DBI::PurePerl; # clone the DBIS structure
+    DBI->trace_msg(sprintf "CLONE DBI for new thread %s\n",
+	$DBI::PurePerl ? "" : sprintf("(dbis %x -> %x)",$olddbis, $DBI::_dbistate));
+    while ( my ($driver, $drh) = each %DBI::installed_drh) {
+	no strict 'refs';
+	next if defined &{"DBD::${driver}::CLONE"};
+	warn("$driver has no driver CLONE() function so is unsafe threaded\n");
+    }
+    %DBI::installed_drh = ();	# clear loaded drivers so they have a chance to reinitialize
+}
+
+sub parse_dsn {
+    my ($class, $dsn) = @_;
+    $dsn =~ s/^(dbi):(\w*?)(?:\((.*?)\))?://i or return;
+    my ($scheme, $driver, $attr, $attr_hash) = (lc($1), $2, $3);
+    $driver ||= $ENV{DBI_DRIVER} || '';
+    $attr_hash = { split /\s*=>?\s*|\s*,\s*/, $attr, -1 } if $attr;
+    return ($scheme, $driver, $attr, $attr_hash, $dsn);
+}
+
+
+# --- The DBI->connect Front Door methods
+
+sub connect_cached {
+    # For library code using connect_cached() with mod_perl
+    # we redirect those calls to Apache::DBI::connect() as well
+    my ($class, $dsn, $user, $pass, $attr) = @_;
+    # XXX modifies callers data!
+    ($attr ||= {})->{dbi_connect_method} =
+	($DBI::connect_via eq "Apache::DBI::connect")
+	    ? 'Apache::DBI::connect' : 'connect_cached';
+    return $class->connect($dsn, $user, $pass, $attr);
+}
+
+sub connect {
+    my $class = shift;
+    my ($dsn, $user, $pass, $attr, $old_driver) = my @orig_args = @_;
+    my $driver;
+
+    if ($attr and !ref($attr)) { # switch $old_driver<->$attr if called in old style
+	Carp::carp("DBI->connect using 'old-style' syntax is deprecated and will be an error in future versions");
+        ($old_driver, $attr) = ($attr, $old_driver);
+    }
+
+    my $connect_meth = $attr->{dbi_connect_method};
+    $connect_meth ||= $DBI::connect_via;	# fallback to default
+
+    $dsn ||= $ENV{DBI_DSN} || $ENV{DBI_DBNAME} || '' unless $old_driver;
+
+    if ($DBI::dbi_debug) {
+	local $^W = 0;
+	pop @_ if $connect_meth ne 'connect';
+	my @args = @_; $args[2] = '****'; # hide password
+	DBI->trace_msg("    -> $class->$connect_meth(".join(", ",@args).")\n");
+    }
+    Carp::croak('Usage: $class->connect([$dsn [,$user [,$passwd [,\%attr]]]])')
+	if (ref $old_driver or ($attr and not ref $attr) or ref $pass);
+
+    # extract dbi:driver prefix from $dsn into $1
+    $dsn =~ s/^dbi:(\w*?)(?:\((.*?)\))?://i
+			or '' =~ /()/; # ensure $1 etc are empty if match fails
+    my $driver_attrib_spec = $2 || '';
+
+    # Set $driver. Old style driver, if specified, overrides new dsn style.
+    $driver = $old_driver || $1 || $ENV{DBI_DRIVER}
+	or Carp::croak("Can't connect to data source $dsn, no database driver specified "
+		."and DBI_DSN env var not set");
+
+    if ($ENV{DBI_AUTOPROXY} && $driver ne 'Proxy' && $driver ne 'Sponge' && $driver ne 'Switch') {
+	my $dbi_autoproxy = $ENV{DBI_AUTOPROXY};
+	my $proxy = 'Proxy';
+	if ($dbi_autoproxy =~ s/^dbi:(\w*?)(?:\((.*?)\))?://i) {
+	    $proxy = $1;
+	    my $attr_spec = $2 || '';
+	    $driver_attrib_spec = ($driver_attrib_spec) ? "$driver_attrib_spec,$attr_spec" : $attr_spec;
+	}
+	$dsn = "$dbi_autoproxy;dsn=dbi:$driver:$dsn";
+	$driver = $proxy;
+	DBI->trace_msg("       DBI_AUTOPROXY: dbi:$driver($driver_attrib_spec):$dsn\n");
+    }
+
+    my %attributes;	# take a copy we can delete from
+    if ($old_driver) {
+	%attributes = %$attr if $attr;
+    }
+    else {		# new-style connect so new default semantics
+	%attributes = (
+	    PrintError => 1,
+	    AutoCommit => 1,
+	    ref $attr           ? %$attr : (),
+	    # attributes in DSN take precedence over \%attr connect parameter
+	    $driver_attrib_spec ? (split /\s*=>?\s*|\s*,\s*/, $driver_attrib_spec, -1) : (),
+	);
+    }
+    $attr = \%attributes; # now set $attr to refer to our local copy
+
+    my $drh = $DBI::installed_drh{$driver} || $class->install_driver($driver)
+	or die "panic: $class->install_driver($driver) failed";
+
+    # attributes in DSN take precedence over \%attr connect parameter
+    $user =        $attr->{Username} if defined $attr->{Username};
+    $pass = delete $attr->{Password} if defined $attr->{Password};
+
+    ($user, $pass) = $drh->default_user($user, $pass, $attr)
+	if !(defined $user && defined $pass);
+
+    $attr->{Username} = $user;	# store username as attribute
+
+    my $connect_closure = sub {
+	my ($old_dbh, $override_attr) = @_;
+
+	my $attr = {
+	    # copy so we can edit them each time we're called
+	    %attributes,
+	    # merge in modified attr in %$old_dbh, this should also copy in
+	    # the dbi_connect_closure attribute so we can reconnect again.
+	    %{ $override_attr || {} },
+	};
+	#warn "connect_closure: ".Data::Dumper::Dumper([\%attributes, $override_attr]);
+
+	my $dbh;
+	unless ($dbh = $drh->$connect_meth($dsn, $user, $pass, $attr)) {
+	    $user = '' if !defined $user;
+	    $dsn = '' if !defined $dsn;
+	    # $drh->errstr isn't safe here because $dbh->DESTROY may not have
+	    # been called yet and so the dbh errstr would not have been copied
+	    # up to the drh errstr. Certainly true for connect_cached!
+	    my $errstr = $DBI::errstr;
+	    $errstr = '(no error string)' if !defined $errstr;
+	    my $msg = "$class connect('$dsn','$user',...) failed: $errstr";
+	    DBI->trace_msg("       $msg\n");
+	    # XXX HandleWarn
+	    unless ($attr->{HandleError} && $attr->{HandleError}->($msg, $drh, $dbh)) {
+		Carp::croak($msg) if $attr->{RaiseError};
+		Carp::carp ($msg) if $attr->{PrintError};
+	    }
+	    $! = 0; # for the daft people who do DBI->connect(...) || die "$!";
+	    return $dbh; # normally undef, but HandleError could change it
+	}
+
+	# handle basic RootClass subclassing:
+	my $rebless_class = $attr->{RootClass} || ($class ne 'DBI' ? $class : '');
+	if ($rebless_class) {
+	    no strict 'refs';
+	    if ($attr->{RootClass}) {	# explicit attribute (rather than static call)
+		delete $attr->{RootClass};
+		DBI::_load_class($rebless_class, 0);
+	    }
+	    unless (@{"$rebless_class\::db::ISA"} && @{"$rebless_class\::st::ISA"}) {
+		Carp::carp("DBI subclasses '$rebless_class\::db' and ::st are not setup, RootClass ignored");
+		$rebless_class = undef;
+		$class = 'DBI';
+	    }
+	    else {
+		$dbh->{RootClass} = $rebless_class; # $dbh->STORE called via plain DBI::db
+		DBI::_set_isa([$rebless_class], 'DBI');     # sets up both '::db' and '::st'
+		DBI::_rebless($dbh, $rebless_class);        # appends '::db'
+	    }
+	}
+
+	if (%$attr) {
+
+	    DBI::_rebless_dbtype_subclass($dbh, $rebless_class||$class, delete $attr->{DbTypeSubclass}, $attr)
+		if $attr->{DbTypeSubclass};
+
+	    my $a;
+	    foreach $a (qw(RaiseError PrintError AutoCommit)) { # do these first
+		next unless  exists $attr->{$a};
+		$dbh->{$a} = delete $attr->{$a};
+	    }
+	    foreach $a (keys %$attr) {
+		eval { $dbh->{$a} = $attr->{$a} } or $@ && warn $@;
+	    }
+	}
+
+	# if we've been subclassed then let the subclass know that we're connected
+	$dbh->connected($dsn, $user, $pass, $attr) if ref $dbh ne 'DBI::db';
+
+	# if the caller has provided a callback then call it
+	# especially useful with connect_cached() XXX not enabled/tested/documented
+	if (0 and $dbh and my $oc = $dbh->{OnConnect}) { # XXX
+	    $oc->($dbh, $dsn, $user, $pass, $attr) if ref $oc eq 'CODE';
+	}
+
+	DBI->trace_msg("    <- connect= $dbh\n") if $DBI::dbi_debug;
+
+	return $dbh;
+    };
+
+    my $dbh = &$connect_closure(undef, undef);
+
+    $dbh->{dbi_connect_closure} = $connect_closure if $dbh;
+
+    return $dbh;
+}
+
+
+sub disconnect_all {
+    keys %DBI::installed_drh; # reset iterator
+    while ( my ($name, $drh) = each %DBI::installed_drh ) {
+	$drh->disconnect_all() if ref $drh;
+    }
+}
+
+
+sub disconnect {		# a regular beginners bug
+    Carp::croak("DBI->disconnect is not a DBI method (read the DBI manual)");
+}
+
+
+sub install_driver {		# croaks on failure
+    my $class = shift;
+    my($driver, $attr) = @_;
+    my $drh;
+
+    $driver ||= $ENV{DBI_DRIVER} || '';
+
+    # allow driver to be specified as a 'dbi:driver:' string
+    $driver = $1 if $driver =~ s/^DBI:(.*?)://i;
+
+    Carp::croak("usage: $class->install_driver(\$driver [, \%attr])")
+		unless ($driver and @_<=3);
+
+    # already installed
+    return $drh if $drh = $DBI::installed_drh{$driver};
+
+    $class->trace_msg("    -> $class->install_driver($driver"
+			.") for $^O perl=$] pid=$$ ruid=$< euid=$>\n")
+	if $DBI::dbi_debug;
+
+    # --- load the code
+    my $driver_class = "DBD::$driver";
+    eval qq{package			# hide from PAUSE
+		DBI::_firesafe;		# just in case
+	    require $driver_class;	# load the driver
+    };
+    if ($@) {
+	my $err = $@;
+	my $advice = "";
+	if ($err =~ /Can't find loadable object/) {
+	    $advice = "Perhaps DBD::$driver was statically linked into a new perl binary."
+		 ."\nIn which case you need to use that new perl binary."
+		 ."\nOr perhaps only the .pm file was installed but not the shared object file."
+	}
+	elsif ($err =~ /Can't locate.*?DBD\/$driver\.pm in \@INC/) {
+	    my @drv = $class->available_drivers(1);
+	    $advice = "Perhaps the DBD::$driver perl module hasn't been fully installed,\n"
+		     ."or perhaps the capitalisation of '$driver' isn't right.\n"
+		     ."Available drivers: ".join(", ", @drv).".";
+	}
+	elsif ($err =~ /Can't load .*? for module DBD::/) {
+	    $advice = "Perhaps a required shared library or dll isn't installed where expected";
+	}
+	elsif ($err =~ /Can't locate .*? in \@INC/) {
+	    $advice = "Perhaps a module that DBD::$driver requires hasn't been fully installed";
+	}
+	Carp::croak("install_driver($driver) failed: $err$advice\n");
+    }
+    if ($DBI::dbi_debug) {
+	no strict 'refs';
+	(my $driver_file = $driver_class) =~ s/::/\//g;
+	my $dbd_ver = ${"$driver_class\::VERSION"} || "undef";
+	$class->trace_msg("       install_driver: $driver_class version $dbd_ver"
+		." loaded from $INC{qq($driver_file.pm)}\n");
+    }
+
+    # --- do some behind-the-scenes checks and setups on the driver
+    $class->setup_driver($driver_class);
+
+    # --- run the driver function
+    $drh = eval { $driver_class->driver($attr || {}) };
+    unless ($drh && ref $drh && !$@) {
+	my $advice = "";
+	# catch people on case in-sensitive systems using the wrong case
+	$advice = "\nPerhaps the capitalisation of DBD '$driver' isn't right."
+		if $@ =~ /locate object method/;
+	Carp::croak("$driver_class initialisation failed: $@$advice");
+    }
+
+    $DBI::installed_drh{$driver} = $drh;
+    $class->trace_msg("    <- install_driver= $drh\n") if $DBI::dbi_debug;
+    $drh;
+}
+
+*driver = \&install_driver;	# currently an alias, may change
+
+
+sub setup_driver {
+    my ($class, $driver_class) = @_;
+    my $type;
+    foreach $type (qw(dr db st)){
+	my $class = $driver_class."::$type";
+	no strict 'refs';
+	push @{"${class}::ISA"},     "DBD::_::$type"
+	    unless UNIVERSAL::isa($class, "DBD::_::$type");
+	my $mem_class = "DBD::_mem::$type";
+	push @{"${class}_mem::ISA"}, $mem_class
+	    unless UNIVERSAL::isa("${class}_mem", $mem_class)
+	    or $DBI::PurePerl;
+    }
+}
+
+
+sub _rebless {
+    my $dbh = shift;
+    my ($outer, $inner) = DBI::_handles($dbh);
+    my $class = shift(@_).'::db';
+    bless $inner => $class;
+    bless $outer => $class; # outer last for return
+}
+
+
+sub _set_isa {
+    my ($classes, $topclass) = @_;
+    my $trace = DBI->trace_msg("       _set_isa([@$classes])\n");
+    foreach my $suffix ('::db','::st') {
+	my $previous = $topclass || 'DBI'; # trees are rooted here
+	foreach my $class (@$classes) {
+	    my $base_class = $previous.$suffix;
+	    my $sub_class  = $class.$suffix;
+	    my $sub_class_isa  = "${sub_class}::ISA";
+	    no strict 'refs';
+	    if (@$sub_class_isa) {
+		DBI->trace_msg("       $sub_class_isa skipped (already set to @$sub_class_isa)\n")
+		    if $trace;
+	    }
+	    else {
+		@$sub_class_isa = ($base_class) unless @$sub_class_isa;
+		DBI->trace_msg("       $sub_class_isa = $base_class\n")
+		    if $trace;
+	    }
+	    $previous = $class;
+	}
+    }
+}
+
+
+sub _rebless_dbtype_subclass {
+    my ($dbh, $rootclass, $DbTypeSubclass, $attr) = @_;
+    # determine the db type names for class hierarchy
+    my @hierarchy = DBI::_dbtype_names($dbh, $DbTypeSubclass, $attr);
+    # add the rootclass prefix to each ('DBI::' or 'MyDBI::' etc)
+    $_ = $rootclass.'::'.$_ foreach (@hierarchy);
+    # load the modules from the 'top down'
+    DBI::_load_class($_, 1) foreach (reverse @hierarchy);
+    # setup class hierarchy if needed, does both '::db' and '::st'
+    DBI::_set_isa(\@hierarchy, $rootclass);
+    # finally bless the handle into the subclass
+    DBI::_rebless($dbh, $hierarchy[0]);
+}
+
+
+sub _dbtype_names { # list dbtypes for hierarchy, ie Informix=>ADO=>ODBC
+    my ($dbh, $DbTypeSubclass, $attr) = @_;
+
+    if ($DbTypeSubclass && $DbTypeSubclass ne '1' && ref $DbTypeSubclass ne 'CODE') {
+	# treat $DbTypeSubclass as a comma separated list of names
+	my @dbtypes = split /\s*,\s*/, $DbTypeSubclass;
+	$dbh->trace_msg("    DbTypeSubclass($DbTypeSubclass)=@dbtypes (explicit)\n");
+	return @dbtypes;
+    }
+
+    # XXX will call $dbh->get_info(17) (=SQL_DBMS_NAME) in future?
+
+    my $driver = $dbh->{Driver}->{Name};
+    if ( $driver eq 'Proxy' ) {
+        # XXX Looking into the internals of DBD::Proxy is questionable!
+        ($driver) = $dbh->{proxy_client}->{application} =~ /^DBI:(.+?):/i
+		or die "Can't determine driver name from proxy";
+    }
+
+    my @dbtypes = (ucfirst($driver));
+    if ($driver eq 'ODBC' || $driver eq 'ADO') {
+	# XXX will move these out and make extensible later:
+	my $_dbtype_name_regexp = 'Oracle'; # eg 'Oracle|Foo|Bar'
+	my %_dbtype_name_map = (
+	     'Microsoft SQL Server'	=> 'MSSQL',
+	     'SQL Server'		=> 'Sybase',
+	     'Adaptive Server Anywhere'	=> 'ASAny',
+	     'ADABAS D'			=> 'AdabasD',
+	);
+
+        my $name;
+	$name = $dbh->func(17, 'GetInfo') # SQL_DBMS_NAME
+		if $driver eq 'ODBC';
+	$name = $dbh->{ado_conn}->Properties->Item('DBMS Name')->Value
+		if $driver eq 'ADO';
+	die "Can't determine driver name! ($DBI::errstr)\n"
+		unless $name;
+
+	my $dbtype;
+        if ($_dbtype_name_map{$name}) {
+            $dbtype = $_dbtype_name_map{$name};
+        }
+	else {
+	    if ($name =~ /($_dbtype_name_regexp)/) {
+		$dbtype = lc($1);
+	    }
+	    else { # generic mangling for other names:
+		$dbtype = lc($name);
+	    }
+	    $dbtype =~ s/\b(\w)/\U$1/g;
+	    $dbtype =~ s/\W+/_/g;
+	}
+	# add ODBC 'behind' ADO
+	push    @dbtypes, 'ODBC' if $driver eq 'ADO';
+	# add discovered dbtype in front of ADO/ODBC
+	unshift @dbtypes, $dbtype;
+    }
+    @dbtypes = &$DbTypeSubclass($dbh, \@dbtypes)
+	if (ref $DbTypeSubclass eq 'CODE');
+    $dbh->trace_msg("    DbTypeSubclass($DbTypeSubclass)=@dbtypes\n");
+    return @dbtypes;
+}
+
+sub _load_class {
+    my ($load_class, $missing_ok) = @_;
+    DBI->trace_msg("    _load_class($load_class, $missing_ok)\n", 2);
+    no strict 'refs';
+    return 1 if @{"$load_class\::ISA"};	# already loaded/exists
+    (my $module = $load_class) =~ s!::!/!g;
+    DBI->trace_msg("    _load_class require $module\n", 2);
+    eval { require "$module.pm"; };
+    return 1 unless $@;
+    return 0 if $missing_ok && $@ =~ /^Can't locate \Q$module.pm\E/;
+    die $@;
+}
+
+
+sub init_rootclass {	# deprecated
+    return 1;
+}
+
+
+*internal = \&DBD::Switch::dr::driver;
+
+
+sub available_drivers {
+    my($quiet) = @_;
+    my(@drivers, $d, $f);
+    local(*DBI::DIR, $@);
+    my(%seen_dir, %seen_dbd);
+    my $haveFileSpec = eval { require File::Spec };
+    foreach $d (@INC){
+	chomp($d); # Perl 5 beta 3 bug in #!./perl -Ilib from Test::Harness
+	my $dbd_dir =
+	    ($haveFileSpec ? File::Spec->catdir($d, 'DBD') : "$d/DBD");
+	next unless -d $dbd_dir;
+	next if $seen_dir{$d};
+	$seen_dir{$d} = 1;
+	# XXX we have a problem here with case insensitive file systems
+	# XXX since we can't tell what case must be used when loading.
+	opendir(DBI::DIR, $dbd_dir) || Carp::carp "opendir $dbd_dir: $!\n";
+	foreach $f (readdir(DBI::DIR)){
+	    next unless $f =~ s/\.pm$//;
+	    next if $f eq 'NullP';
+	    if ($seen_dbd{$f}){
+		Carp::carp "DBD::$f in $d is hidden by DBD::$f in $seen_dbd{$f}\n"
+		    unless $quiet;
+            } else {
+		push(@drivers, $f);
+	    }
+	    $seen_dbd{$f} = $d;
+	}
+	closedir(DBI::DIR);
+    }
+
+    # "return sort @drivers" will not DWIM in scalar context.
+    return wantarray ? sort @drivers : @drivers;
+}
+
+sub installed_versions {
+    my ($class, $quiet) = @_;
+    my %error;
+    my %version = ( DBI => $DBI::VERSION );
+    $version{"DBI::PurePerl"} = $DBI::PurePerl::VERSION
+	if $DBI::PurePerl;
+    for my $driver ($class->available_drivers($quiet)) {
+	next if $DBI::PurePerl && grep { -d "$_/auto/DBD/$driver" } @INC;
+	my $drh = eval {
+	    local $SIG{__WARN__} = sub {};
+	    $class->install_driver($driver);
+	};
+	($error{"DBD::$driver"}=$@),next if $@;
+	no strict 'refs';
+	my $vers = ${"DBD::$driver" . '::VERSION'};
+	$version{"DBD::$driver"} = $vers || '?';
+    }
+    if (wantarray) {
+       return map { m/^DBD::(\w+)/ ? ($1) : () } sort keys %version;
+    }
+    if (!defined wantarray) {	# void context
+	require Config;		# add more detail
+	$version{OS}   = "$^O\t($Config::Config{osvers})";
+	$version{Perl} = "$]\t($Config::Config{archname})";
+	$version{$_}   = (($error{$_} =~ s/ \(\@INC.*//s),$error{$_})
+	    for keys %error;
+	printf "  %-16s: %s\n",$_,$version{$_}
+	    for reverse sort keys %version;
+    }
+    return \%version;
+}
+
+
+sub data_sources {
+    my ($class, $driver, @other) = @_;
+    my $drh = $class->install_driver($driver);
+    my @ds = $drh->data_sources(@other);
+    return @ds;
+}
+
+
+sub neat_list {
+    my ($listref, $maxlen, $sep) = @_;
+    $maxlen = 0 unless defined $maxlen;	# 0 == use internal default
+    $sep = ", " unless defined $sep;
+    join($sep, map { neat($_,$maxlen) } @$listref);
+}
+
+
+sub dump_results {	# also aliased as a method in DBD::_::st
+    my ($sth, $maxlen, $lsep, $fsep, $fh) = @_;
+    return 0 unless $sth;
+    $maxlen ||= 35;
+    $lsep   ||= "\n";
+    $fh ||= \*STDOUT;
+    my $rows = 0;
+    my $ref;
+    while($ref = $sth->fetch) {
+	print $fh $lsep if $rows++ and $lsep;
+	my $str = neat_list($ref,$maxlen,$fsep);
+	print $fh $str;	# done on two lines to avoid 5.003 errors
+    }
+    print $fh "\n$rows rows".($DBI::err ? " ($DBI::err: $DBI::errstr)" : "")."\n";
+    $rows;
+}
+
+
+sub data_diff {
+    my ($a, $b, $logical) = @_;
+
+    my $diff   = data_string_diff($a, $b);
+    return "" if $logical and !$diff;
+
+    my $a_desc = data_string_desc($a);
+    my $b_desc = data_string_desc($b);
+    return "" if !$diff and $a_desc eq $b_desc;
+
+    $diff ||= "Strings contain the same sequence of characters"
+    	if length($a);
+    $diff .= "\n" if $diff;
+    return "a: $a_desc\nb: $b_desc\n$diff";
+}
+    
+
+sub data_string_diff {
+    # Compares 'logical' characters, not bytes, so a latin1 string and an
+    # an equivalent unicode string will compare as equal even though their
+    # byte encodings are different.
+    my ($a, $b) = @_;
+    unless (defined $a and defined $b) {             # one undef
+	return ""
+		if !defined $a and !defined $b;
+	return "String a is undef, string b has ".length($b)." characters"
+		if !defined $a;
+	return "String b is undef, string a has ".length($a)." characters"
+		if !defined $b;
+    }
+
+    require utf8;
+    # hack to cater for perl 5.6
+    *utf8::is_utf8 = sub { (DBI::neat(shift)=~/^"/) } unless defined &utf8::is_utf8;
+
+    my @a_chars = (utf8::is_utf8($a)) ? unpack("U*", $a) : unpack("C*", $a);
+    my @b_chars = (utf8::is_utf8($b)) ? unpack("U*", $b) : unpack("C*", $b);
+    my $i = 0;
+    while (@a_chars && @b_chars) {
+	++$i, shift(@a_chars), shift(@b_chars), next
+	    if $a_chars[0] == $b_chars[0];# compare ordinal values
+	my @desc = map {
+	    $_ > 255 ?                    # if wide character...
+	      sprintf("\\x{%04X}", $_) :  # \x{...}
+	      chr($_) =~ /[[:cntrl:]]/ ?  # else if control character ...
+	      sprintf("\\x%02X", $_) :    # \x..
+	      chr($_)                     # else as themselves
+	} ($a_chars[0], $b_chars[0]);
+	# highlight probable double-encoding?
+        foreach my $c ( @desc ) {
+	    next unless $c =~ m/\\x\{08(..)}/;
+	    $c .= "='" .chr(hex($1)) ."'"
+	}
+	return sprintf "Strings differ at index $i: a[$i]=$desc[0], b[$i]=$desc[1]";
+    }
+    return "String a truncated after $i characters" if @b_chars;
+    return "String b truncated after $i characters" if @a_chars;
+    return "";
+}
+
+
+sub data_string_desc {	# describe a data string
+    my ($a) = @_;
+    require bytes;
+    require utf8;
+
+    # hacks to cater for perl 5.6
+    *utf8::is_utf8 = sub { (DBI::neat(shift)=~/^"/) } unless defined &utf8::is_utf8;
+    *utf8::valid   = sub {                        1 } unless defined &utf8::valid;
+
+    # Give sufficient info to help diagnose at least these kinds of situations:
+    # - valid UTF8 byte sequence but UTF8 flag not set
+    #   (might be ascii so also need to check for hibit to make it worthwhile)
+    # - UTF8 flag set but invalid UTF8 byte sequence
+    # could do better here, but this'll do for now
+    my $utf8 = sprintf "UTF8 %s%s", 
+	utf8::is_utf8($a) ? "on" : "off",
+	utf8::valid($a||'') ? "" : " but INVALID encoding";
+    return "$utf8, undef" unless defined $a;
+    my $is_ascii = $a =~ m/^[\000-\177]*$/;
+    return sprintf "%s, %s, %d characters %d bytes",
+	$utf8, $is_ascii ? "ASCII" : "non-ASCII",
+	length($a), bytes::length($a);
+}
+
+
+sub connect_test_perf {
+    my($class, $dsn,$dbuser,$dbpass, $attr) = @_;
+	Carp::croak("connect_test_perf needs hash ref as fourth arg") unless ref $attr;
+    # these are non standard attributes just for this special method
+    my $loops ||= $attr->{dbi_loops} || 5;
+    my $par   ||= $attr->{dbi_par}   || 1;	# parallelism
+    my $verb  ||= $attr->{dbi_verb}  || 1;
+    print "$dsn: testing $loops sets of $par connections:\n";
+    require Benchmark;
+    require "FileHandle.pm";	# don't let toke.c create empty FileHandle package
+    $| = 1;
+    my $t0 = new Benchmark;		# not currently used
+    my $drh = $class->install_driver($dsn) or Carp::croak("Can't install $dsn driver\n");
+    my $t1 = new Benchmark;
+    my $loop;
+    for $loop (1..$loops) {
+	my @cons;
+	print "Connecting... " if $verb;
+	for (1..$par) {
+	    print "$_ ";
+	    push @cons, ($drh->connect($dsn,$dbuser,$dbpass)
+		    or Carp::croak("Can't connect # $_: $DBI::errstr\n"));
+	}
+	print "\nDisconnecting...\n" if $verb;
+	for (@cons) {
+	    $_->disconnect or warn "bad disconnect $DBI::errstr"
+	}
+    }
+    my $t2 = new Benchmark;
+    my $td = Benchmark::timediff($t2, $t1);
+    printf "Made %2d connections in %s\n", $loops*$par, Benchmark::timestr($td);
+	print "\n";
+    return $td;
+}
+
+
+# Help people doing DBI->errstr, might even document it one day
+# XXX probably best moved to cheaper XS code
+sub err    { $DBI::err    }
+sub errstr { $DBI::errstr }
+
+
+# --- Private Internal Function for Creating New DBI Handles
+
+sub _new_handle {
+    my ($class, $parent, $attr, $imp_data, $imp_class) = @_;
+
+    Carp::croak('Usage: DBI::_new_handle'
+	    .'($class_name, parent_handle, \%attr, $imp_data)'."\n"
+	    .'got: ('.join(", ",$class, $parent, $attr, $imp_data).")\n")
+	unless (@_ == 5	and (!$parent or ref $parent)
+			and ref $attr eq 'HASH'
+			and $imp_class);
+
+    $attr->{ImplementorClass} = $imp_class
+	or Carp::croak("_new_handle($class): 'ImplementorClass' attribute not given");
+
+    DBI->trace_msg("    New $class (for $imp_class, parent=$parent, id=".($imp_data||'').")\n")
+	if $DBI::dbi_debug >= 3;
+
+    # This is how we create a DBI style Object:
+    my (%hash, $i, $h);
+    $i = tie    %hash, $class, $attr;  # ref to inner hash (for driver)
+    $h = bless \%hash, $class;         # ref to outer hash (for application)
+    # The above tie and bless may migrate down into _setup_handle()...
+    # Now add magic so DBI method dispatch works
+    DBI::_setup_handle($h, $imp_class, $parent, $imp_data);
+
+    return $h unless wantarray;
+    ($h, $i);
+}
+# XXX minimum constructors for the tie's (alias to XS version)
+sub DBI::st::TIEHASH { bless $_[1] => $_[0] };
+*DBI::dr::TIEHASH = \&DBI::st::TIEHASH;
+*DBI::db::TIEHASH = \&DBI::st::TIEHASH;
+
+
+# These three special constructors are called by the drivers
+# The way they are called is likely to change.
+
+my $profile;
+
+sub _new_drh {	# called by DBD::<drivername>::driver()
+    my ($class, $initial_attr, $imp_data) = @_;
+    # Provide default storage for State,Err and Errstr.
+    # Note that these are shared by all child handles by default! XXX
+    # State must be undef to get automatic faking in DBI::var::FETCH
+    my ($h_state_store, $h_err_store, $h_errstr_store) = (undef, 0, '');
+    my $attr = {
+	# these attributes get copied down to child handles by default
+	'State'		=> \$h_state_store,  # Holder for DBI::state
+	'Err'		=> \$h_err_store,    # Holder for DBI::err
+	'Errstr'	=> \$h_errstr_store, # Holder for DBI::errstr
+	'TraceLevel' 	=> 0,
+	FetchHashKeyName=> 'NAME',
+	%$initial_attr,
+    };
+    my ($h, $i) = _new_handle('DBI::dr', '', $attr, $imp_data, $class);
+
+    # XXX DBI_PROFILE unless DBI::PurePerl because for some reason
+    # it kills the t/zz_*_pp.t tests (they silently exit early)
+    if ($ENV{DBI_PROFILE} && !$DBI::PurePerl) {
+	# The profile object created here when the first driver is loaded
+	# is shared by all drivers so we end up with just one set of profile
+	# data and thus the 'total time in DBI' is really the true total.
+	if (!$profile) {	# first time
+	    $h->{Profile} = $ENV{DBI_PROFILE};
+	    $profile = $h->{Profile};
+	}
+	else {
+	    $h->{Profile} = $profile;
+	}
+    }
+    return $h unless wantarray;
+    ($h, $i);
+}
+
+sub _new_dbh {	# called by DBD::<drivername>::dr::connect()
+    my ($drh, $attr, $imp_data) = @_;
+    my $imp_class = $drh->{ImplementorClass}
+	or Carp::croak("DBI _new_dbh: $drh has no ImplementorClass");
+    substr($imp_class,-4,4) = '::db';
+    my $app_class = ref $drh;
+    substr($app_class,-4,4) = '::db';
+    $attr->{Err}    ||= \my $err;
+    $attr->{Errstr} ||= \my $errstr;
+    $attr->{State}  ||= \my $state;
+    _new_handle($app_class, $drh, $attr, $imp_data, $imp_class);
+}
+
+sub _new_sth {	# called by DBD::<drivername>::db::prepare)
+    my ($dbh, $attr, $imp_data) = @_;
+    my $imp_class = $dbh->{ImplementorClass}
+	or Carp::croak("DBI _new_sth: $dbh has no ImplementorClass");
+    substr($imp_class,-4,4) = '::st';
+    my $app_class = ref $dbh;
+    substr($app_class,-4,4) = '::st';
+    _new_handle($app_class, $dbh, $attr, $imp_data, $imp_class);
+}
+
+
+# end of DBI package
+
+
+
+# --------------------------------------------------------------------
+# === The internal DBI Switch pseudo 'driver' class ===
+
+{   package	# hide from PAUSE
+	DBD::Switch::dr;
+    DBI->setup_driver('DBD::Switch');	# sets up @ISA
+
+    $DBD::Switch::dr::imp_data_size = 0;
+    $DBD::Switch::dr::imp_data_size = 0;	# avoid typo warning
+    my $drh;
+
+    sub driver {
+	return $drh if $drh;	# a package global
+
+	my $inner;
+	($drh, $inner) = DBI::_new_drh('DBD::Switch::dr', {
+		'Name'    => 'Switch',
+		'Version' => $DBI::VERSION,
+		'Attribution' => "DBI $DBI::VERSION by Tim Bunce",
+	    });
+	Carp::croak("DBD::Switch init failed!") unless ($drh && $inner);
+	return $drh;
+    }
+    sub CLONE {
+	undef $drh;
+    }
+
+    sub FETCH {
+	my($drh, $key) = @_;
+	return DBI->trace if $key eq 'DebugDispatch';
+	return undef if $key eq 'DebugLog';	# not worth fetching, sorry
+	return $drh->DBD::_::dr::FETCH($key);
+	undef;
+    }
+    sub STORE {
+	my($drh, $key, $value) = @_;
+	if ($key eq 'DebugDispatch') {
+	    DBI->trace($value);
+	} elsif ($key eq 'DebugLog') {
+	    DBI->trace(-1, $value);
+	} else {
+	    $drh->DBD::_::dr::STORE($key, $value);
+	}
+    }
+}
+
+
+# --------------------------------------------------------------------
+# === OPTIONAL MINIMAL BASE CLASSES FOR DBI SUBCLASSES ===
+
+# We only define default methods for harmless functions.
+# We don't, for example, define a DBD::_::st::prepare()
+
+{   package		# hide from PAUSE
+	DBD::_::common; # ====== Common base class methods ======
+    use strict;
+
+    # methods common to all handle types:
+
+    sub _not_impl {
+	my ($h, $method) = @_;
+	$h->trace_msg("Driver does not implement the $method method.\n");
+	return;	# empty list / undef
+    }
+
+    # generic TIEHASH default methods:
+    sub FIRSTKEY { }
+    sub NEXTKEY  { }
+    sub EXISTS   { defined($_[0]->FETCH($_[1])) } # XXX undef?
+    sub CLEAR    { Carp::carp "Can't CLEAR $_[0] (DBI)" }
+
+    *dump_handle = \&DBI::dump_handle;
+
+    sub install_method {
+	# special class method called directly by apps and/or drivers
+	# to install new methods into the DBI dispatcher
+	# DBD::Foo::db->install_method("foo_mumble", { usage => [...], options => '...' });
+	my ($class, $method, $attr) = @_;
+	Carp::croak("Class '$class' must begin with DBD:: and end with ::db or ::st")
+	    unless $class =~ /^DBD::(\w+)::(dr|db|st)$/;
+	my ($driver, $subtype) = ($1, $2);
+	Carp::croak("invalid method name '$method'")
+	    unless $method =~ m/^([a-z]+_)\w+$/;
+	my $prefix = $1;
+	my $reg_info = $dbd_prefix_registry->{$prefix};
+	Carp::croak("method name prefix '$prefix' is not registered") unless $reg_info;
+	my %attr = %{$attr||{}}; # copy so we can edit
+	# XXX reformat $attr as needed for _install_method
+	my ($caller_pkg, $filename, $line) = caller;
+	DBI->_install_method("DBI::${subtype}::$method", "$filename at line $line", \%attr);
+    }
+
+    sub parse_trace_flags {
+	my ($h, $spec) = @_;
+	my $level = 0;
+	my $flags = 0;
+	my @unknown;
+	for my $word (split /\s*[|&,]\s*/, $spec) {
+	    if (DBI::looks_like_number($word) && $word <= 0xF && $word >= 0) {
+		$level = $word;
+	    } elsif ($word eq 'ALL') {
+		$flags = 0x7FFFFFFF; # XXX last bit causes negative headaches
+		last;
+	    } elsif (my $flag = $h->parse_trace_flag($word)) {
+		$flags |= $flag;
+	    }
+	    else {
+		push @unknown, $word;
+	    }
+	}
+	if (@unknown && (ref $h ? $h->FETCH('Warn') : 1)) {
+	    Carp::carp("$h->parse_trace_flags($spec) ignored unknown trace flags: ".
+		join(" ", map { DBI::neat($_) } @unknown));
+	}
+	$flags |= $level;
+	return $flags;
+    }
+
+    sub parse_trace_flag {
+	my ($h, $name) = @_;
+	#      0xddDDDDrL (driver, DBI, reserved, Level)
+	return 0x00000100 if $name eq 'SQL';
+	return;
+    }
+
+}
+
+
+{   package		# hide from PAUSE
+	DBD::_::dr;	# ====== DRIVER ======
+    @DBD::_::dr::ISA = qw(DBD::_::common);
+    use strict;
+
+    sub default_user {
+	my ($drh, $user, $pass, $attr) = @_;
+	$user = $ENV{DBI_USER} unless defined $user;
+	$pass = $ENV{DBI_PASS} unless defined $pass;
+	return ($user, $pass);
+    }
+
+    sub connect { # normally overridden, but a handy default
+	my ($drh, $dsn, $user, $auth) = @_;
+	my ($this) = DBI::_new_dbh($drh, {
+	    'Name' => $dsn,
+	});
+	# XXX debatable as there's no "server side" here
+	# (and now many uses would trigger warnings on DESTROY)
+	# $this->STORE(Active => 1);
+	$this;
+    }
+
+
+    sub connect_cached {
+	my $drh = shift;
+	my ($dsn, $user, $auth, $attr)= @_;
+
+	# Needs support at dbh level to clear cache before complaining about
+	# active children. The XS template code does this. Drivers not using
+	# the template must handle clearing the cache themselves.
+	my $cache = $drh->FETCH('CachedKids');
+	$drh->STORE('CachedKids', $cache = {}) unless $cache;
+
+	my @attr_keys = $attr ? sort keys %$attr : ();
+	my $key = do { local $^W; # silence undef warnings
+	    join "~~", $dsn, $user||'', $auth||'', $attr ? (@attr_keys,@{$attr}{@attr_keys}) : ()
+	};
+	my $dbh = $cache->{$key};
+	if ($dbh && $dbh->FETCH('Active') && eval { $dbh->ping }) {
+	    # XXX warn if BegunWork?
+	    # XXX warn if $dbh->FETCH('AutoCommit') != $attr->{AutoCommit} ?
+	    # but that's just one (bad) case of a more general issue.
+	    return $dbh;
+	}
+	$dbh = $drh->connect(@_);
+	$cache->{$key} = $dbh;	# replace prev entry, even if connect failed
+	return $dbh;
+    }
+
+}
+
+
+{   package		# hide from PAUSE
+	DBD::_::db;	# ====== DATABASE ======
+    @DBD::_::db::ISA = qw(DBD::_::common);
+    use strict;
+
+    sub clone {
+	my ($old_dbh, $attr) = @_;
+	my $closure = $old_dbh->{dbi_connect_closure} or return;
+	unless ($attr) {
+	    # copy attributes visible in the attribute cache
+	    keys %$old_dbh;	# reset iterator
+	    while ( my ($k, $v) = each %$old_dbh ) {
+		# ignore non-code refs, i.e., caches, handles, Err etc
+		next if ref $v && ref $v ne 'CODE'; # HandleError etc
+		$attr->{$k} = $v;
+	    }
+	    # explicitly set attributes which are unlikely to be in the
+	    # attribute cache, i.e., boolean's and some others
+	    $attr->{$_} = $old_dbh->FETCH($_) for (qw(
+		AutoCommit ChopBlanks InactiveDestroy
+		LongTruncOk PrintError PrintWarn Profile RaiseError
+		ShowErrorStatement TaintIn TaintOut
+	    ));
+	}
+	# use Data::Dumper; warn Dumper([$old_dbh, $attr]);
+	my $new_dbh = &$closure($old_dbh, $attr);
+	unless ($new_dbh) {
+	    # need to copy err/errstr from driver back into $old_dbh
+	    my $drh = $old_dbh->{Driver};
+	    return $old_dbh->set_err($drh->err, $drh->errstr, $drh->state);
+	}
+	return $new_dbh;
+    }
+
+    sub quote_identifier {
+	my ($dbh, @id) = @_;
+	my $attr = (@id > 3 && ref($id[-1])) ? pop @id : undef;
+
+	my $info = $dbh->{dbi_quote_identifier_cache} ||= [
+	    $dbh->get_info(29)  || '"',	# SQL_IDENTIFIER_QUOTE_CHAR
+	    $dbh->get_info(41)  || '.',	# SQL_CATALOG_NAME_SEPARATOR
+	    $dbh->get_info(114) ||   1,	# SQL_CATALOG_LOCATION
+	];
+
+	my $quote = $info->[0];
+	foreach (@id) {			# quote the elements
+	    next unless defined;
+	    s/$quote/$quote$quote/g;	# escape embedded quotes
+	    $_ = qq{$quote$_$quote};
+	}
+
+	# strip out catalog if present for special handling
+	my $catalog = (@id >= 3) ? shift @id : undef;
+
+	# join the dots, ignoring any null/undef elements (ie schema)
+	my $quoted_id = join '.', grep { defined } @id;
+
+	if ($catalog) {			# add catalog correctly
+	    $quoted_id = ($info->[2] == 2)	# SQL_CL_END
+		    ? $quoted_id . $info->[1] . $catalog
+		    : $catalog   . $info->[1] . $quoted_id;
+	}
+	return $quoted_id;
+    }
+
+    sub quote {
+	my ($dbh, $str, $data_type) = @_;
+
+	return "NULL" unless defined $str;
+	unless ($data_type) {
+	    $str =~ s/'/''/g;		# ISO SQL2
+	    return "'$str'";
+	}
+
+	my $dbi_literal_quote_cache = $dbh->{'dbi_literal_quote_cache'} ||= [ {} , {} ];
+	my ($prefixes, $suffixes) = @$dbi_literal_quote_cache;
+
+	my $lp = $prefixes->{$data_type};
+	my $ls = $suffixes->{$data_type};
+
+	if ( ! defined $lp || ! defined $ls ) {
+	    my $ti = $dbh->type_info($data_type);
+	    $lp = $prefixes->{$data_type} = $ti ? $ti->{LITERAL_PREFIX} || "" : "'";
+	    $ls = $suffixes->{$data_type} = $ti ? $ti->{LITERAL_SUFFIX} || "" : "'";
+	}
+	return $str unless $lp || $ls; # no quoting required
+
+	# XXX don't know what the standard says about escaping
+	# in the 'general case' (where $lp != "'").
+	# So we just do this and hope:
+	$str =~ s/$lp/$lp$lp/g
+		if $lp && $lp eq $ls && ($lp eq "'" || $lp eq '"');
+	return "$lp$str$ls";
+    }
+
+    sub rows { -1 }	# here so $DBI::rows 'works' after using $dbh
+
+    sub do {
+	my($dbh, $statement, $attr, @params) = @_;
+	my $sth = $dbh->prepare($statement, $attr) or return undef;
+	$sth->execute(@params) or return undef;
+	my $rows = $sth->rows;
+	($rows == 0) ? "0E0" : $rows;
+    }
+
+    sub _do_selectrow {
+	my ($method, $dbh, $stmt, $attr, @bind) = @_;
+	my $sth = ((ref $stmt) ? $stmt : $dbh->prepare($stmt, $attr))
+	    or return;
+	$sth->execute(@bind)
+	    or return;
+	my $row = $sth->$method()
+	    and $sth->finish;
+	return $row;
+    }
+
+    sub selectrow_hashref {  return _do_selectrow('fetchrow_hashref',  @_); }
+
+    # XXX selectrow_array/ref also have C implementations in Driver.xst
+    sub selectrow_arrayref { return _do_selectrow('fetchrow_arrayref', @_); }
+    sub selectrow_array {
+	my $row = _do_selectrow('fetchrow_arrayref', @_) or return;
+	return $row->[0] unless wantarray;
+	return @$row;
+    }
+
+    # XXX selectall_arrayref also has C implementation in Driver.xst
+    # which fallsback to this if a slice is given
+    sub selectall_arrayref {
+	my ($dbh, $stmt, $attr, @bind) = @_;
+	my $sth = (ref $stmt) ? $stmt : $dbh->prepare($stmt, $attr)
+	    or return;
+	$sth->execute(@bind) || return;
+	my $slice = $attr->{Slice}; # typically undef, else hash or array ref
+	if (!$slice and $slice=$attr->{Columns}) {
+	    if (ref $slice eq 'ARRAY') { # map col idx to perl array idx
+		$slice = [ @{$attr->{Columns}} ];	# take a copy
+		for (@$slice) { $_-- }
+	    }
+	}
+	my $rows = $sth->fetchall_arrayref($slice, my $MaxRows = $attr->{MaxRows});
+	$sth->finish if defined $MaxRows;
+	return $rows;
+    }
+
+    sub selectall_hashref {
+	my ($dbh, $stmt, $key_field, $attr, @bind) = @_;
+	my $sth = (ref $stmt) ? $stmt : $dbh->prepare($stmt, $attr);
+	return unless $sth;
+	$sth->execute(@bind) || return;
+	return $sth->fetchall_hashref($key_field);
+    }
+
+    sub selectcol_arrayref {
+	my ($dbh, $stmt, $attr, @bind) = @_;
+	my $sth = (ref $stmt) ? $stmt : $dbh->prepare($stmt, $attr);
+	return unless $sth;
+	$sth->execute(@bind) || return;
+	my @columns = ($attr->{Columns}) ? @{$attr->{Columns}} : (1);
+	my @values  = (undef) x @columns;
+	my $idx = 0;
+	for (@columns) {
+	    $sth->bind_col($_, \$values[$idx++]) || return;
+	}
+	my @col;
+	if (my $max = $attr->{MaxRows}) {
+	    push @col, @values while @col<$max && $sth->fetch;
+	}
+	else {
+	    push @col, @values while $sth->fetch;
+	}
+	return \@col;
+    }
+
+    sub prepare_cached {
+	my ($dbh, $statement, $attr, $if_active) = @_;
+	# Needs support at dbh level to clear cache before complaining about
+	# active children. The XS template code does this. Drivers not using
+	# the template must handle clearing the cache themselves.
+	my $cache = $dbh->FETCH('CachedKids');
+	$dbh->STORE('CachedKids', $cache = {}) unless $cache;
+	my @attr_keys = ($attr) ? sort keys %$attr : ();
+	my $key = ($attr) ? join("~~", $statement, @attr_keys, @{$attr}{@attr_keys}) : $statement;
+	my $sth = $cache->{$key};
+	if ($sth) {
+	    return $sth unless $sth->FETCH('Active');
+	    Carp::carp("prepare_cached($statement) statement handle $sth still Active")
+		unless ($if_active ||= 0);
+	    $sth->finish if $if_active <= 1;
+	    return $sth  if $if_active <= 2;
+	}
+	$sth = $dbh->prepare($statement, $attr);
+	$cache->{$key} = $sth if $sth;
+	return $sth;
+    }
+
+    sub ping {
+	shift->_not_impl('ping');
+	"0 but true";	# special kind of true 0
+    }
+
+    sub begin_work {
+	my $dbh = shift;
+	return $dbh->set_err(1, "Already in a transaction")
+		unless $dbh->FETCH('AutoCommit');
+	$dbh->STORE('AutoCommit', 0); # will croak if driver doesn't support it
+	$dbh->STORE('BegunWork',  1); # trigger post commit/rollback action
+	return 1;
+    }
+
+    sub primary_key {
+	my ($dbh, @args) = @_;
+	my $sth = $dbh->primary_key_info(@args) or return;
+	my ($row, @col);
+	push @col, $row->[3] while ($row = $sth->fetch);
+	Carp::croak("primary_key method not called in list context")
+		unless wantarray; # leave us some elbow room
+	return @col;
+    }
+
+    sub tables {
+	my ($dbh, @args) = @_;
+	my $sth    = $dbh->table_info(@args[0,1,2,3,4]) or return;
+	my $tables = $sth->fetchall_arrayref or return;
+	my @tables;
+	if ($dbh->get_info(29)) { # SQL_IDENTIFIER_QUOTE_CHAR
+	    @tables = map { $dbh->quote_identifier( @{$_}[0,1,2] ) } @$tables;
+	}
+	else {		# temporary old style hack (yeach)
+	    @tables = map {
+		my $name = $_->[2];
+		if ($_->[1]) {
+		    my $schema = $_->[1];
+		    # a sad hack (mostly for Informix I recall)
+		    my $quote = ($schema eq uc($schema)) ? '' : '"';
+		    $name = "$quote$schema$quote.$name"
+		}
+		$name;
+	    } @$tables;
+	}
+	return @tables;
+    }
+
+    sub type_info {	# this should be sufficient for all drivers
+	my ($dbh, $data_type) = @_;
+	my $idx_hash;
+	my $tia = $dbh->{dbi_type_info_row_cache};
+	if ($tia) {
+	    $idx_hash = $dbh->{dbi_type_info_idx_cache};
+	}
+	else {
+	    my $temp = $dbh->type_info_all;
+	    return unless $temp && @$temp;
+	    # we cache here because type_info_all may be expensive to call
+	    $tia      = $dbh->{dbi_type_info_row_cache} = $temp;
+	    $idx_hash = $dbh->{dbi_type_info_idx_cache} = shift @$tia;
+	}
+
+	my $dt_idx   = $idx_hash->{DATA_TYPE} || $idx_hash->{data_type};
+	Carp::croak("type_info_all returned non-standard DATA_TYPE index value ($dt_idx != 1)")
+	    if $dt_idx && $dt_idx != 1;
+
+	# --- simple DATA_TYPE match filter
+	my @ti;
+	my @data_type_list = (ref $data_type) ? @$data_type : ($data_type);
+	foreach $data_type (@data_type_list) {
+	    if (defined($data_type) && $data_type != DBI::SQL_ALL_TYPES()) {
+		push @ti, grep { $_->[$dt_idx] == $data_type } @$tia;
+	    }
+	    else {	# SQL_ALL_TYPES
+		push @ti, @$tia;
+	    }
+	    last if @ti;	# found at least one match
+	}
+
+	# --- format results into list of hash refs
+	my $idx_fields = keys %$idx_hash;
+	my @idx_names  = map { uc($_) } keys %$idx_hash;
+	my @idx_values = values %$idx_hash;
+	Carp::croak "type_info_all result has $idx_fields keys but ".(@{$ti[0]})." fields"
+		if @ti && @{$ti[0]} != $idx_fields;
+	my @out = map {
+	    my %h; @h{@idx_names} = @{$_}[ @idx_values ]; \%h;
+	} @ti;
+	return $out[0] unless wantarray;
+	return @out;
+    }
+
+    sub data_sources {
+	my ($dbh, @other) = @_;
+	my $drh = $dbh->{Driver}; # XXX proxy issues?
+	return $drh->data_sources(@other);
+    }
+
+}
+
+
+{   package		# hide from PAUSE
+	DBD::_::st;	# ====== STATEMENT ======
+    @DBD::_::st::ISA = qw(DBD::_::common);
+    use strict;
+
+    sub bind_param { Carp::croak("Can't bind_param, not implement by driver") }
+
+#
+# ********************************************************
+#
+#	BEGIN ARRAY BINDING
+#
+#	Array binding support for drivers which don't support
+#	array binding, but have sufficient interfaces to fake it.
+#	NOTE: mixing scalars and arrayrefs requires using bind_param_array
+#	for *all* params...unless we modify bind_param for the default
+#	case...
+#
+#	2002-Apr-10	D. Arnold
+
+    sub bind_param_array {
+	my $sth = shift;
+	my ($p_id, $value_array, $attr) = @_;
+
+	return $sth->set_err(1, "Value for parameter $p_id must be a scalar or an arrayref, not a ".ref($value_array))
+	    if defined $value_array and ref $value_array and ref $value_array ne 'ARRAY';
+
+	return $sth->set_err(1, "Can't use named placeholder '$p_id' for non-driver supported bind_param_array")
+	    unless DBI::looks_like_number($p_id); # because we rely on execute(@ary) here
+
+	return $sth->set_err(1, "Placeholder '$p_id' is out of range")
+	    if $p_id <= 0; # can't easily/reliably test for too big
+
+	# get/create arrayref to hold params
+	my $hash_of_arrays = $sth->{ParamArrays} ||= { };
+
+	# If the bind has attribs then we rely on the driver conforming to
+	# the DBI spec in that a single bind_param() call with those attribs
+	# makes them 'sticky' and apply to all later execute(@values) calls.
+	# Since we only call bind_param() if we're given attribs then
+	# applications using drivers that don't support bind_param can still
+	# use bind_param_array() so long as they don't pass any attribs.
+
+	$$hash_of_arrays{$p_id} = $value_array;
+	return $sth->bind_param($p_id, undef, $attr) 
+		if $attr;
+	1;
+    }
+
+    sub bind_param_inout_array { 
+	my $sth = shift;
+	# XXX not supported so we just call bind_param_array instead
+	# and then return an error
+	my ($p_num, $value_array, $attr) = @_;
+	$sth->bind_param_array($p_num, $value_array, $attr);
+	return $sth->set_err(1, "bind_param_inout_array not supported");
+    }
+
+    sub bind_columns {
+	my $sth = shift;
+	my $fields = $sth->FETCH('NUM_OF_FIELDS') || 0;
+	if ($fields <= 0 && !$sth->{Active}) {
+	    return $sth->set_err(1, "Statement has no result columns to bind"
+		    ." (perhaps you need to successfully call execute first)");
+	}
+	# Backwards compatibility for old-style call with attribute hash
+	# ref as first arg. Skip arg if undef or a hash ref.
+	my $attr;
+	$attr = shift if !defined $_[0] or ref($_[0]) eq 'HASH';
+
+	die "bind_columns called with ".@_." refs when $fields needed."
+	    if @_ != $fields;
+	my $idx = 0;
+	$sth->bind_col(++$idx, shift, $attr) or return
+	    while (@_);
+	return 1;
+    }
+
+    sub execute_array {
+	my $sth = shift;
+	my ($attr, @array_of_arrays) = @_;
+	my $NUM_OF_PARAMS = $sth->FETCH('NUM_OF_PARAMS'); # may be undef at this point
+
+	# get tuple status array or hash attribute
+	my $tuple_sts = $attr->{ArrayTupleStatus};
+	return $sth->set_err(1, "ArrayTupleStatus attribute must be an arrayref")
+		if $tuple_sts and ref $tuple_sts ne 'ARRAY';
+
+	# bind all supplied arrays
+	if (@array_of_arrays) {
+	    $sth->{ParamArrays} = { };	# clear out old params
+	    return $sth->set_err(1,
+		    @array_of_arrays." bind values supplied but $NUM_OF_PARAMS expected")
+		if defined ($NUM_OF_PARAMS) && @array_of_arrays != $NUM_OF_PARAMS;
+	    $sth->bind_param_array($_, $array_of_arrays[$_-1]) or return
+		foreach (1..@array_of_arrays);
+	}
+
+	my $fetch_tuple_sub;
+
+	if ($fetch_tuple_sub = $attr->{ArrayTupleFetch}) {	# fetch on demand
+
+	    return $sth->set_err(1,
+		    "Can't use both ArrayTupleFetch and explicit bind values")
+		if @array_of_arrays; # previous bind_param_array calls will simply be ignored
+
+	    if (UNIVERSAL::isa($fetch_tuple_sub,'DBI::st')) {
+		my $fetch_sth = $fetch_tuple_sub;
+		return $sth->set_err(1,
+			"ArrayTupleFetch sth is not Active, need to execute() it first")
+		    unless $fetch_sth->{Active};
+		# check column count match to give more friendly message
+		my $NUM_OF_FIELDS = $fetch_sth->{NUM_OF_FIELDS};
+		return $sth->set_err(1,
+			"$NUM_OF_FIELDS columns from ArrayTupleFetch sth but $NUM_OF_PARAMS expected")
+		    if defined($NUM_OF_FIELDS) && defined($NUM_OF_PARAMS)
+		    && $NUM_OF_FIELDS != $NUM_OF_PARAMS;
+		$fetch_tuple_sub = sub { $fetch_sth->fetchrow_arrayref };
+	    }
+	    elsif (!UNIVERSAL::isa($fetch_tuple_sub,'CODE')) {
+		return $sth->set_err(1, "ArrayTupleFetch '$fetch_tuple_sub' is not a code ref or statement handle");
+	    }
+
+	}
+	else {
+	    my $NUM_OF_PARAMS_given = keys %{ $sth->{ParamArrays} || {} };
+	    return $sth->set_err(1,
+		    "$NUM_OF_PARAMS_given bind values supplied but $NUM_OF_PARAMS expected")
+		if defined($NUM_OF_PARAMS) && $NUM_OF_PARAMS != $NUM_OF_PARAMS_given;
+
+	    # get the length of a bound array
+	    my $maxlen;
+	    my %hash_of_arrays = %{$sth->{ParamArrays}};
+	    foreach (keys(%hash_of_arrays)) {
+		my $ary = $hash_of_arrays{$_};
+		next unless ref $ary eq 'ARRAY';
+		$maxlen = @$ary if !$maxlen || @$ary > $maxlen;
+	    }
+	    # if there are no arrays then execute scalars once
+	    $maxlen = 1 unless defined $maxlen;
+	    my @bind_ids = 1..keys(%hash_of_arrays);
+
+	    my $tuple_idx = 0;
+	    $fetch_tuple_sub = sub {
+		return if $tuple_idx >= $maxlen;
+		my @tuple = map {
+		    my $a = $hash_of_arrays{$_};
+		    ref($a) ? $a->[$tuple_idx] : $a
+		} @bind_ids;
+		++$tuple_idx;
+		return \@tuple;
+	    };
+	}
+
+	return $sth->execute_for_fetch($fetch_tuple_sub, $tuple_sts);
+    }
+
+    sub execute_for_fetch {
+	my ($sth, $fetch_tuple_sub, $tuple_status) = @_;
+	# start with empty status array
+	($tuple_status) ? @$tuple_status = () : $tuple_status = [];
+
+	my ($err_count, %errstr_cache);
+	while ( my $tuple = &$fetch_tuple_sub() ) {
+	    if ( my $rc = $sth->execute(@$tuple) ) {
+		push @$tuple_status, $rc;
+	    }
+	    else {
+		$err_count++;
+		my $err = $sth->err;
+		push @$tuple_status, [ $err, $errstr_cache{$err} ||= $sth->errstr, $sth->state ];
+	    }
+	}
+	return ($err_count) ? undef : scalar(@$tuple_status)||"0E0";
+    }
+
+
+    sub fetchall_arrayref {	# ALSO IN Driver.xst
+	my ($sth, $slice, $max_rows) = @_;
+	$max_rows = -1 unless defined $max_rows;
+	my $mode = ref($slice) || 'ARRAY';
+	my @rows;
+	my $row;
+	if ($mode eq 'ARRAY') {
+	    # we copy the array here because fetch (currently) always
+	    # returns the same array ref. XXX
+	    if ($slice && @$slice) {
+		$max_rows = -1 unless defined $max_rows;
+		push @rows, [ @{$row}[ @$slice] ]
+		    while($max_rows-- and $row = $sth->fetch);
+	    }
+	    elsif (defined $max_rows) {
+		$max_rows = -1 unless defined $max_rows;
+		push @rows, [ @$row ]
+		    while($max_rows-- and $row = $sth->fetch);
+	    }
+	    else {
+		push @rows, [ @$row ]          while($row = $sth->fetch);
+	    }
+	}
+	elsif ($mode eq 'HASH') {
+	    $max_rows = -1 unless defined $max_rows;
+	    if (keys %$slice) {
+		my @o_keys = keys %$slice;
+		my @i_keys = map { lc } keys %$slice;
+		while ($max_rows-- and $row = $sth->fetchrow_hashref('NAME_lc')) {
+		    my %hash;
+		    @hash{@o_keys} = @{$row}{@i_keys};
+		    push @rows, \%hash;
+		}
+	    }
+	    else {
+		# XXX assumes new ref each fetchhash
+		push @rows, $row
+		    while ($max_rows-- and $row = $sth->fetchrow_hashref());
+	    }
+	}
+	else { Carp::croak("fetchall_arrayref($mode) invalid") }
+	return \@rows;
+    }
+
+    sub fetchall_hashref {
+	my ($sth, $key_field) = @_;
+
+        my $hash_key_name = $sth->{FetchHashKeyName} || 'NAME';
+        my $names_hash = $sth->FETCH("${hash_key_name}_hash");
+        my @key_fields = (ref $key_field) ? @$key_field : ($key_field);
+        my @key_indexes;
+        my $num_of_fields = $sth->FETCH('NUM_OF_FIELDS');
+        foreach (@key_fields) {
+           my $index = $names_hash->{$_};  # perl index not column
+           $index = $_ - 1 if !defined $index && DBI::looks_like_number($_) && $_>=1 && $_ <= $num_of_fields;
+           return $sth->set_err(1, "Field '$_' does not exist (not one of @{[keys %$names_hash]})")
+                unless defined $index;
+           push @key_indexes, $index;
+        }
+        my $rows = {};
+        my $NAME = $sth->FETCH($hash_key_name);
+        my @row = (undef) x $num_of_fields;
+        $sth->bind_columns(\(@row));
+        while ($sth->fetch) {
+            my $ref = $rows;
+            $ref = $ref->{$row[$_]} ||= {} for @key_indexes;
+            @{$ref}{@$NAME} = @row;
+        }
+        return $rows;
+    }
+
+    *dump_results = \&DBI::dump_results;
+
+    sub blob_copy_to_file {	# returns length or undef on error
+	my($self, $field, $filename_or_handleref, $blocksize) = @_;
+	my $fh = $filename_or_handleref;
+	my($len, $buf) = (0, "");
+	$blocksize ||= 512;	# not too ambitious
+	local(*FH);
+	unless(ref $fh) {
+	    open(FH, ">$fh") || return undef;
+	    $fh = \*FH;
+	}
+	while(defined($self->blob_read($field, $len, $blocksize, \$buf))) {
+	    print $fh $buf;
+	    $len += length $buf;
+	}
+	close(FH);
+	$len;
+    }
+
+    sub more_results {
+	shift->{syb_more_results};	# handy grandfathering
+    }
+
+}
+
+unless ($DBI::PurePerl) {   # See install_driver
+    { @DBD::_mem::dr::ISA = qw(DBD::_mem::common);	}
+    { @DBD::_mem::db::ISA = qw(DBD::_mem::common);	}
+    { @DBD::_mem::st::ISA = qw(DBD::_mem::common);	}
+    # DBD::_mem::common::DESTROY is implemented in DBI.xs
+}
+
+1;
+__END__
+
+=head1 DESCRIPTION
+
+The DBI is a database access module for the Perl programming language.  It defines
+a set of methods, variables, and conventions that provide a consistent
+database interface, independent of the actual database being used.
+
+It is important to remember that the DBI is just an interface.
+The DBI is a layer
+of "glue" between an application and one or more database I<driver>
+modules.  It is the driver modules which do most of the real work. The DBI
+provides a standard interface and framework for the drivers to operate
+within.
+
+
+=head2 Architecture of a DBI Application
+
+             |<- Scope of DBI ->|
+                  .-.   .--------------.   .-------------.
+  .-------.       | |---| XYZ Driver   |---| XYZ Engine  |
+  | Perl  |       | |   `--------------'   `-------------'
+  | script|  |A|  |D|   .--------------.   .-------------.
+  | using |--|P|--|B|---|Oracle Driver |---|Oracle Engine|
+  | DBI   |  |I|  |I|   `--------------'   `-------------'
+  | API   |       | |...
+  |methods|       | |... Other drivers
+  `-------'       | |...
+                  `-'
+
+The API, or Application Programming Interface, defines the
+call interface and variables for Perl scripts to use. The API
+is implemented by the Perl DBI extension.
+
+The DBI "dispatches" the method calls to the appropriate driver for
+actual execution.  The DBI is also responsible for the dynamic loading
+of drivers, error checking and handling, providing default
+implementations for methods, and many other non-database specific duties.
+
+Each driver
+contains implementations of the DBI methods using the
+private interface functions of the corresponding database engine.  Only authors
+of sophisticated/multi-database applications or generic library
+functions need be concerned with drivers.
+
+=head2 Notation and Conventions
+
+The following conventions are used in this document:
+
+  $dbh    Database handle object
+  $sth    Statement handle object
+  $drh    Driver handle object (rarely seen or used in applications)
+  $h      Any of the handle types above ($dbh, $sth, or $drh)
+  $rc     General Return Code  (boolean: true=ok, false=error)
+  $rv     General Return Value (typically an integer)
+  @ary    List of values returned from the database, typically a row of data
+  $rows   Number of rows processed (if available, else -1)
+  $fh     A filehandle
+  undef   NULL values are represented by undefined values in Perl
+  \%attr  Reference to a hash of attribute values passed to methods
+
+Note that Perl will automatically destroy database and statement handle objects
+if all references to them are deleted.
+
+
+=head2 Outline Usage
+
+To use DBI,
+first you need to load the DBI module:
+
+  use DBI;
+  use strict;
+
+(The C<use strict;> isn't required but is strongly recommended.)
+
+Then you need to L</connect> to your data source and get a I<handle> for that
+connection:
+
+  $dbh = DBI->connect($dsn, $user, $password,
+                      { RaiseError => 1, AutoCommit => 0 });
+
+Since connecting can be expensive, you generally just connect at the
+start of your program and disconnect at the end.
+
+Explicitly defining the required C<AutoCommit> behaviour is strongly
+recommended and may become mandatory in a later version.  This
+determines whether changes are automatically committed to the
+database when executed, or need to be explicitly committed later.
+
+The DBI allows an application to "prepare" statements for later
+execution.  A prepared statement is identified by a statement handle
+held in a Perl variable.
+We'll call the Perl variable C<$sth> in our examples.
+
+The typical method call sequence for a C<SELECT> statement is:
+
+  prepare,
+    execute, fetch, fetch, ...
+    execute, fetch, fetch, ...
+    execute, fetch, fetch, ...
+
+for example:
+
+  $sth = $dbh->prepare("SELECT foo, bar FROM table WHERE baz=?");
+
+  $sth->execute( $baz );
+
+  while ( @row = $sth->fetchrow_array ) {
+    print "@row\n";
+  }
+
+The typical method call sequence for a I<non>-C<SELECT> statement is:
+
+  prepare,
+    execute,
+    execute,
+    execute.
+
+for example:
+
+  $sth = $dbh->prepare("INSERT INTO table(foo,bar,baz) VALUES (?,?,?)");
+
+  while(<CSV>) {
+    chomp;
+    my ($foo,$bar,$baz) = split /,/;
+	$sth->execute( $foo, $bar, $baz );
+  }
+
+The C<do()> method can be used for non repeated I<non>-C<SELECT> statement
+(or with drivers that don't support placeholders):
+
+  $rows_affected = $dbh->do("UPDATE your_table SET foo = foo + 1");
+
+To commit your changes to the database (when L</AutoCommit> is off):
+
+  $dbh->commit;  # or call $dbh->rollback; to undo changes
+
+Finally, when you have finished working with the data source, you should
+L</disconnect> from it:
+
+  $dbh->disconnect;
+
+
+=head2 General Interface Rules & Caveats
+
+The DBI does not have a concept of a "current session". Every session
+has a handle object (i.e., a C<$dbh>) returned from the C<connect> method.
+That handle object is used to invoke database related methods.
+
+Most data is returned to the Perl script as strings. (Null values are
+returned as C<undef>.)  This allows arbitrary precision numeric data to be
+handled without loss of accuracy.  Beware that Perl may not preserve
+the same accuracy when the string is used as a number.
+
+Dates and times are returned as character strings in the current
+default format of the corresponding database engine.  Time zone effects
+are database/driver dependent.
+
+Perl supports binary data in Perl strings, and the DBI will pass binary
+data to and from the driver without change. It is up to the driver
+implementors to decide how they wish to handle such binary data.
+
+Most databases that understand multiple character sets have a
+default global charset. Text stored in the database is, or should
+be, stored in that charset; if not, then that's the fault of either
+the database or the application that inserted the data. When text is
+fetched it should be automatically converted to the charset of the
+client, presumably based on the locale. If a driver needs to set a
+flag to get that behaviour, then it should do so; it should not require
+the application to do that.
+
+Multiple SQL statements may not be combined in a single statement
+handle (C<$sth>), although some databases and drivers do support this
+(notably Sybase and SQL Server).
+
+Non-sequential record reads are not supported in this version of the DBI.
+In other words, records can only be fetched in the order that the
+database returned them, and once fetched they are forgotten.
+
+Positioned updates and deletes are not directly supported by the DBI.
+See the description of the C<CursorName> attribute for an alternative.
+
+Individual driver implementors are free to provide any private
+functions and/or handle attributes that they feel are useful.
+Private driver functions can be invoked using the DBI C<func()> method.
+Private driver attributes are accessed just like standard attributes.
+
+Many methods have an optional C<\%attr> parameter which can be used to
+pass information to the driver implementing the method. Except where
+specifically documented, the C<\%attr> parameter can only be used to pass
+driver specific hints. In general, you can ignore C<\%attr> parameters
+or pass it as C<undef>.
+
+
+=head2 Naming Conventions and Name Space
+
+The DBI package and all packages below it (C<DBI::*>) are reserved for
+use by the DBI. Extensions and related modules use the C<DBIx::>
+namespace (see L<http://www.perl.com/CPAN/modules/by-module/DBIx/>).
+Package names beginning with C<DBD::> are reserved for use
+by DBI database drivers.  All environment variables used by the DBI
+or by individual DBDs begin with "C<DBI_>" or "C<DBD_>".
+
+The letter case used for attribute names is significant and plays an
+important part in the portability of DBI scripts.  The case of the
+attribute name is used to signify who defined the meaning of that name
+and its values.
+
+  Case of name  Has a meaning defined by
+  ------------  ------------------------
+  UPPER_CASE    Standards, e.g.,  X/Open, ISO SQL92 etc (portable)
+  MixedCase     DBI API (portable), underscores are not used.
+  lower_case    Driver or database engine specific (non-portable)
+
+It is of the utmost importance that Driver developers only use
+lowercase attribute names when defining private attributes. Private
+attribute names must be prefixed with the driver name or suitable
+abbreviation (e.g., "C<ora_>" for Oracle, "C<ing_>" for Ingres, etc).
+
+
+=head2 SQL - A Query Language
+
+Most DBI drivers require applications to use a dialect of SQL
+(Structured Query Language) to interact with the database engine.
+The L</"Standards Reference Information"> section provides links
+to useful information about SQL.
+
+The DBI itself does not mandate or require any particular language to
+be used; it is language independent. In ODBC terms, the DBI is in
+"pass-thru" mode, although individual drivers might not be. The only requirement
+is that queries and other statements must be expressed as a single
+string of characters passed as the first argument to the L</prepare> or
+L</do> methods.
+
+For an interesting diversion on the I<real> history of RDBMS and SQL,
+from the people who made it happen, see:
+
+  http://ftp.digital.com/pub/DEC/SRC/technical-notes/SRC-1997-018-html/sqlr95.html
+
+Follow the "Full Contents" then "Intergalactic dataspeak" links for the
+SQL history.
+
+=head2 Placeholders and Bind Values
+
+Some drivers support placeholders and bind values.
+I<Placeholders>, also called parameter markers, are used to indicate
+values in a database statement that will be supplied later,
+before the prepared statement is executed.  For example, an application
+might use the following to insert a row of data into the SALES table:
+
+  INSERT INTO sales (product_code, qty, price) VALUES (?, ?, ?)
+
+or the following, to select the description for a product:
+
+  SELECT description FROM products WHERE product_code = ?
+
+The C<?> characters are the placeholders.  The association of actual
+values with placeholders is known as I<binding>, and the values are
+referred to as I<bind values>.
+
+Note that the C<?> is not enclosed in quotation marks, even when the
+placeholder represents a string.  Some drivers also allow placeholders
+like C<:>I<name> and C<:>I<n> (e.g., C<:1>, C<:2>, and so on)
+in addition to C<?>, but their use is not portable.
+
+With most drivers, placeholders can't be used for any element of a
+statement that would prevent the database server from validating the
+statement and creating a query execution plan for it. For example:
+
+  "SELECT name, age FROM ?"         # wrong (will probably fail)
+  "SELECT name, ?   FROM people"    # wrong (but may not 'fail')
+
+Also, placeholders can only represent single scalar values.
+For example, the following
+statement won't work as expected for more than one value:
+
+  "SELECT name, age FROM people WHERE name IN (?)"    # wrong
+  "SELECT name, age FROM people WHERE name IN (?,?)"  # two names
+
+When using placeholders with the SQL C<LIKE> qualifier, you must
+remember that the placeholder substitutes for the whole string.
+So you should use "C<... LIKE ? ...>" and include any wildcard
+characters in the value that you bind to the placeholder.
+
+B<NULL Values>
+
+Undefined values, or C<undef>, are used to indicate NULL values.
+You can insert and update columns with a NULL value as you would a
+non-NULL value.  These examples insert and update the column
+C<age> with a NULL value:
+
+  $sth = $dbh->prepare(qq{
+    INSERT INTO people (fullname, age) VALUES (?, ?)
+  });
+  $sth->execute("Joe Bloggs", undef);
+
+  $sth = $dbh->prepare(qq{
+    UPDATE people SET age = ? WHERE fullname = ?
+  });
+  $sth->execute(undef, "Joe Bloggs");
+  
+However, care must be taken when trying to use NULL values in a
+C<WHERE> clause.  Consider:
+
+  SELECT fullname FROM people WHERE age = ?
+
+Binding an C<undef> (NULL) to the placeholder will I<not> select rows
+which have a NULL C<age>!  At least for database engines that
+conform to the SQL standard.  Refer to the SQL manual for your database
+engine or any SQL book for the reasons for this.  To explicitly select
+NULLs you have to say "C<WHERE age IS NULL>".
+
+A common issue is to have a code fragment handle a value that could be
+either C<defined> or C<undef> (non-NULL or NULL) at runtime.
+A simple technique is to prepare the appropriate statement as needed,
+and substitute the placeholder for non-NULL cases:
+
+  $sql_clause = defined $age? "age = ?" : "age IS NULL";
+  $sth = $dbh->prepare(qq{
+    SELECT fullname FROM people WHERE $sql_clause
+  });
+  $sth->execute(defined $age ? $age : ());
+
+The following technique illustrates qualifying a C<WHERE> clause with
+several columns, whose associated values (C<defined> or C<undef>) are
+in a hash %h:
+
+  for my $col ("age", "phone", "email") {
+    if (defined $h{$col}) {
+      push @sql_qual, "$col = ?";
+      push @sql_bind, $h{$col};
+    }
+    else {
+      push @sql_qual, "$col IS NULL";
+    }
+  }
+  $sql_clause = join(" AND ", @sql_qual);
+  $sth = $dbh->prepare(qq{
+      SELECT fullname FROM people WHERE $sql_clause
+  });
+  $sth->execute(@sql_bind);
+
+The techniques above call prepare for the SQL statement with each call to
+execute.  Because calls to prepare() can be expensive, performance
+can suffer when an application iterates many times over statements
+like the above.
+
+A better solution is a single C<WHERE> clause that supports both
+NULL and non-NULL comparisons.  Its SQL statement would need to be
+prepared only once for all cases, thus improving performance.
+Several examples of C<WHERE> clauses that support this are presented
+below.  But each example lacks portability, robustness, or simplicity.
+Whether an example is supported on your database engine depends on
+what SQL extensions it provides, and where it supports the C<?>
+placeholder in a statement.
+
+  0)  age = ?
+  1)  NVL(age, xx) = NVL(?, xx)
+  2)  ISNULL(age, xx) = ISNULL(?, xx)
+  3)  DECODE(age, ?, 1, 0) = 1
+  4)  age = ? OR (age IS NULL AND ? IS NULL)
+  5)  age = ? OR (age IS NULL AND SP_ISNULL(?) = 1)
+  6)  age = ? OR (age IS NULL AND ? = 1)
+	
+Statements formed with the above C<WHERE> clauses require execute
+statements as follows.  The arguments are required, whether their
+values are C<defined> or C<undef>.
+
+  0,1,2,3)  $sth->execute($age);
+  4,5)      $sth->execute($age, $age);
+  6)        $sth->execute($age, defined($age) ? 0 : 1);
+
+Example 0 should not work (as mentioned earlier), but may work on
+a few database engines anyway (e.g. Sybase).  Example 0 is part
+of examples 4, 5, and 6, so if example 0 works, these other
+examples may work, even if the engine does not properly support
+the right hand side of the C<OR> expression.
+
+Examples 1 and 2 are not robust: they require that you provide a
+valid column value xx (e.g. '~') which is not present in any row.
+That means you must have some notion of what data won't be stored
+in the column, and expect clients to adhere to that.
+
+Example 5 requires that you provide a stored procedure (SP_ISNULL
+in this example) that acts as a function: it checks whether a value
+is null, and returns 1 if it is, or 0 if not.
+
+Example 6, the least simple, is probably the most portable, i.e., it
+should work with with most, if not all, database engines.
+
+Here is a table that indicates which examples above are known to
+work on various database engines:
+
+                   -----Examples------
+                   0  1  2  3  4  5  6
+                   -  -  -  -  -  -  -
+  Oracle 9         N  Y  N  Y  Y  ?  Y
+  Informix IDS 9   N  N  N  Y  N  Y  Y
+  MS SQL           N  N  Y  N  Y  ?  Y
+  Sybase           Y  N  N  N  N  N  Y
+  AnyData,DBM,CSV  Y  N  N  N  Y  Y* Y  
+
+* Works only because Example 0 works.
+
+DBI provides a sample perl script that will test the examples above
+on your database engine and tell you which ones work.  It is located
+in the F<ex/> subdirectory of the DBI source distribution, or here:
+L<http://svn.perl.org/modules/dbi/trunk/ex/perl_dbi_nulls_test.pl>
+Please use the script to help us fill-in and maintain this table.
+
+B<Performance>
+
+Without using placeholders, the insert statement shown previously would have to
+contain the literal values to be inserted and would have to be
+re-prepared and re-executed for each row. With placeholders, the insert
+statement only needs to be prepared once. The bind values for each row
+can be given to the C<execute> method each time it's called. By avoiding
+the need to re-prepare the statement for each row, the application
+typically runs many times faster. Here's an example:
+
+  my $sth = $dbh->prepare(q{
+    INSERT INTO sales (product_code, qty, price) VALUES (?, ?, ?)
+  }) or die $dbh->errstr;
+  while (<>) {
+      chomp;
+      my ($product_code, $qty, $price) = split /,/;
+      $sth->execute($product_code, $qty, $price) or die $dbh->errstr;
+  }
+  $dbh->commit or die $dbh->errstr;
+
+See L</execute> and L</bind_param> for more details.
+
+The C<q{...}> style quoting used in this example avoids clashing with
+quotes that may be used in the SQL statement. Use the double-quote like
+C<qq{...}> operator if you want to interpolate variables into the string.
+See L<perlop/"Quote and Quote-like Operators"> for more details.
+
+See also the L</bind_columns> method, which is used to associate Perl
+variables with the output columns of a C<SELECT> statement.
+
+=head1 THE DBI PACKAGE AND CLASS
+
+In this section, we cover the DBI class methods, utility functions,
+and the dynamic attributes associated with generic DBI handles.
+
+=head2 DBI Constants
+
+Constants representing the values of the SQL standard types can be
+imported individually by name, or all together by importing the
+special C<:sql_types> tag.
+
+The names and values of all the defined SQL standard types can be
+produced like this:
+
+  foreach (@{ $DBI::EXPORT_TAGS{sql_types} }) {
+    printf "%s=%d\n", $_, &{"DBI::$_"};
+  }
+
+These constants are defined by SQL/CLI, ODBC or both.
+C<SQL_BIGINT> is (currently) omitted, because SQL/CLI and ODBC provide
+conflicting codes.
+
+See the L</type_info>, L</type_info_all>, and L</bind_param> methods
+for possible uses.
+
+Note that just because the DBI defines a named constant for a given
+data type doesn't mean that drivers will support that data type.
+
+
+=head2 DBI Class Methods
+
+The following methods are provided by the DBI class:
+
+=over 4
+
+=item C<parse_dsn>
+
+  ($scheme, $driver, $attr_string, $attr_hash, $driver_dsn) = DBI->parse_dsn($dsn)
+      or die "Can't parse DBI DSN '$dsn'";
+
+Breaks apart a DBI Data Source Name (DSN) and returns the individual
+parts. If $dsn doesn't contain a valid DSN then parse_dsn() returns
+an empty list.
+
+$scheme is the first part of the DSN and is currently always 'dbi'.
+$driver is the driver name, possibly defaulted to $ENV{DBI_DRIVER},
+and may be undefined.  $attr_string is the optional attribute string,
+which may be undefined.  If $attr_string is true then $attr_hash
+is a reference to a hash containing the parsed attribute names and
+values. $driver_dsn is the last part of the DBI DSN string.
+
+The parse_dsn() method was added in DBI 1.43.
+
+=item C<connect>
+
+  $dbh = DBI->connect($data_source, $username, $password)
+            or die $DBI::errstr;
+  $dbh = DBI->connect($data_source, $username, $password, \%attr)
+            or die $DBI::errstr;
+
+Establishes a database connection, or session, to the requested C<$data_source>.
+Returns a database handle object if the connection succeeds. Use
+C<$dbh-E<gt>disconnect> to terminate the connection.
+
+If the connect fails (see below), it returns C<undef> and sets both C<$DBI::err>
+and C<$DBI::errstr>. (It does I<not> explicitly set C<$!>.) You should generally
+test the return status of C<connect> and C<print $DBI::errstr> if it has failed.
+
+Multiple simultaneous connections to multiple databases through multiple
+drivers can be made via the DBI. Simply make one C<connect> call for each
+database and keep a copy of each returned database handle.
+
+The C<$data_source> value must begin with "C<dbi:>I<driver_name>C<:>".
+The I<driver_name> specifies the driver that will be used to make the
+connection. (Letter case is significant.)
+
+As a convenience, if the C<$data_source> parameter is undefined or empty,
+the DBI will substitute the value of the environment variable C<DBI_DSN>.
+If just the I<driver_name> part is empty (i.e., the C<$data_source>
+prefix is "C<dbi::>"), the environment variable C<DBI_DRIVER> is
+used. If neither variable is set, then C<connect> dies.
+
+Examples of C<$data_source> values are:
+
+  dbi:DriverName:database_name
+  dbi:DriverName:database_name@hostname:port
+  dbi:DriverName:database=database_name;host=hostname;port=port
+
+There is I<no standard> for the text following the driver name. Each
+driver is free to use whatever syntax it wants. The only requirement the
+DBI makes is that all the information is supplied in a single string.
+You must consult the documentation for the drivers you are using for a
+description of the syntax they require.
+
+It is recommended that drivers support the ODBC style, shown in the
+last example above. It is also recommended that that they support the
+three common names 'C<host>', 'C<port>', and 'C<database>' (plus 'C<db>'
+as an alias for C<database>). This simplifies automatic construction
+of basic DSNs: C<"dbi:$driver:database=$db;host=$host;port=$port">.
+Drivers should aim to 'do something reasonable' when given a DSN
+in this form, but if any part is meaningless for that driver (such
+as 'port' for Informix) it should generate an error if that part
+is not empty.
+
+If the environment variable C<DBI_AUTOPROXY> is defined (and the
+driver in C<$data_source> is not "C<Proxy>") then the connect request
+will automatically be changed to:
+
+  $ENV{DBI_AUTOPROXY};dsn=$data_source
+
+C<DBI_AUTOPROXY> is typically set as "C<dbi:Proxy:hostname=...;port=...>".
+If $ENV{DBI_AUTOPROXY} doesn't begin with 'C<dbi:>' then "dbi:Proxy:"
+will be prepended to it first.  See the DBD::Proxy documentation
+for more details.
+
+If C<$username> or C<$password> are undefined (rather than just empty),
+then the DBI will substitute the values of the C<DBI_USER> and C<DBI_PASS>
+environment variables, respectively.  The DBI will warn if the
+environment variables are not defined.  However, the everyday use
+of these environment variables is not recommended for security
+reasons. The mechanism is primarily intended to simplify testing.
+See below for alternative way to specify the username and password.
+
+C<DBI-E<gt>connect> automatically installs the driver if it has not been
+installed yet. Driver installation either returns a valid driver
+handle, or it I<dies> with an error message that includes the string
+"C<install_driver>" and the underlying problem. So C<DBI-E<gt>connect>
+will die
+on a driver installation failure and will only return C<undef> on a
+connect failure, in which case C<$DBI::errstr> will hold the error message.
+Use C<eval { ... }> if you need to catch the "C<install_driver>" error.
+
+The C<$data_source> argument (with the "C<dbi:...:>" prefix removed) and the
+C<$username> and C<$password> arguments are then passed to the driver for
+processing. The DBI does not define any interpretation for the
+contents of these fields.  The driver is free to interpret the
+C<$data_source>, C<$username>, and C<$password> fields in any way, and supply
+whatever defaults are appropriate for the engine being accessed.
+(Oracle, for example, uses the ORACLE_SID and TWO_TASK environment
+variables if no C<$data_source> is specified.)
+
+The C<AutoCommit> and C<PrintError> attributes for each connection
+default to "on". (See L</AutoCommit> and L</PrintError> for more information.)
+However, it is strongly recommended that you explicitly define C<AutoCommit>
+rather than rely on the default. The C<PrintWarn> attribute defaults to
+on if $^W is true, i.e., perl is running with warnings enabled.
+
+The C<\%attr> parameter can be used to alter the default settings of
+C<PrintError>, C<RaiseError>, C<AutoCommit>, and other attributes. For example:
+
+  $dbh = DBI->connect($data_source, $user, $pass, {
+	PrintError => 0,
+	AutoCommit => 0
+  });
+
+The username and password can also be specified using the attributes
+C<Username> and C<Password>, in which case they take precedence
+over the C<$username> and C<$password> parameters.
+
+You can also define connection attribute values within the C<$data_source>
+parameter. For example:
+
+  dbi:DriverName(PrintWarn=>1,PrintError=>0,Taint=>1):...
+
+Individual attributes values specified in this way take precedence over
+any conflicting values specified via the C<\%attr> parameter to C<connect>.
+
+The C<dbi_connect_method> attribute can be used to specify which driver
+method should be called to establish the connection. The only useful
+values are 'connect', 'connect_cached', or some specialized case like
+'Apache::DBI::connect' (which is automatically the default when running
+within Apache).
+
+Where possible, each session (C<$dbh>) is independent from the transactions
+in other sessions. This is useful when you need to hold cursors open
+across transactions--for example, if you use one session for your long lifespan
+cursors (typically read-only) and another for your short update
+transactions.
+
+For compatibility with old DBI scripts, the driver can be specified by
+passing its name as the fourth argument to C<connect> (instead of C<\%attr>):
+
+  $dbh = DBI->connect($data_source, $user, $pass, $driver);
+
+In this "old-style" form of C<connect>, the C<$data_source> should not start
+with "C<dbi:driver_name:>". (If it does, the embedded driver_name
+will be ignored). Also note that in this older form of C<connect>,
+the C<$dbh-E<gt>{AutoCommit}> attribute is I<undefined>, the
+C<$dbh-E<gt>{PrintError}> attribute is off, and the old C<DBI_DBNAME>
+environment variable is
+checked if C<DBI_DSN> is not defined. Beware that this "old-style"
+C<connect> will soon be withdrawn in a future version of DBI.
+
+=item C<connect_cached>
+
+  $dbh = DBI->connect_cached($data_source, $username, $password)
+            or die $DBI::errstr;
+  $dbh = DBI->connect_cached($data_source, $username, $password, \%attr)
+            or die $DBI::errstr;
+
+C<connect_cached> is like L</connect>, except that the database handle
+returned is also
+stored in a hash associated with the given parameters. If another call
+is made to C<connect_cached> with the same parameter values, then the
+corresponding cached C<$dbh> will be returned if it is still valid.
+The cached database handle is replaced with a new connection if it
+has been disconnected or if the C<ping> method fails.
+
+Note that the behaviour of this method differs in several respects from the
+behaviour of persistent connections implemented by Apache::DBI.
+
+Caching connections can be useful in some applications, but it can
+also cause problems, such as too many connections, and so should
+be used with care. In particular, avoid changing the attributes of
+a database handle created via connect_cached() because it will affect
+other code that may be using the same handle.
+
+Where multiple separate parts of a program are using connect_cached()
+to connect to the same database with the same (initial) attributes
+it is a good idea to add a private attribute to the connect_cached()
+call to effectively limit the scope of the caching. For example:
+
+  DBI->connect_cached(..., { private_foo_cachekey => "Bar", ... });
+
+Handles returned from that connect_cached() call will only be returned
+by other connect_cached() call elsewhere in the code if those other
+calls also pass in the same attribute values, including the private one.
+(I've used C<private_foo_cachekey> here as an example, you can use
+any attribute name with a C<private_> prefix.)
+
+Taking that one step further, you can limit a particular connect_cached()
+call to return handles unique to that one place in the code by setting the
+private attribute to a unique value for that place:
+
+  DBI->connect_cached(..., { private_foo_cachekey => __FILE__.__LINE__, ... });
+
+By using a private attribute you still get connection caching for
+the individual calls to connect_cached() but, by making separate
+database conections for separate parts of the code, the database
+handles are isolated from any attribute changes made to other handles.
+
+The cache can be accessed (and cleared) via the L</CachedKids> attribute:
+
+  my $CachedKids_hashref = $dbh->{Driver}->{CachedKids};
+  %$CachedKids_hashref = () if $CachedKids_hashref;
+
+
+=item C<available_drivers>
+
+  @ary = DBI->available_drivers;
+  @ary = DBI->available_drivers($quiet);
+
+Returns a list of all available drivers by searching for C<DBD::*> modules
+through the directories in C<@INC>. By default, a warning is given if
+some drivers are hidden by others of the same name in earlier
+directories. Passing a true value for C<$quiet> will inhibit the warning.
+
+
+=item C<installed_versions>
+
+  DBI->installed_versions;
+  @ary  = DBI->installed_versions;
+  %hash = DBI->installed_versions;
+
+Calls available_drivers() and attempts to load each of them in turn
+using install_driver().  For each load that succeeds the driver
+name and version number are added to a hash. When running under
+L<DBI::PurePerl> drivers which appear not be pure-perl are ignored.
+
+When called in array context the list of successfully loaded drivers
+is returned (without the 'DBD::' prefix).
+
+When called in scalar context a reference to the hash is returned
+and the hash will also contain other entries for the C<DBI> version,
+C<OS> name, etc.
+
+When called in a void context the installed_versions() method will
+print out a formatted list of the hash contents, one per line.
+
+Due to the potentially high memory cost and unknown risks of loading
+in an unknown number of drivers that just happen to be installed
+on the system, this method is nor recommended for general use.
+Use available_drivers() instead.
+
+The installed_versions() method is primarily intended as a quick
+way to see from the command line what's installed. For example:
+
+  perl -MDBI -e 'DBI->installed_versions'
+
+The installed_versions() method was added in DBI 1.38.
+
+=item C<data_sources>
+
+  @ary = DBI->data_sources($driver);
+  @ary = DBI->data_sources($driver, \%attr);
+
+Returns a list of data sources (databases) available via the named
+driver.  If C<$driver> is empty or C<undef>, then the value of the
+C<DBI_DRIVER> environment variable is used.
+
+The driver will be loaded if it hasn't been already. Note that if the
+driver loading fails then data_sources() I<dies> with an error message
+that includes the string "C<install_driver>" and the underlying problem.
+
+Data sources are returned in a form suitable for passing to the
+L</connect> method (that is, they will include the "C<dbi:$driver:>" prefix).
+
+Note that many drivers have no way of knowing what data sources might
+be available for it. These drivers return an empty or incomplete list
+or may require driver-specific attributes.
+
+There is also a data_sources() method defined for database handles.
+
+
+=item C<trace>
+
+  DBI->trace($trace_setting)
+  DBI->trace($trace_setting, $trace_filename)
+  $trace_setting = DBI->trace;
+
+The C<DBI-E<gt>trace> method sets the I<global default> trace
+settings and returns the I<previous> trace settings. It can also
+be used to change where the trace output is sent.
+
+There's a similar method, C<$h-E<gt>trace>, which sets the trace
+settings for the specific handle it's called on.
+
+See the L</TRACING> section for full details about the DBI's powerful
+tracing facilities.
+
+=back
+
+
+=head2 DBI Utility Functions
+
+In addition to the DBI methods listed in the previous section,
+the DBI package also provides several utility functions.
+
+These can be imported into your code by listing them in
+the C<use> statement. For example:
+
+  use DBI qw(neat data_diff);
+
+Alternatively, all these utility functions (except hash) can be
+imported using the C<:utils> import tag. For example:
+
+  use DBI qw(:utils);
+
+=over 4
+
+=item C<data_string_desc>
+
+  $description = data_string_desc($string);
+
+Returns an informal description of the string. For example:
+
+  UTF8 off, ASCII, 42 characters 42 bytes
+  UTF8 off, non-ASCII, 42 characters 42 bytes
+  UTF8 on, non-ASCII, 4 characters 6 bytes
+  UTF8 on but INVALID encoding, non-ASCII, 4 characters 6 bytes
+  UTF8 off, undef
+
+The initial C<UTF8> on/off refers to Perl's internal SvUTF8 flag.
+If $string has the SvUTF8 flag set but the sequence of bytes it
+contains are not a valid UTF-8 encoding then data_string_desc()
+will report C<UTF8 on but INVALID encoding>.
+
+The C<ASCII> vs C<non-ASCII> portion shows C<ASCII> if I<all> the
+characters in the string are ASCII (have code points <= 127).
+
+The data_string_desc() function was added in DBI 1.46.
+
+=item C<data_string_diff>
+
+  $diff = data_string_diff($a, $b);
+
+Returns an informal description of the first character difference
+between the strings. If both $a and $b contain the same sequence
+of characters then data_string_diff() returns an empty string.
+For example:
+
+ Params a & b     Result
+ ------------     ------
+ 'aaa', 'aaa'     ''
+ 'aaa', 'abc'     'Strings differ at index 2: a[2]=a, b[2]=b'
+ 'aaa', undef     'String b is undef, string a has 3 characters'
+ 'aaa', 'aa'      'String b truncated after 2 characters'
+
+Unicode characters are reported in C<\x{XXXX}> format. Unicode
+code points in the range U+0800 to U+08FF are unassigned and most
+likely to occur due to double-encoding. Characters in this range
+are reported as C<\x{08XX}='C'> where C<C> is the corresponding
+latin-1 character.
+
+The data_string_diff() function only considers logical I<characters>
+and not the underlying encoding. See L</data_diff> for an alternative.
+
+The data_string_diff() function was added in DBI 1.46.
+
+=item C<data_diff>
+
+  $diff = data_diff($a, $b);
+  $diff = data_diff($a, $b, $logical);
+
+Returns an informal description of the difference between two strings.
+It calls L</data_string_desc> and L</data_string_diff>
+and returns the combined results as a multi-line string.
+
+For example, C<data_diff("abc", "ab\x{263a}")> will return:
+
+  a: UTF8 off, ASCII, 3 characters 3 bytes
+  b: UTF8 on, non-ASCII, 3 characters 5 bytes
+  Strings differ at index 2: a[2]=c, b[2]=\x{263A}
+
+If $a and $b are identical in both the characters they contain I<and>
+their physical encoding then data_diff() returns an empty string.
+If $logical is true then physical encoding differences are ignored
+(but are still reported if there is a difference in the characters).
+
+The data_diff() function was added in DBI 1.46.
+
+=item C<neat>
+
+  $str = neat($value);
+  $str = neat($value, $maxlen);
+
+Return a string containing a neat (and tidy) representation of the
+supplied value.
+
+Strings will be quoted, although internal quotes will I<not> be escaped.
+Values known to be numeric will be unquoted. Undefined (NULL) values
+will be shown as C<undef> (without quotes).
+
+If the string is flagged internally as utf8 then double quotes will
+be used, otherwise single quotes are used and unprintable characters
+will be replaced by dot (.).
+
+For result strings longer than C<$maxlen> the result string will be
+truncated to C<$maxlen-4> and "C<...'>" will be appended.  If C<$maxlen> is 0
+or C<undef>, it defaults to C<$DBI::neat_maxlen> which, in turn, defaults to 400.
+
+This function is designed to format values for human consumption.
+It is used internally by the DBI for L</trace> output. It should
+typically I<not> be used for formatting values for database use.
+(See also L</quote>.)
+
+=item C<neat_list>
+
+  $str = neat_list(\@listref, $maxlen, $field_sep);
+
+Calls C<neat> on each element of the list and returns a string
+containing the results joined with C<$field_sep>. C<$field_sep> defaults
+to C<", ">.
+
+=item C<looks_like_number>
+
+  @bool = looks_like_number(@array);
+
+Returns true for each element that looks like a number.
+Returns false for each element that does not look like a number.
+Returns C<undef> for each element that is undefined or empty.
+
+=item C<hash>
+
+  $hash_value = DBI::hash($buffer, $type);
+
+Return a 32-bit integer 'hash' value corresponding to the contents of $buffer.
+The $type parameter selects which kind of hash algorithm should be used.
+
+For the technically curious, type 0 (which is the default if $type
+isn't specified) is based on the Perl 5.1 hash except that the value
+is forced to be negative (for obscure historical reasons).
+Type 1 is the better "Fowler / Noll / Vo" (FNV) hash. See
+L<http://www.isthe.com/chongo/tech/comp/fnv/> for more information.
+Both types are implemented in C and are very fast.
+
+This function doesn't have much to do with databases, except that
+it can be handy to store hash values in a database.
+
+=back
+
+
+=head2 DBI Dynamic Attributes
+
+Dynamic attributes are always associated with the I<last handle used>
+(that handle is represented by C<$h> in the descriptions below).
+
+Where an attribute is equivalent to a method call, then refer to
+the method call for all related documentation.
+
+Warning: these attributes are provided as a convenience but they
+do have limitations. Specifically, they have a short lifespan:
+because they are associated with
+the last handle used, they should only be used I<immediately> after
+calling the method that "sets" them.
+If in any doubt, use the corresponding method call.
+
+=over 4
+
+=item C<$DBI::err>
+
+Equivalent to C<$h-E<gt>err>.
+
+=item C<$DBI::errstr>
+
+Equivalent to C<$h-E<gt>errstr>.
+
+=item C<$DBI::state>
+
+Equivalent to C<$h-E<gt>state>.
+
+=item C<$DBI::rows>
+
+Equivalent to C<$h-E<gt>rows>. Please refer to the documentation
+for the L</rows> method.
+
+=item C<$DBI::lasth>
+
+Returns the DBI object handle used for the most recent DBI method call.
+If the last DBI method call was a DESTROY then $DBI::lasth will return
+the handle of the parent of the destroyed handle, if there is one.
+
+=back
+
+
+=head1 METHODS COMMON TO ALL HANDLES
+
+The following methods can be used by all types of DBI handles.
+
+=over 4
+
+=item C<err>
+
+  $rv = $h->err;
+
+Returns the I<native> database engine error code from the last driver
+method called. The code is typically an integer but you should not
+assume that.
+
+The DBI resets $h->err to undef before most DBI method calls, so the
+value only has a short lifespan. Also, for most drivers, the statement
+handles share the same error variable as the parent database handle,
+so calling a method on one handle may reset the error on the
+related handles.
+
+If you need to test for individual errors I<and> have your program be
+portable to different database engines, then you'll need to determine
+what the corresponding error codes are for all those engines and test for
+all of them.
+
+A driver may return C<0> from err() to indicate a warning condition
+after a method call. Similarly, a driver may return an empty string
+to indicate a 'success with information' condition. In both these
+cases the value is false but not undef. The errstr() and state()
+methods may be used to retrieve extra information in these cases.
+
+See L</set_err> for more information.
+
+=item C<errstr>
+
+  $str = $h->errstr;
+
+Returns the native database engine error message from the last DBI
+method called. This has the same lifespan issues as the L</err> method
+described above.
+
+The returned string may contain multiple messages separated by
+newline characters.
+
+The errstr() method should not be used to test for errors, use err()
+for that, because drivers may return 'success with information' or
+warning messages via errstr() for methods that have not 'failed'.
+
+See L</set_err> for more information.
+
+=item C<state>
+
+  $str = $h->state;
+
+Returns a state code in the standard SQLSTATE five character format.
+Note that the specific success code C<00000> is translated to any empty string
+(false). If the driver does not support SQLSTATE (and most don't),
+then state will return C<S1000> (General Error) for all errors.
+
+The driver is free to return any value via C<state>, e.g., warning
+codes, even if it has not declared an error by returning a true value
+via the L</err> method described above.
+
+The state() method should not be used to test for errors, use err()
+for that, because drivers may return a 'success with information' or
+warning state code via errstr() for methods that have not 'failed'.
+
+=item C<set_err>
+
+  $rv = $h->set_err($err, $errstr);
+  $rv = $h->set_err($err, $errstr, $state);
+  $rv = $h->set_err($err, $errstr, $state, $method);
+  $rv = $h->set_err($err, $errstr, $state, $method, $rv);
+
+Set the C<err>, C<errstr>, and C<state> values for the handle.
+This method is typically only used by DBI drivers and DBI subclasses.
+
+If the L</HandleSetErr> attribute holds a reference to a subroutine
+it is called first. The subroutine can alter the $err, $errstr, $state,
+and $method values. See L</HandleSetErr> for full details.
+If the subroutine returns a true value then the handle C<err>,
+C<errstr>, and C<state> values are not altered and set_err() returns
+an empty list (it normally returns $rv which defaults to undef, see below).
+
+Setting C<err> to a I<true> value indicates an error and will trigger
+the normal DBI error handling mechanisms, such as C<RaiseError> and
+C<HandleError>, if they are enabled, when execution returns from
+the DBI back to the application.
+
+Setting C<err> to C<""> indicates an 'information' state, and setting
+it to C<"0"> indicates a 'warning' state. Setting C<err> to C<undef>
+also sets C<errstr> to undef, and C<state> to C<"">, irrespective
+of the values of the $errstr and $state parameters.
+
+The $method parameter provides an alternate method name for the
+C<RaiseError>/C<PrintError>/C<PrintWarn> error string instead of
+the fairly unhelpful 'C<set_err>'.
+
+The C<set_err> method normally returns undef.  The $rv parameter
+provides an alternate return value.
+
+Some special rules apply if the C<err> or C<errstr>
+values for the handle are I<already> set...
+
+If C<errstr> is true then: "C< [err was %s now %s]>" is appended if
+$err is true and C<err> is already true; "C< [state was %s now %s]>"
+is appended if $state is true and C<state> is already true; then
+"C<\n>" and the new $errstr are appended. Obviously the C<%s>'s
+above are replaced by the corresponding values.
+
+The handle C<err> value is set to $err if: $err is true; or handle
+C<err> value is undef; or $err is defined and the length is greater
+than the handle C<err> length. The effect is that an 'information'
+state only overrides undef; a 'warning' overrides undef or 'information',
+and an 'error' state overrides anything.
+
+The handle C<state> value is set to $state if $state is true and
+the handle C<err> value was set (by the rules above).
+
+Support for warning and information states was added in DBI 1.41.
+
+=item C<trace>
+
+  $h->trace($trace_settings);
+  $h->trace($trace_settings, $trace_filename);
+  $trace_settings = $h->trace;
+
+The trace() method is used to alter the trace settings for a handle
+(and any future children of that handle).  It can also be used to
+change where the trace output is sent.
+
+There's a similar method, C<DBI-E<gt>trace>, which sets the global
+default trace settings.
+
+See the L</TRACING> section for full details about the DBI's powerful
+tracing facilities.
+
+=item C<trace_msg>
+
+  $h->trace_msg($message_text);
+  $h->trace_msg($message_text, $min_level);
+
+Writes C<$message_text> to the trace file if the trace level is
+greater than or equal to $min_level (which defaults to 1).
+Can also be called as C<DBI-E<gt>trace_msg($msg)>.
+
+See L</TRACING> for more details.
+
+=item C<func>
+
+  $h->func(@func_arguments, $func_name) or die ...;
+
+The C<func> method can be used to call private non-standard and
+non-portable methods implemented by the driver. Note that the function
+name is given as the I<last> argument.
+
+It's also important to note that the func() method does not clear
+a previous error ($DBI::err etc.) and it does not trigger automatic
+error detection (RaiseError etc.) so you must check the return
+status and/or $h->err to detect errors.
+
+(This method is not directly related to calling stored procedures.
+Calling stored procedures is currently not defined by the DBI.
+Some drivers, such as DBD::Oracle, support it in non-portable ways.
+See driver documentation for more details.)
+
+See also L</install_method> for how you can avoid needing to
+use func() and gain.
+
+=item C<can>
+
+  $is_implemented = $h->can($method_name);
+
+Returns true if $method_name is implemented by the driver or a
+default method is provided by the DBI.
+It returns false where a driver hasn't implemented a method and the
+default method is provided by the DBI is just an empty stub.
+
+=item C<parse_trace_flags>
+
+  $trace_settings_integer = $h->parse_trace_flags($trace_settings);
+
+Parses a string containing trace settings and returns the corresponding
+integer value used internally by the DBI and drivers.
+
+The $trace_settings argument is a string containing a trace level
+between 0 and 15 and/or trace flag names separated by vertical bar
+("C<|>") or comma ("C<,>") characters. For example: C<"SQL|3|foo">.
+
+It uses the parse_trace_flag() method, described below, to process
+the individual trage flag names.
+
+The parse_trace_flags() method was added in DBI 1.42.
+
+=item C<parse_trace_flag>
+
+  $bit_flag = $h->parse_trace_flag($trace_flag_name);
+
+Returns the bit flag corresponding to the trace flag name in
+$trace_flag_name.  Drivers are expected to override this method and
+check if $trace_flag_name is a driver specific trace flags and, if
+not, then call the DBIs default parse_trace_flag().
+
+The parse_trace_flag() method was added in DBI 1.42.
+
+=item C<swap_inner_handle>
+
+  $rc = $h1->swap_inner_handle( $h2 );
+  $rc = $h1->swap_inner_handle( $h2, $allow_reparent );
+
+Brain transplants for handles. You don't need to know about this
+unless you want to become a handle surgeon.
+
+A DBI handle is a reference to a tied hash. A tied hash has an
+I<inner> hash that actually holds the contents.  The swap_inner_handle()
+method swaps the inner hashes between two handles. The $h1 and $h2
+handles still point to the same tied hashes, but what those hashes
+are tied to has been swapped.  In effect $h1 I<becomes> $h2 and
+vice-versa. This is powerful stuff. Use with care.
+
+As a small safety measure, the two handles, $h1 and $h2, have to
+share the same parent unless $allow_reparent is true.
+
+The swap_inner_handle() method was added in DBI 1.44.
+
+=back
+
+
+=head1 ATTRIBUTES COMMON TO ALL HANDLES
+
+These attributes are common to all types of DBI handles.
+
+Some attributes are inherited by child handles. That is, the value
+of an inherited attribute in a newly created statement handle is the
+same as the value in the parent database handle. Changes to attributes
+in the new statement handle do not affect the parent database handle
+and changes to the database handle do not affect existing statement
+handles, only future ones.
+
+Attempting to set or get the value of an unknown attribute generates a warning,
+except for private driver specific attributes (which all have names
+starting with a lowercase letter).
+
+Example:
+
+  $h->{AttributeName} = ...;	# set/write
+  ... = $h->{AttributeName};	# get/read
+
+=over 4
+
+=item C<Warn> (boolean, inherited)
+
+The C<Warn> attribute enables useful warnings for certain bad
+practices. It is enabled by default and should only be disabled in
+rare circumstances.  Since warnings are generated using the Perl
+C<warn> function, they can be intercepted using the Perl C<$SIG{__WARN__}>
+hook.
+
+The C<Warn> attribute is not related to the C<PrintWarn> attribute.
+
+=item C<Active> (boolean, read-only)
+
+The C<Active> attribute is true if the handle object is "active". This is rarely used in
+applications. The exact meaning of active is somewhat vague at the
+moment. For a database handle it typically means that the handle is
+connected to a database (C<$dbh-E<gt>disconnect> sets C<Active> off).  For
+a statement handle it typically means that the handle is a C<SELECT>
+that may have more data to fetch. (Fetching all the data or calling C<$sth-E<gt>finish>
+sets C<Active> off.)
+
+=item C<Executed> (boolean)
+
+The C<Executed> attribute is true if the handle object has been "executed".
+Currently only the $dbh do() method and the $sth execute(), execute_array(),
+and execute_for_fetch() methods set the C<Executed> attribute.
+
+When it's set on a handle it is also set on the parent handle at the
+same time. So calling execute() on a $sth also sets the C<Executed>
+attribute on the parent $dbh.
+
+The C<Executed> attribute for a database handle is cleared by the
+commit() and rollback() methods. The C<Executed> attribute of a
+statement handle is not cleared by the DBI under any circumstances
+and so acts as a permanent record of whether the statement handle
+was ever used.
+
+The C<Executed> attribute was added in DBI 1.41.
+
+=item C<Kids> (integer, read-only)
+
+For a driver handle, C<Kids> is the number of currently existing database
+handles that were created from that driver handle.  For a database
+handle, C<Kids> is the number of currently existing statement handles that
+were created from that database handle.
+For a statement handle, the value is zero.
+
+=item C<ActiveKids> (integer, read-only)
+
+Like C<Kids>, but only counting those that are C<Active> (as above).
+
+=item C<CachedKids> (hash ref)
+
+For a database handle, C<CachedKids> returns a reference to the cache (hash) of
+statement handles created by the L</prepare_cached> method.  For a
+driver handle, returns a reference to the cache (hash) of
+database handles created by the L</connect_cached> method.
+
+=item C<CompatMode> (boolean, inherited)
+
+The C<CompatMode> attribute is used by emulation layers (such as
+Oraperl) to enable compatible behaviour in the underlying driver
+(e.g., DBD::Oracle) for this handle. Not normally set by application code.
+
+It also has the effect of disabling the 'quick FETCH' of attribute
+values from the handles attribute cache. So all attribute values
+are handled by the drivers own FETCH method. This makes them slightly
+slower but is useful for special-purpose drivers like DBD::Multiplex.
+
+=item C<InactiveDestroy> (boolean)
+
+The C<InactiveDestroy> attribute can be used to disable the I<database
+engine> related effect of DESTROYing a handle (which would normally
+close a prepared statement or disconnect from the database etc).
+The default value, false, means a handle will be fully destroyed
+when it passes out of scope.
+
+For a database handle, this attribute does not disable an I<explicit>
+call to the disconnect method, only the implicit call from DESTROY
+that happens if the handle is still marked as C<Active>.
+
+Think of the name as meaning 'treat the handle as not-Active in the
+DESTROY method'.
+
+This attribute is specifically designed for use in Unix applications
+that "fork" child processes. Either the parent or the child process,
+but not both, should set C<InactiveDestroy> on all their shared handles.
+Note that some databases, including Oracle, don't support passing a
+database connection across a fork.
+
+To help tracing applications using fork the process id is shown in
+the trace log whenever a DBI or handle trace() method is called.
+The process id also shown for I<every> method call if the DBI trace
+level (not handle trace level) is set high enough to show the trace
+from the DBI's method dispatcher, e.g. >= 9.
+
+=item C<PrintWarn> (boolean, inherited)
+
+The C<PrintWarn> attribute controls the printing of warnings recorded
+by the driver.  When set to a true value the DBI will check method
+calls to see if a warning condition has been set. If so, the DBI
+will effectively do a C<warn("$class $method warning: $DBI::errstr")>
+where C<$class> is the driver class and C<$method> is the name of
+the method which failed. E.g.,
+
+  DBD::Oracle::db execute warning: ... warning text here ...
+
+By default, C<DBI-E<gt>connect> sets C<PrintWarn> "on" if $^W is true,
+i.e., perl is running with warnings enabled.
+
+If desired, the warnings can be caught and processed using a C<$SIG{__WARN__}>
+handler or modules like CGI::Carp and CGI::ErrorWrap.
+
+See also L</set_err> for how warnings are recorded and L</HandleSetErr>
+for how to influence it.
+
+Fetching the full details of warnings can require an extra round-trip
+to the database server for some drivers. In which case the driver
+may opt to only fetch the full details of warnings if the C<PrintWarn>
+attribute is true. If C<PrintWarn> is false then these drivers should
+still indicate the fact that there were warnings by setting the
+warning string to, for example: "3 warnings".
+
+=item C<PrintError> (boolean, inherited)
+
+The C<PrintError> attribute can be used to force errors to generate warnings (using
+C<warn>) in addition to returning error codes in the normal way.  When set
+"on", any method which results in an error occuring will cause the DBI to
+effectively do a C<warn("$class $method failed: $DBI::errstr")> where C<$class>
+is the driver class and C<$method> is the name of the method which failed. E.g.,
+
+  DBD::Oracle::db prepare failed: ... error text here ...
+
+By default, C<DBI-E<gt>connect> sets C<PrintError> "on".
+
+If desired, the warnings can be caught and processed using a C<$SIG{__WARN__}>
+handler or modules like CGI::Carp and CGI::ErrorWrap.
+
+=item C<RaiseError> (boolean, inherited)
+
+The C<RaiseError> attribute can be used to force errors to raise exceptions rather
+than simply return error codes in the normal way. It is "off" by default.
+When set "on", any method which results in an error will cause
+the DBI to effectively do a C<die("$class $method failed: $DBI::errstr")>,
+where C<$class> is the driver class and C<$method> is the name of the method
+that failed. E.g.,
+
+  DBD::Oracle::db prepare failed: ... error text here ...
+
+If you turn C<RaiseError> on then you'd normally turn C<PrintError> off.
+If C<PrintError> is also on, then the C<PrintError> is done first (naturally).
+
+Typically C<RaiseError> is used in conjunction with C<eval { ... }>
+to catch the exception that's been thrown and followed by an
+C<if ($@) { ... }> block to handle the caught exception.
+For example:
+
+  eval {
+    ...
+    $sth->execute();
+    ...
+  };
+  if ($@) {
+    # $sth->err and $DBI::err will be true if error was from DBI
+    warn $@; # print the error
+    ... # do whatever you need to deal with the error
+  }
+
+In that eval block the $DBI::lasth variable can be useful for
+diagnosis and reporting if you can't be sure which handle triggered
+the error.  For example, $DBI::lasth->{Type} and $DBI::lasth->{Statement}.
+
+See also L</Transactions>.
+
+If you want to temporarily turn C<RaiseError> off (inside a library function
+that is likely to fail, for example), the recommended way is like this:
+
+  {
+    local $h->{RaiseError};  # localize and turn off for this block
+    ...
+  }
+
+The original value will automatically and reliably be restored by Perl,
+regardless of how the block is exited.
+The same logic applies to other attributes, including C<PrintError>.
+
+=item C<HandleError> (code ref, inherited)
+
+The C<HandleError> attribute can be used to provide your own alternative behaviour
+in case of errors. If set to a reference to a subroutine then that
+subroutine is called when an error is detected (at the same point that
+C<RaiseError> and C<PrintError> are handled).
+
+The subroutine is called with three parameters: the error message
+string that C<RaiseError> and C<PrintError> would use,
+the DBI handle being used, and the first value being returned by
+the method that failed (typically undef).
+
+If the subroutine returns a false value then the C<RaiseError>
+and/or C<PrintError> attributes are checked and acted upon as normal.
+
+For example, to C<die> with a full stack trace for any error:
+
+  use Carp;
+  $h->{HandleError} = sub { confess(shift) };
+
+Or to turn errors into exceptions:
+
+  use Exception; # or your own favourite exception module
+  $h->{HandleError} = sub { Exception->new('DBI')->raise($_[0]) };
+
+It is possible to 'stack' multiple HandleError handlers by using
+closures:
+
+  sub your_subroutine {
+    my $previous_handler = $h->{HandleError};
+    $h->{HandleError} = sub {
+      return 1 if $previous_handler and &$previous_handler(@_);
+      ... your code here ...
+    };
+  }
+
+Using a C<my> inside a subroutine to store the previous C<HandleError>
+value is important.  See L<perlsub> and L<perlref> for more information
+about I<closures>.
+
+It is possible for C<HandleError> to alter the error message that
+will be used by C<RaiseError> and C<PrintError> if it returns false.
+It can do that by altering the value of $_[0]. This example appends
+a stack trace to all errors and, unlike the previous example using
+Carp::confess, this will work C<PrintError> as well as C<RaiseError>:
+
+  $h->{HandleError} = sub { $_[0]=Carp::longmess($_[0]); 0; };
+
+It is also possible for C<HandleError> to hide an error, to a limited
+degree, by using L</set_err> to reset $DBI::err and $DBI::errstr,
+and altering the return value of the failed method. For example:
+
+  $h->{HandleError} = sub {
+    return 0 unless $_[0] =~ /^\S+ fetchrow_arrayref failed:/;
+    return 0 unless $_[1]->err == 1234; # the error to 'hide'
+    $h->set_err(undef,undef);	# turn off the error
+    $_[2] = [ ... ];	# supply alternative return value
+    return 1;
+  };
+
+This only works for methods which return a single value and is hard
+to make reliable (avoiding infinite loops, for example) and so isn't
+recommended for general use!  If you find a I<good> use for it then
+please let me know.
+
+=item C<HandleSetErr> (code ref, inherited)
+
+The C<HandleSetErr> attribute can be used to intercept
+the setting of handle C<err>, C<errstr>, and C<state> values.
+If set to a reference to a subroutine then that subroutine is called
+whenever set_err() is called, typically by the driver or a subclass.
+
+The subroutine is called with five arguments, the first five that
+were passed to set_err(): the handle, the C<err>, C<errstr>, and
+C<state> values being set, and the method name. These can be altered
+by changing the values in the @_ array. The return value affects
+set_err() behaviour, see L</set_err> for details.
+
+It is possible to 'stack' multiple HandleSetErr handlers by using
+closures. See L</HandleError> for an example.
+
+The C<HandleSetErr> and C<HandleError> subroutines differ in subtle
+but significant ways. HandleError is only invoked at the point where
+the DBI is about to return to the application with C<err> set true.
+It's not invoked by the failure of a method that's been called by
+another DBI method.  HandleSetErr, on the other hand, is called
+whenever set_err() is called with a defined C<err> value, even if false.
+So it's not just for errors, despite the name, but also warn and info states.
+The set_err() method, and thus HandleSetErr, may be called multiple
+times within a method and is usually invoked from deep within driver code.
+
+In theory a driver can use the return value from HandleSetErr via
+set_err() to decide whether to continue or not. If set_err() returns
+an empty list, indicating that the HandleSetErr code has 'handled'
+the 'error', the driver could then continue instead of failing (if
+that's a reasonable thing to do).  This isn't excepted to be
+common and any such cases should be clearly marked in the driver
+documentation and discussed on the dbi-dev mailing list.
+
+The C<HandleSetErr> attribute was added in DBI 1.41.
+
+=item C<ErrCount> (unsigned integer)
+
+The C<ErrCount> attribute is incremented whenever the set_err()
+method records an error. It isn't incremented by warnings or
+information states. It is not reset by the DBI at any time.
+
+The C<ErrCount> attribute was added in DBI 1.41. Older drivers may
+not have been updated to use set_err() to record errors and so this
+attribute may not be incremented when using them.
+
+
+=item C<ShowErrorStatement> (boolean, inherited)
+
+The C<ShowErrorStatement> attribute can be used to cause the relevant
+Statement text to be appended to the error messages generated by
+the C<RaiseError>, C<PrintError>, and C<PrintWarn> attributes.
+Only applies to errors on statement handles
+plus the prepare(), do(), and the various C<select*()> database handle methods.
+(The exact format of the appended text is subject to change.)
+
+If C<$h-E<gt>{ParamValues}> returns a hash reference of parameter
+(placeholder) values then those are formatted and appended to the
+end of the Statement text in the error message.
+
+=item C<TraceLevel> (integer, inherited)
+
+The C<TraceLevel> attribute can be used as an alternative to the
+L</trace> method to set the DBI trace level and trace flags for a
+specific handle.  See L</TRACING> for more details.
+
+The C<TraceLevel> attribute is especially useful combined with
+C<local> to alter the trace settings for just a single block of code.
+
+=item C<FetchHashKeyName> (string, inherited)
+
+The C<FetchHashKeyName> attribute is used to specify whether the fetchrow_hashref()
+method should perform case conversion on the field names used for
+the hash keys. For historical reasons it defaults to 'C<NAME>' but
+it is recommended to set it to 'C<NAME_lc>' (convert to lower case)
+or 'C<NAME_uc>' (convert to upper case) according to your preference.
+It can only be set for driver and database handles.  For statement
+handles the value is frozen when prepare() is called.
+
+
+=item C<ChopBlanks> (boolean, inherited)
+
+The C<ChopBlanks> attribute can be used to control the trimming of trailing space
+characters from fixed width character (CHAR) fields. No other field
+types are affected, even where field values have trailing spaces.
+
+The default is false (although it is possible that the default may change).
+Applications that need specific behaviour should set the attribute as
+needed.
+
+Drivers are not required to support this attribute, but any driver which
+does not support it must arrange to return C<undef> as the attribute value.
+
+
+=item C<LongReadLen> (unsigned integer, inherited)
+
+The C<LongReadLen> attribute may be used to control the maximum
+length of 'long' type fields (LONG, BLOB, CLOB, MEMO, etc.) which the driver will
+read from the database automatically when it fetches each row of data.
+
+The C<LongReadLen> attribute only relates to fetching and reading
+long values; it is not involved in inserting or updating them.
+
+A value of 0 means not to automatically fetch any long data.
+Drivers may return undef or an empty string for long fields when
+C<LongReadLen> is 0.
+
+The default is typically 0 (zero) bytes but may vary between drivers.
+Applications fetching long fields should set this value to slightly
+larger than the longest long field value to be fetched.
+
+Some databases return some long types encoded as pairs of hex digits.
+For these types, C<LongReadLen> relates to the underlying data
+length and not the doubled-up length of the encoded string.
+
+Changing the value of C<LongReadLen> for a statement handle after it
+has been C<prepare>'d will typically have no effect, so it's common to
+set C<LongReadLen> on the C<$dbh> before calling C<prepare>.
+
+For most drivers the value used here has a direct effect on the
+memory used by the statement handle while it's active, so don't be
+too generous. If you can't be sure what value to use you could
+execute an extra select statement to determine the longest value.
+For example:
+
+  $dbh->{LongReadLen} = $dbh->selectrow_array(qq{
+      SELECT MAX(OCTET_LENGTH(long_column_name))
+      FROM table WHERE ...
+  });
+  $sth = $dbh->prepare(qq{
+      SELECT long_column_name, ... FROM table WHERE ...
+  });
+
+You may need to take extra care if the table can be modified between
+the first select and the second being executed. You may also need to
+use a different function if OCTET_LENGTH() does not work for long
+types in your database. For example, for Sybase use DATALENGTH() and
+for Oracle use LENGTHB().
+
+See also L</LongTruncOk> for information on truncation of long types.
+
+=item C<LongTruncOk> (boolean, inherited)
+
+The C<LongTruncOk> attribute may be used to control the effect of
+fetching a long field value which has been truncated (typically
+because it's longer than the value of the C<LongReadLen> attribute).
+
+By default, C<LongTruncOk> is false and so fetching a long value that
+needs to be truncated will cause the fetch to fail.
+(Applications should always be sure to
+check for errors after a fetch loop in case an error, such as a divide
+by zero or long field truncation, caused the fetch to terminate
+prematurely.)
+
+If a fetch fails due to a long field truncation when C<LongTruncOk> is
+false, many drivers will allow you to continue fetching further rows.
+
+See also L</LongReadLen>.
+
+=item C<TaintIn> (boolean, inherited)
+
+If the C<TaintIn> attribute is set to a true value I<and> Perl is running in
+taint mode (e.g., started with the C<-T> option), then all the arguments
+to most DBI method calls are checked for being tainted. I<This may change.>
+
+The attribute defaults to off, even if Perl is in taint mode.
+See L<perlsec> for more about taint mode.  If Perl is not
+running in taint mode, this attribute has no effect.
+
+When fetching data that you trust you can turn off the TaintIn attribute,
+for that statement handle, for the duration of the fetch loop.
+
+The C<TaintIn> attribute was added in DBI 1.31.
+
+=item C<TaintOut> (boolean, inherited)
+
+If the C<TaintOut> attribute is set to a true value I<and> Perl is running in
+taint mode (e.g., started with the C<-T> option), then most data fetched
+from the database is considered tainted. I<This may change.>
+
+The attribute defaults to off, even if Perl is in taint mode.
+See L<perlsec> for more about taint mode.  If Perl is not
+running in taint mode, this attribute has no effect.
+
+When fetching data that you trust you can turn off the TaintOut attribute,
+for that statement handle, for the duration of the fetch loop.
+
+Currently only fetched data is tainted. It is possible that the results
+of other DBI method calls, and the value of fetched attributes, may
+also be tainted in future versions. That change may well break your
+applications unless you take great care now. If you use DBI Taint mode,
+please report your experience and any suggestions for changes.
+
+The C<TaintOut> attribute was added in DBI 1.31.
+
+=item C<Taint> (boolean, inherited)
+
+The C<Taint> attribute is a shortcut for L</TaintIn> and L</TaintOut> (it is also present
+for backwards compatibility).
+
+Setting this attribute sets both L</TaintIn> and L</TaintOut>, and retrieving
+it returns a true value if and only if L</TaintIn> and L</TaintOut> are
+both set to true values.
+
+=item C<Profile> (inherited)
+
+The C<Profile> attribute enables the collection and reporting of method call timing statistics.
+See the L<DBI::Profile> module documentation for I<much> more detail.
+
+The C<Profile> attribute was added in DBI 1.24.
+
+=item C<private_your_module_name_*>
+
+The DBI provides a way to store extra information in a DBI handle as
+"private" attributes. The DBI will allow you to store and retrieve any
+attribute which has a name starting with "C<private_>".
+
+It is I<strongly> recommended that you use just I<one> private
+attribute (e.g., use a hash ref) I<and> give it a long and unambiguous
+name that includes the module or application name that the attribute
+relates to (e.g., "C<private_YourFullModuleName_thingy>").
+
+Because of the way the Perl tie mechanism works you cannot reliably
+use the C<||=> operator directly to initialise the attribute, like this:
+
+  my $foo = $dbh->{private_yourmodname_foo} ||= { ... }; # WRONG
+
+you should use a two step approach like this:
+
+  my $foo = $dbh->{private_yourmodname_foo};
+  $foo ||= $dbh->{private_yourmodname_foo} = { ... };
+
+This attribute is primarily of interest to people sub-classing DBI.
+
+=back
+
+
+=head1 DBI DATABASE HANDLE OBJECTS
+
+This section covers the methods and attributes associated with
+database handles.
+
+=head2 Database Handle Methods
+
+The following methods are specified for DBI database handles:
+
+=over 4
+
+=item C<clone>
+
+  $new_dbh = $dbh->clone();
+  $new_dbh = $dbh->clone(\%attr);
+
+The C<clone> method duplicates the $dbh connection by connecting
+with the same parameters ($dsn, $user, $password) as originally used.
+
+The attributes for the cloned connect are the same as those used
+for the original connect, with some other attribute merged over
+them depending on the \%attr parameter.
+
+If \%attr is given then the attributes it contains are merged into
+the original attributes and override any with the same names.
+Effectively the same as doing:
+
+  %attribues_used = ( %original_attributes, %attr );
+
+If \%attr is not given then it defaults to a hash containing all
+the attributes in the attribute cache of $dbh excluding any non-code
+references, plus the main boolean attributes (RaiseError, PrintError,
+AutoCommit, etc.). This behaviour is subject to change.
+
+The clone method can be used even if the database handle is disconnected.
+
+The C<clone> method was added in DBI 1.33. It is very new and likely
+to change.
+
+=item C<data_sources>
+
+  @ary = $dbh->data_sources();
+  @ary = $dbh->data_sources(\%attr);
+
+Returns a list of data sources (databases) available via the $dbh
+driver's data_sources() method, plus any extra data sources that
+the driver can discover via the connected $dbh. Typically the extra
+data sources are other databases managed by the same server process
+that the $dbh is connected to.
+
+Data sources are returned in a form suitable for passing to the
+L</connect> method (that is, they will include the "C<dbi:$driver:>" prefix).
+
+The data_sources() method, for a $dbh, was added in DBI 1.38.
+
+=item C<do>
+
+  $rows = $dbh->do($statement)           or die $dbh->errstr;
+  $rows = $dbh->do($statement, \%attr)   or die $dbh->errstr;
+  $rows = $dbh->do($statement, \%attr, @bind_values) or die ...
+
+Prepare and execute a single statement. Returns the number of rows
+affected or C<undef> on error. A return value of C<-1> means the
+number of rows is not known, not applicable, or not available.
+
+This method is typically most useful for I<non>-C<SELECT> statements that
+either cannot be prepared in advance (due to a limitation of the
+driver) or do not need to be executed repeatedly. It should not
+be used for C<SELECT> statements because it does not return a statement
+handle (so you can't fetch any data).
+
+The default C<do> method is logically similar to:
+
+  sub do {
+      my($dbh, $statement, $attr, @bind_values) = @_;
+      my $sth = $dbh->prepare($statement, $attr) or return undef;
+      $sth->execute(@bind_values) or return undef;
+      my $rows = $sth->rows;
+      ($rows == 0) ? "0E0" : $rows; # always return true if no error
+  }
+
+For example:
+
+  my $rows_deleted = $dbh->do(q{
+      DELETE FROM table
+      WHERE status = ?
+  }, undef, 'DONE') or die $dbh->errstr;
+
+Using placeholders and C<@bind_values> with the C<do> method can be
+useful because it avoids the need to correctly quote any variables
+in the C<$statement>. But if you'll be executing the statement many
+times then it's more efficient to C<prepare> it once and call
+C<execute> many times instead.
+
+The C<q{...}> style quoting used in this example avoids clashing with
+quotes that may be used in the SQL statement. Use the double-quote-like
+C<qq{...}> operator if you want to interpolate variables into the string.
+See L<perlop/"Quote and Quote-like Operators"> for more details.
+
+=item C<last_insert_id>
+
+  $rv = $dbh->last_insert_id($catalog, $schema, $table, $field);
+  $rv = $dbh->last_insert_id($catalog, $schema, $table, $field, \%attr);
+
+Returns a value 'identifying' the row just inserted, if possible.
+Typically this would be a value assigned by the database server
+to a column with an I<auto_increment> or I<serial> type.
+Returns undef if the driver does not support the method or can't
+determine the value.
+
+The $catalog, $schema, $table, and $field parameters may be required
+for some drivers (see below).  If you don't know the parameter values
+and your driver does not need them, then use C<undef> for each.
+
+There are several caveats to be aware of with this method if you want
+to use it for portable applications:
+
+B<*> For some drivers the value may only available immediately after
+the insert statement has executed (e.g., mysql, Informix).
+
+B<*> For some drivers the $catalog, $schema, $table, and $field parameters
+are required (e.g., Pg), for others they are ignored (e.g., mysql).
+
+B<*> Drivers may return an indeterminate value if no insert has
+been performed yet.
+
+B<*> For some drivers the value may only be available if placeholders
+have I<not> been used (e.g., Sybase, MS SQL). In this case the value
+returned would be from the last non-placeholder insert statement.
+
+B<*> Some drivers may need driver-specific hints about how to get
+the value. For example, being told the name of the database 'sequence'
+object that holds the value. Any such hints are passed as driver-specific
+attributes in the \%attr parameter.
+
+B<*> If the underlying database offers nothing better, then some
+drivers may attempt to implement this method by executing
+"C<select max($field) from $table>". Drivers using any approach
+like this should issue a warning if C<AutoCommit> is true because
+it is generally unsafe - another process may have modified the table
+between your insert and the select. For situations where you know
+it is safe, such as when you have locked the table, you can silence
+the warning by passing C<Warn> => 0 in \%attr.
+
+B<*> If no insert has been performed yet, or the last insert failed,
+then the value is implementation defined.
+
+Given all the caveats above, it's clear that this method must be
+used with care.
+
+The C<last_insert_id> method was added in DBI 1.38.
+
+=item C<selectrow_array>
+
+  @row_ary = $dbh->selectrow_array($statement);
+  @row_ary = $dbh->selectrow_array($statement, \%attr);
+  @row_ary = $dbh->selectrow_array($statement, \%attr, @bind_values);
+
+This utility method combines L</prepare>, L</execute> and
+L</fetchrow_array> into a single call. If called in a list context, it
+returns the first row of data from the statement.  The C<$statement>
+parameter can be a previously prepared statement handle, in which case
+the C<prepare> is skipped.
+
+If any method fails, and L</RaiseError> is not set, C<selectrow_array>
+will return an empty list.
+
+If called in a scalar context for a statement handle that has more
+than one column, it is undefined whether the driver will return
+the value of the first column or the last. So don't do that.
+Also, in a scalar context, an C<undef> is returned if there are no
+more rows or if an error occurred. That C<undef> can't be distinguished
+from an C<undef> returned because the first field value was NULL.
+For these reasons you should exercise some caution if you use
+C<selectrow_array> in a scalar context.
+
+
+=item C<selectrow_arrayref>
+
+  $ary_ref = $dbh->selectrow_arrayref($statement);
+  $ary_ref = $dbh->selectrow_arrayref($statement, \%attr);
+  $ary_ref = $dbh->selectrow_arrayref($statement, \%attr, @bind_values);
+
+This utility method combines L</prepare>, L</execute> and
+L</fetchrow_arrayref> into a single call. It returns the first row of
+data from the statement.  The C<$statement> parameter can be a previously
+prepared statement handle, in which case the C<prepare> is skipped.
+
+If any method fails, and L</RaiseError> is not set, C<selectrow_array>
+will return undef.
+
+
+=item C<selectrow_hashref>
+
+  $hash_ref = $dbh->selectrow_hashref($statement);
+  $hash_ref = $dbh->selectrow_hashref($statement, \%attr);
+  $hash_ref = $dbh->selectrow_hashref($statement, \%attr, @bind_values);
+
+This utility method combines L</prepare>, L</execute> and
+L</fetchrow_hashref> into a single call. It returns the first row of
+data from the statement.  The C<$statement> parameter can be a previously
+prepared statement handle, in which case the C<prepare> is skipped.
+
+If any method fails, and L</RaiseError> is not set, C<selectrow_hashref>
+will return undef.
+
+
+=item C<selectall_arrayref>
+
+  $ary_ref = $dbh->selectall_arrayref($statement);
+  $ary_ref = $dbh->selectall_arrayref($statement, \%attr);
+  $ary_ref = $dbh->selectall_arrayref($statement, \%attr, @bind_values);
+
+This utility method combines L</prepare>, L</execute> and
+L</fetchall_arrayref> into a single call. It returns a reference to an
+array containing a reference to an array for each row of data fetched.
+
+The C<$statement> parameter can be a previously prepared statement handle,
+in which case the C<prepare> is skipped. This is recommended if the
+statement is going to be executed many times.
+
+If L</RaiseError> is not set and any method except C<fetchall_arrayref>
+fails then C<selectall_arrayref> will return C<undef>; if
+C<fetchall_arrayref> fails then it will return with whatever data
+has been fetched thus far. You should check C<$sth-E<gt>err>
+afterwards (or use the C<RaiseError> attribute) to discover if the data is
+complete or was truncated due to an error.
+
+The L</fetchall_arrayref> method called by C<selectall_arrayref>
+supports a $max_rows parameter. You can specify a value for $max_rows
+by including a 'C<MaxRows>' attribute in \%attr. In which case finish()
+is called for you after fetchall_arrayref() returns.
+
+The L</fetchall_arrayref> method called by C<selectall_arrayref>
+also supports a $slice parameter. You can specify a value for $slice by
+including a 'C<Slice>' or 'C<Columns>' attribute in \%attr. The only
+difference between the two is that if C<Slice> is not defined and
+C<Columns> is an array ref, then the array is assumed to contain column
+index values (which count from 1), rather than perl array index values.
+In which case the array is copied and each value decremented before
+passing to C</fetchall_arrayref>.
+
+
+=item C<selectall_hashref>
+
+  $hash_ref = $dbh->selectall_hashref($statement, $key_field);
+  $hash_ref = $dbh->selectall_hashref($statement, $key_field, \%attr);
+  $hash_ref = $dbh->selectall_hashref($statement, $key_field, \%attr, @bind_values);
+
+This utility method combines L</prepare>, L</execute> and
+L</fetchall_hashref> into a single call. It returns a reference to a
+hash containing one entry, at most, for each row, as returned by fetchall_hashref().
+
+The C<$key_field> parameter defines which column, or columns, are used as keys
+in the returned hash. It can either be the name of a single field, or a
+reference to an array containing multiple field names. See fetchall_hashref()
+for more details.
+
+The C<$statement> parameter can be a previously prepared statement handle,
+in which case the C<prepare> is skipped. This is recommended if the
+statement is going to be executed many times.
+
+If any method except C<fetchrow_hashref> fails, and L</RaiseError> is not set,
+C<selectall_hashref> will return C<undef>.  If C<fetchrow_hashref> fails and
+L</RaiseError> is not set, then it will return with whatever data it
+has fetched thus far. $DBI::err should be checked to catch that.
+
+
+=item C<selectcol_arrayref>
+
+  $ary_ref = $dbh->selectcol_arrayref($statement);
+  $ary_ref = $dbh->selectcol_arrayref($statement, \%attr);
+  $ary_ref = $dbh->selectcol_arrayref($statement, \%attr, @bind_values);
+
+This utility method combines L</prepare>, L</execute>, and fetching one
+column from all the rows, into a single call. It returns a reference to
+an array containing the values of the first column from each row.
+
+The C<$statement> parameter can be a previously prepared statement handle,
+in which case the C<prepare> is skipped. This is recommended if the
+statement is going to be executed many times.
+
+If any method except C<fetch> fails, and L</RaiseError> is not set,
+C<selectcol_arrayref> will return C<undef>.  If C<fetch> fails and
+L</RaiseError> is not set, then it will return with whatever data it
+has fetched thus far. $DBI::err should be checked to catch that.
+
+The C<selectcol_arrayref> method defaults to pushing a single column
+value (the first) from each row into the result array. However, it can
+also push another column, or even multiple columns per row, into the
+result array. This behaviour can be specified via a 'C<Columns>'
+attribute which must be a ref to an array containing the column number
+or numbers to use. For example:
+
+  # get array of id and name pairs:
+  my $ary_ref = $dbh->selectcol_arrayref("select id, name from table", { Columns=>[1,2] });
+  my %hash = @$ary_ref; # build hash from key-value pairs so $hash{$id} => name
+
+You can specify a maximum number of rows to fetch by including a
+'C<MaxRows>' attribute in \%attr.
+
+=item C<prepare>
+
+  $sth = $dbh->prepare($statement)          or die $dbh->errstr;
+  $sth = $dbh->prepare($statement, \%attr)  or die $dbh->errstr;
+
+Prepares a statement for later execution by the database
+engine and returns a reference to a statement handle object.
+
+The returned statement handle can be used to get attributes of the
+statement and invoke the L</execute> method. See L</Statement Handle Methods>.
+
+Drivers for engines without the concept of preparing a
+statement will typically just store the statement in the returned
+handle and process it when C<$sth-E<gt>execute> is called. Such drivers are
+unlikely to give much useful information about the
+statement, such as C<$sth-E<gt>{NUM_OF_FIELDS}>, until after C<$sth-E<gt>execute>
+has been called. Portable applications should take this into account.
+
+In general, DBI drivers do not parse the contents of the statement
+(other than simply counting any L</Placeholders>). The statement is
+passed directly to the database engine, sometimes known as pass-thru
+mode. This has advantages and disadvantages. On the plus side, you can
+access all the functionality of the engine being used. On the downside,
+you're limited if you're using a simple engine, and you need to take extra care if
+writing applications intended to be portable between engines.
+
+Portable applications should not assume that a new statement can be
+prepared and/or executed while still fetching results from a previous
+statement.
+
+Some command-line SQL tools use statement terminators, like a semicolon,
+to indicate the end of a statement. Such terminators should not normally
+be used with the DBI.
+
+
+=item C<prepare_cached>
+
+  $sth = $dbh->prepare_cached($statement)
+  $sth = $dbh->prepare_cached($statement, \%attr)
+  $sth = $dbh->prepare_cached($statement, \%attr, $if_active)
+
+Like L</prepare> except that the statement handle returned will be
+stored in a hash associated with the C<$dbh>. If another call is made to
+C<prepare_cached> with the same C<$statement> and C<%attr> parameter values,
+then the corresponding cached C<$sth> will be returned without contacting the
+database server.
+
+The C<$if_active> parameter lets you adjust the behaviour if an
+already cached statement handle is still Active.  There are several
+alternatives:
+
+=over 4
+
+=item B<0>: A warning will be generated, and finish() will be called on
+the statement handle before it is returned.  This is the default
+behaviour if $if_active is not passed.
+
+=item B<1>: finish() will be called on the statement handle, but the
+warning is suppressed.
+
+=item B<2>: Disables any checking.
+
+=item B<3>: The existing active statement handle will be removed from the
+cache and a new statement handle prepared and cached in its place.
+This is the safest option because it doesn't affect the state of the
+old handle, it just removes it from the cache. [Added in DBI 1.40]
+
+=back
+
+Here are some examples of C<prepare_cached>:
+
+  sub insert_hash {
+    my ($table, $field_values) = @_;
+    my @fields = sort keys %$field_values; # sort required
+    my @values = @{$field_values}{@fields};
+    my $sql = sprintf "insert into %s (%s) values (%s)",
+	$table, join(",", @fields), join(",", ("?")x@fields);
+    my $sth = $dbh->prepare_cached($sql);
+    return $sth->execute(@values);
+  }
+
+  sub search_hash {
+    my ($table, $field_values) = @_;
+    my @fields = sort keys %$field_values; # sort required
+    my @values = @{$field_values}{@fields};
+    my $qualifier = "";
+    $qualifier = "where ".join(" and ", map { "$_=?" } @fields) if @fields;
+    $sth = $dbh->prepare_cached("SELECT * FROM $table $qualifier");
+    return $dbh->selectall_arrayref($sth, {}, @values);
+  }
+
+I<Caveat emptor:> This caching can be useful in some applications,
+but it can also cause problems and should be used with care. Here
+is a contrived case where caching would cause a significant problem:
+
+  my $sth = $dbh->prepare_cached('SELECT * FROM foo WHERE bar=?');
+  $sth->execute(...);
+  while (my $data = $sth->fetchrow_hashref) {
+
+    # later, in some other code called within the loop...
+    my $sth2 = $dbh->prepare_cached('SELECT * FROM foo WHERE bar=?');
+    $sth2->execute(...);
+    while (my $data2 = $sth2->fetchrow_arrayref) {
+      do_stuff(...);
+    }
+  }
+
+In this example, since both handles are preparing the exact same statement,
+C<$sth2> will not be its own statement handle, but a duplicate of C<$sth>
+returned from the cache. The results will certainly not be what you expect.
+Typically the the inner fetch loop will work normally, fetching all
+the records and terminating when there are no more, but now $sth
+is the same as $sth2 the outer fetch loop will also terminate.
+
+You'll know if you run into this problem because prepare_cached()
+will generate a warning by default (when $if_active is false).
+
+The cache used by prepare_cached() is keyed by both the statement
+and any attributes so you can also avoid this issue by doing something
+like:
+
+  $sth = $dbh->prepare_cached("...", { dbi_dummy => __FILE__.__LINE__ });
+
+which will ensure that prepare_cached only returns statements cached
+by that line of code in that source file. 
+
+
+=item C<commit>
+
+  $rc  = $dbh->commit     or die $dbh->errstr;
+
+Commit (make permanent) the most recent series of database changes
+if the database supports transactions and AutoCommit is off.
+
+If C<AutoCommit> is on, then calling
+C<commit> will issue a "commit ineffective with AutoCommit" warning.
+
+See also L</Transactions> in the L</FURTHER INFORMATION> section below.
+
+=item C<rollback>
+
+  $rc  = $dbh->rollback   or die $dbh->errstr;
+
+Rollback (undo) the most recent series of uncommitted database
+changes if the database supports transactions and AutoCommit is off.
+
+If C<AutoCommit> is on, then calling
+C<rollback> will issue a "rollback ineffective with AutoCommit" warning.
+
+See also L</Transactions> in the L</FURTHER INFORMATION> section below.
+
+=item C<begin_work>
+
+  $rc  = $dbh->begin_work   or die $dbh->errstr;
+
+Enable transactions (by turning C<AutoCommit> off) until the next call
+to C<commit> or C<rollback>. After the next C<commit> or C<rollback>,
+C<AutoCommit> will automatically be turned on again.
+
+If C<AutoCommit> is already off when C<begin_work> is called then
+it does nothing except return an error. If the driver does not support
+transactions then when C<begin_work> attempts to set C<AutoCommit> off
+the driver will trigger a fatal error.
+
+See also L</Transactions> in the L</FURTHER INFORMATION> section below.
+
+
+=item C<disconnect>
+
+  $rc = $dbh->disconnect  or warn $dbh->errstr;
+
+Disconnects the database from the database handle. C<disconnect> is typically only used
+before exiting the program. The handle is of little use after disconnecting.
+
+The transaction behaviour of the C<disconnect> method is, sadly,
+undefined.  Some database systems (such as Oracle and Ingres) will
+automatically commit any outstanding changes, but others (such as
+Informix) will rollback any outstanding changes.  Applications not
+using C<AutoCommit> should explicitly call C<commit> or C<rollback> before
+calling C<disconnect>.
+
+The database is automatically disconnected by the C<DESTROY> method if
+still connected when there are no longer any references to the handle.
+The C<DESTROY> method for each driver should implicitly call C<rollback> to
+undo any uncommitted changes. This is vital behaviour to ensure that
+incomplete transactions don't get committed simply because Perl calls
+C<DESTROY> on every object before exiting. Also, do not rely on the order
+of object destruction during "global destruction", as it is undefined.
+
+Generally, if you want your changes to be commited or rolled back when
+you disconnect, then you should explicitly call L</commit> or L</rollback>
+before disconnecting.
+
+If you disconnect from a database while you still have active
+statement handles (e.g., SELECT statement handles that may have
+more data to fetch), you will get a warning. The warning may indicate
+that a fetch loop terminated early, perhaps due to an uncaught error.
+To avoid the warning call the C<finish> method on the active handles.
+
+
+=item C<ping>
+
+  $rc = $dbh->ping;
+
+Attempts to determine, in a reasonably efficient way, if the database
+server is still running and the connection to it is still working.
+Individual drivers should implement this function in the most suitable
+manner for their database engine.
+
+The current I<default> implementation always returns true without
+actually doing anything. Actually, it returns "C<0 but true>" which is
+true but zero. That way you can tell if the return value is genuine or
+just the default. Drivers should override this method with one that
+does the right thing for their type of database.
+
+Few applications would have direct use for this method. See the specialized
+Apache::DBI module for one example usage.
+
+
+=item C<get_info>
+
+  $value = $dbh->get_info( $info_type );
+
+Returns information about the implementation, i.e. driver and data
+source capabilities, restrictions etc. It returns C<undef> for
+unknown or unimplemented information types. For example:
+
+  $database_version  = $dbh->get_info(  18 ); # SQL_DBMS_VER
+  $max_select_tables = $dbh->get_info( 106 ); # SQL_MAXIMUM_TABLES_IN_SELECT
+
+See L</"Standards Reference Information"> for more detailed information
+about the information types and their meanings and possible return values.
+
+The DBI::Const::GetInfoType module exports a %GetInfoType hash that
+can be used to map info type names to numbers. For example:
+
+  $database_version = $dbh->get_info( $GetInfoType{SQL_DBMS_VER} );
+
+The names are a merging of the ANSI and ODBC standards (which differ
+in some cases). See L<DBI::Const::GetInfoType> for more details.
+
+Because some DBI methods make use of get_info(), drivers are strongly
+encouraged to support I<at least> the following very minimal set
+of information types to ensure the DBI itself works properly:
+
+ Type  Name                        Example A     Example B
+ ----  --------------------------  ------------  ----------------
+   17  SQL_DBMS_NAME               'ACCESS'      'Oracle'
+   18  SQL_DBMS_VER                '03.50.0000'  '08.01.0721 ...'
+   29  SQL_IDENTIFIER_QUOTE_CHAR   '`'           '"'
+   41  SQL_CATALOG_NAME_SEPARATOR  '.'           '@'
+  114  SQL_CATALOG_LOCATION        1             2
+
+=item C<table_info>
+
+  $sth = $dbh->table_info( $catalog, $schema, $table, $type );
+  $sth = $dbh->table_info( $catalog, $schema, $table, $type, \%attr );
+
+Returns an active statement handle that can be used to fetch
+information about tables and views that exist in the database.
+
+The arguments $catalog, $schema and $table may accept search patterns
+according to the database/driver, for example: $table = '%FOO%';
+Remember that the underscore character ('C<_>') is a search pattern
+that means match any character, so 'FOO_%' is the same as 'FOO%'
+and 'FOO_BAR%' will match names like 'FOO1BAR'.
+
+The value of $type is a comma-separated list of one or more types of
+tables to be returned in the result set. Each value may optionally be
+quoted, e.g.:
+
+  $type = "TABLE";
+  $type = "'TABLE','VIEW'";
+
+In addition the following special cases may also be supported by some drivers:
+
+=over 4
+
+=item *
+If the value of $catalog is '%' and $schema and $table name
+are empty strings, the result set contains a list of catalog names.
+For example:
+
+  $sth = $dbh->table_info('%', '', '');
+
+=item *
+If the value of $schema is '%' and $catalog and $table are empty
+strings, the result set contains a list of schema names.
+
+=item *
+If the value of $type is '%' and $catalog, $schema, and $table are all
+empty strings, the result set contains a list of table types.
+
+=back
+
+If your driver doesn't support one or more of the selection filter
+parameters then you may get back more than you asked for and can
+do the filtering yourself.
+
+This method can be expensive, and can return a large amount of data.
+(For example, small Oracle installation returns over 2000 rows.)
+So it's a good idea to use the filters to limit the data as much as possible.
+
+The statement handle returned has at least the following fields in the
+order show below. Other fields, after these, may also be present.
+
+B<TABLE_CAT>: Table catalog identifier. This field is NULL (C<undef>) if not
+applicable to the data source, which is usually the case. This field
+is empty if not applicable to the table.
+
+B<TABLE_SCHEM>: The name of the schema containing the TABLE_NAME value.
+This field is NULL (C<undef>) if not applicable to data source, and
+empty if not applicable to the table.
+
+B<TABLE_NAME>: Name of the table (or view, synonym, etc).
+
+B<TABLE_TYPE>: One of the following: "TABLE", "VIEW", "SYSTEM TABLE",
+"GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM" or a type
+identifier that is specific to the data
+source.
+
+B<REMARKS>: A description of the table. May be NULL (C<undef>).
+
+Note that C<table_info> might not return records for all tables.
+Applications can use any valid table regardless of whether it's
+returned by C<table_info>.
+
+See also L</tables>, L</"Catalog Methods"> and
+L</"Standards Reference Information">.
+
+=item C<column_info>
+
+  $sth = $dbh->column_info( $catalog, $schema, $table, $column );
+
+Returns an active statement handle that can be used to fetch
+information about columns in specified tables.
+
+The arguments $schema, $table and $column may accept search patterns
+according to the database/driver, for example: $table = '%FOO%';
+
+Note: The support for the selection criteria is driver specific. If the
+driver doesn't support one or more of them then you may get back more
+than you asked for and can do the filtering yourself.
+
+The statement handle returned has at least the following fields in the
+order shown below. Other fields, after these, may also be present.
+
+B<TABLE_CAT>: The catalog identifier.
+This field is NULL (C<undef>) if not applicable to the data source,
+which is often the case.  This field is empty if not applicable to the
+table.
+
+B<TABLE_SCHEM>: The schema identifier.
+This field is NULL (C<undef>) if not applicable to the data source,
+and empty if not applicable to the table.
+
+B<TABLE_NAME>: The table identifier.
+Note: A driver may provide column metadata not only for base tables, but
+also for derived objects like SYNONYMS etc.
+
+B<COLUMN_NAME>: The column identifier.
+
+B<DATA_TYPE>: The concise data type code.
+
+B<TYPE_NAME>: A data source dependent data type name.
+
+B<COLUMN_SIZE>: The column size.
+This is the maximum length in characters for character data types,
+the number of digits or bits for numeric data types or the length
+in the representation of temporal types.
+See the relevant specifications for detailed information.
+
+B<BUFFER_LENGTH>: The length in bytes of transferred data.
+
+B<DECIMAL_DIGITS>: The total number of significant digits to the right of
+the decimal point.
+
+B<NUM_PREC_RADIX>: The radix for numeric precision.
+The value is 10 or 2 for numeric data types and NULL (C<undef>) if not
+applicable.
+
+B<NULLABLE>: Indicates if a column can accept NULLs.
+The following values are defined:
+
+  SQL_NO_NULLS          0
+  SQL_NULLABLE          1
+  SQL_NULLABLE_UNKNOWN  2
+
+B<REMARKS>: A description of the column.
+
+B<COLUMN_DEF>: The default value of the column.
+
+B<SQL_DATA_TYPE>: The SQL data type.
+
+B<SQL_DATETIME_SUB>: The subtype code for datetime and interval data types.
+
+B<CHAR_OCTET_LENGTH>: The maximum length in bytes of a character or binary
+data type column.
+
+B<ORDINAL_POSITION>: The column sequence number (starting with 1).
+
+B<IS_NULLABLE>: Indicates if the column can accept NULLs.
+Possible values are: 'NO', 'YES' and ''.
+
+SQL/CLI defines the following additional columns:
+
+  CHAR_SET_CAT
+  CHAR_SET_SCHEM
+  CHAR_SET_NAME
+  COLLATION_CAT
+  COLLATION_SCHEM
+  COLLATION_NAME
+  UDT_CAT
+  UDT_SCHEM
+  UDT_NAME
+  DOMAIN_CAT
+  DOMAIN_SCHEM
+  DOMAIN_NAME
+  SCOPE_CAT
+  SCOPE_SCHEM
+  SCOPE_NAME
+  MAX_CARDINALITY
+  DTD_IDENTIFIER
+  IS_SELF_REF
+
+Drivers capable of supplying any of those values should do so in
+the corresponding column and supply undef values for the others.
+
+Drivers wishing to provide extra database/driver specific information
+should do so in extra columns beyond all those listed above, and
+use lowercase field names with the driver-specific prefix (i.e.,
+'ora_...'). Applications accessing such fields should do so by name
+and not by column number.
+
+The result set is ordered by TABLE_CAT, TABLE_SCHEM, TABLE_NAME
+and ORDINAL_POSITION.
+
+Note: There is some overlap with statement attributes (in perl) and
+SQLDescribeCol (in ODBC). However, SQLColumns provides more metadata.
+
+See also L</"Catalog Methods"> and L</"Standards Reference Information">.
+
+=item C<primary_key_info>
+
+  $sth = $dbh->primary_key_info( $catalog, $schema, $table );
+
+Returns an active statement handle that can be used to fetch information
+about columns that make up the primary key for a table.
+The arguments don't accept search patterns (unlike table_info()).
+
+For example:
+
+  $sth = $dbh->primary_key_info( undef, $user, 'foo' );
+  $data = $sth->fetchall_arrayref;
+
+The statement handle will return one row per column, ordered by
+TABLE_CAT, TABLE_SCHEM, TABLE_NAME, and KEY_SEQ.
+If there is no primary key then the statement handle will fetch no rows.
+
+Note: The support for the selection criteria, such as $catalog, is
+driver specific.  If the driver doesn't support catalogs and/or
+schemas, it may ignore these criteria.
+
+The statement handle returned has at least the following fields in the
+order shown below. Other fields, after these, may also be present.
+
+B<TABLE_CAT>: The catalog identifier.
+This field is NULL (C<undef>) if not applicable to the data source,
+which is often the case.  This field is empty if not applicable to the
+table.
+
+B<TABLE_SCHEM>: The schema identifier.
+This field is NULL (C<undef>) if not applicable to the data source,
+and empty if not applicable to the table.
+
+B<TABLE_NAME>: The table identifier.
+
+B<COLUMN_NAME>: The column identifier.
+
+B<KEY_SEQ>: The column sequence number (starting with 1).
+Note: This field is named B<ORDINAL_POSITION> in SQL/CLI.
+
+B<PK_NAME>: The primary key constraint identifier.
+This field is NULL (C<undef>) if not applicable to the data source.
+
+See also L</"Catalog Methods"> and L</"Standards Reference Information">.
+
+=item C<primary_key>
+
+  @key_column_names = $dbh->primary_key( $catalog, $schema, $table );
+
+Simple interface to the primary_key_info() method. Returns a list of
+the column names that comprise the primary key of the specified table.
+The list is in primary key column sequence order.
+If there is no primary key then an empty list is returned.
+
+=item C<foreign_key_info>
+
+  $sth = $dbh->foreign_key_info( $pk_catalog, $pk_schema, $pk_table
+                               , $fk_catalog, $fk_schema, $fk_table );
+
+  $sth = $dbh->foreign_key_info( $pk_catalog, $pk_schema, $pk_table
+                               , $fk_catalog, $fk_schema, $fk_table
+                               , \%attr );
+
+Returns an active statement handle that can be used to fetch information
+about foreign keys in and/or referencing the specified table(s).
+The arguments don't accept search patterns (unlike table_info()).
+
+C<$pk_catalog>, C<$pk_schema>, C<$pk_table>
+identify the primary (unique) key table (B<PKT>).
+
+C<$fk_catalog>, C<$fk_schema>, C<$fk_table>
+identify the foreign key table (B<FKT>).
+
+If both B<PKT> and B<FKT> are given, the function returns the foreign key, if
+any, in table B<FKT> that refers to the primary (unique) key of table B<PKT>.
+(Note: In SQL/CLI, the result is implementation-defined.)
+
+If only B<PKT> is given, then the result set contains the primary key
+of that table and all foreign keys that refer to it.
+
+If only B<FKT> is given, then the result set contains all foreign keys
+in that table and the primary keys to which they refer.
+(Note: In SQL/CLI, the result includes unique keys too.)
+
+For example:
+
+  $sth = $dbh->foreign_key_info( undef, $user, 'master');
+  $sth = $dbh->foreign_key_info( undef, undef,   undef , undef, $user, 'detail');
+  $sth = $dbh->foreign_key_info( undef, $user, 'master', undef, $user, 'detail');
+
+Note: The support for the selection criteria, such as C<$catalog>, is
+driver specific.  If the driver doesn't support catalogs and/or
+schemas, it may ignore these criteria.
+
+The statement handle returned has the following fields in the order shown below.
+Because ODBC never includes unique keys, they define different columns in the
+result set than SQL/CLI. SQL/CLI column names are shown in parentheses.
+
+B<PKTABLE_CAT    ( UK_TABLE_CAT      )>:
+The primary (unique) key table catalog identifier.
+This field is NULL (C<undef>) if not applicable to the data source,
+which is often the case.  This field is empty if not applicable to the
+table.
+
+B<PKTABLE_SCHEM  ( UK_TABLE_SCHEM    )>:
+The primary (unique) key table schema identifier.
+This field is NULL (C<undef>) if not applicable to the data source,
+and empty if not applicable to the table.
+
+B<PKTABLE_NAME   ( UK_TABLE_NAME     )>:
+The primary (unique) key table identifier.
+
+B<PKCOLUMN_NAME  (UK_COLUMN_NAME    )>:
+The primary (unique) key column identifier.
+
+B<FKTABLE_CAT    ( FK_TABLE_CAT      )>:
+The foreign key table catalog identifier.
+This field is NULL (C<undef>) if not applicable to the data source,
+which is often the case.  This field is empty if not applicable to the
+table.
+
+B<FKTABLE_SCHEM  ( FK_TABLE_SCHEM    )>:
+The foreign key table schema identifier.
+This field is NULL (C<undef>) if not applicable to the data source,
+and empty if not applicable to the table.
+
+B<FKTABLE_NAME   ( FK_TABLE_NAME     )>:
+The foreign key table identifier.
+
+B<FKCOLUMN_NAME  ( FK_COLUMN_NAME    )>:
+The foreign key column identifier.
+
+B<KEY_SEQ        ( ORDINAL_POSITION  )>:
+The column sequence number (starting with 1).
+
+B<UPDATE_RULE    ( UPDATE_RULE       )>:
+The referential action for the UPDATE rule.
+The following codes are defined:
+
+  CASCADE              0
+  RESTRICT             1
+  SET NULL             2
+  NO ACTION            3
+  SET DEFAULT          4
+
+B<DELETE_RULE    ( DELETE_RULE       )>:
+The referential action for the DELETE rule.
+The codes are the same as for UPDATE_RULE.
+
+B<FK_NAME        ( FK_NAME           )>:
+The foreign key name.
+
+B<PK_NAME        ( UK_NAME           )>:
+The primary (unique) key name.
+
+B<DEFERRABILITY  ( DEFERABILITY      )>:
+The deferrability of the foreign key constraint.
+The following codes are defined:
+
+  INITIALLY DEFERRED   5
+  INITIALLY IMMEDIATE  6
+  NOT DEFERRABLE       7
+
+B<               ( UNIQUE_OR_PRIMARY )>:
+This column is necessary if a driver includes all candidate (i.e. primary and
+alternate) keys in the result set (as specified by SQL/CLI).
+The value of this column is UNIQUE if the foreign key references an alternate
+key and PRIMARY if the foreign key references a primary key, or it
+may be undefined if the driver doesn't have access to the information.
+
+See also L</"Catalog Methods"> and L</"Standards Reference Information">.
+
+=item C<tables>
+
+  @names = $dbh->tables( $catalog, $schema, $table, $type );
+  @names = $dbh->tables;	# deprecated
+
+Simple interface to table_info(). Returns a list of matching
+table names, possibly including a catalog/schema prefix.
+
+See L</table_info> for a description of the parameters.
+
+If C<$dbh-E<gt>get_info(29)> returns true (29 is SQL_IDENTIFIER_QUOTE_CHAR)
+then the table names are constructed and quoted by L</quote_identifier>
+to ensure they are usable even if they contain whitespace or reserved
+words etc. This means that the table names returned will include
+quote characters.
+
+=item C<type_info_all>
+
+  $type_info_all = $dbh->type_info_all;
+
+Returns a reference to an array which holds information about each data
+type variant supported by the database and driver. The array and its
+contents should be treated as read-only.
+
+The first item is a reference to an 'index' hash of C<Name =>E<gt> C<Index> pairs.
+The items following that are references to arrays, one per supported data
+type variant. The leading index hash defines the names and order of the
+fields within the arrays that follow it.
+For example:
+
+  $type_info_all = [
+    {   TYPE_NAME         => 0,
+	DATA_TYPE         => 1,
+	COLUMN_SIZE       => 2,     # was PRECISION originally
+	LITERAL_PREFIX    => 3,
+	LITERAL_SUFFIX    => 4,
+	CREATE_PARAMS     => 5,
+	NULLABLE          => 6,
+	CASE_SENSITIVE    => 7,
+	SEARCHABLE        => 8,
+	UNSIGNED_ATTRIBUTE=> 9,
+	FIXED_PREC_SCALE  => 10,    # was MONEY originally
+	AUTO_UNIQUE_VALUE => 11,    # was AUTO_INCREMENT originally
+	LOCAL_TYPE_NAME   => 12,
+	MINIMUM_SCALE     => 13,
+	MAXIMUM_SCALE     => 14,
+	SQL_DATA_TYPE     => 15,
+	SQL_DATETIME_SUB  => 16,
+	NUM_PREC_RADIX    => 17,
+	INTERVAL_PRECISION=> 18,
+    },
+    [ 'VARCHAR', SQL_VARCHAR,
+	undef, "'","'", undef,0, 1,1,0,0,0,undef,1,255, undef
+    ],
+    [ 'INTEGER', SQL_INTEGER,
+	undef,  "", "", undef,0, 0,1,0,0,0,undef,0,  0, 10
+    ],
+  ];
+
+More than one row may have the same value in the C<DATA_TYPE>
+field if there are different ways to spell the type name and/or there
+are variants of the type with different attributes (e.g., with and
+without C<AUTO_UNIQUE_VALUE> set, with and without C<UNSIGNED_ATTRIBUTE>, etc).
+
+The rows are ordered by C<DATA_TYPE> first and then by how closely each
+type maps to the corresponding ODBC SQL data type, closest first.
+
+The meaning of the fields is described in the documentation for
+the L</type_info> method.
+
+An 'index' hash is provided so you don't need to rely on index
+values defined above.  However, using DBD::ODBC with some old ODBC
+drivers may return older names, shown as comments in the example above.
+Another issue with the index hash is that the lettercase of the
+keys is not defined. It is usually uppercase, as show here, but
+drivers may return names with any lettercase.
+
+Drivers are also free to return extra driver-specific columns of
+information - though it's recommended that they start at column
+index 50 to leave room for expansion of the DBI/ODBC specification.
+
+The type_info_all() method is not normally used directly.
+The L</type_info> method provides a more usable and useful interface
+to the data.
+
+=item C<type_info>
+
+  @type_info = $dbh->type_info($data_type);
+
+Returns a list of hash references holding information about one or more
+variants of $data_type. The list is ordered by C<DATA_TYPE> first and
+then by how closely each type maps to the corresponding ODBC SQL data
+type, closest first.  If called in a scalar context then only the first
+(best) element is returned.
+
+If $data_type is undefined or C<SQL_ALL_TYPES>, then the list will
+contain hashes for all data type variants supported by the database and driver.
+
+If $data_type is an array reference then C<type_info> returns the
+information for the I<first> type in the array that has any matches.
+
+The keys of the hash follow the same letter case conventions as the
+rest of the DBI (see L</Naming Conventions and Name Space>). The
+following uppercase items should always exist, though may be undef:
+
+=over 4
+
+=item TYPE_NAME (string)
+
+Data type name for use in CREATE TABLE statements etc.
+
+=item DATA_TYPE (integer)
+
+SQL data type number.
+
+=item COLUMN_SIZE (integer)
+
+For numeric types, this is either the total number of digits (if the
+NUM_PREC_RADIX value is 10) or the total number of bits allowed in the
+column (if NUM_PREC_RADIX is 2).
+
+For string types, this is the maximum size of the string in characters.
+
+For date and interval types, this is the maximum number of characters
+needed to display the value.
+
+=item LITERAL_PREFIX (string)
+
+Characters used to prefix a literal. A typical prefix is "C<'>" for characters,
+or possibly "C<0x>" for binary values passed as hexadecimal.  NULL (C<undef>) is
+returned for data types for which this is not applicable.
+
+
+=item LITERAL_SUFFIX (string)
+
+Characters used to suffix a literal. Typically "C<'>" for characters.
+NULL (C<undef>) is returned for data types where this is not applicable.
+
+=item CREATE_PARAMS (string)
+
+Parameter names for data type definition. For example, C<CREATE_PARAMS> for a
+C<DECIMAL> would be "C<precision,scale>" if the DECIMAL type should be
+declared as C<DECIMAL(>I<precision,scale>C<)> where I<precision> and I<scale>
+are integer values.  For a C<VARCHAR> it would be "C<max length>".
+NULL (C<undef>) is returned for data types for which this is not applicable.
+
+=item NULLABLE (integer)
+
+Indicates whether the data type accepts a NULL value:
+C<0> or an empty string = no, C<1> = yes, C<2> = unknown.
+
+=item CASE_SENSITIVE (boolean)
+
+Indicates whether the data type is case sensitive in collations and
+comparisons.
+
+=item SEARCHABLE (integer)
+
+Indicates how the data type can be used in a WHERE clause, as
+follows:
+
+  0 - Cannot be used in a WHERE clause
+  1 - Only with a LIKE predicate
+  2 - All comparison operators except LIKE
+  3 - Can be used in a WHERE clause with any comparison operator
+
+=item UNSIGNED_ATTRIBUTE (boolean)
+
+Indicates whether the data type is unsigned.  NULL (C<undef>) is returned
+for data types for which this is not applicable.
+
+=item FIXED_PREC_SCALE (boolean)
+
+Indicates whether the data type always has the same precision and scale
+(such as a money type).  NULL (C<undef>) is returned for data types
+for which
+this is not applicable.
+
+=item AUTO_UNIQUE_VALUE (boolean)
+
+Indicates whether a column of this data type is automatically set to a
+unique value whenever a new row is inserted.  NULL (C<undef>) is returned
+for data types for which this is not applicable.
+
+=item LOCAL_TYPE_NAME (string)
+
+Localized version of the C<TYPE_NAME> for use in dialog with users.
+NULL (C<undef>) is returned if a localized name is not available (in which
+case C<TYPE_NAME> should be used).
+
+=item MINIMUM_SCALE (integer)
+
+The minimum scale of the data type. If a data type has a fixed scale,
+then C<MAXIMUM_SCALE> holds the same value.  NULL (C<undef>) is returned for
+data types for which this is not applicable.
+
+=item MAXIMUM_SCALE (integer)
+
+The maximum scale of the data type. If a data type has a fixed scale,
+then C<MINIMUM_SCALE> holds the same value.  NULL (C<undef>) is returned for
+data types for which this is not applicable.
+
+=item SQL_DATA_TYPE (integer)
+
+This column is the same as the C<DATA_TYPE> column, except for interval
+and datetime data types.  For interval and datetime data types, the
+C<SQL_DATA_TYPE> field will return C<SQL_INTERVAL> or C<SQL_DATETIME>, and the
+C<SQL_DATETIME_SUB> field below will return the subcode for the specific
+interval or datetime data type. If this field is NULL, then the driver
+does not support or report on interval or datetime subtypes.
+
+=item SQL_DATETIME_SUB (integer)
+
+For interval or datetime data types, where the C<SQL_DATA_TYPE>
+field above is C<SQL_INTERVAL> or C<SQL_DATETIME>, this field will
+hold the I<subcode> for the specific interval or datetime data type.
+Otherwise it will be NULL (C<undef>).
+
+Although not mentioned explicitly in the standards, it seems there
+is a simple relationship between these values:
+
+  DATA_TYPE == (10 * SQL_DATA_TYPE) + SQL_DATETIME_SUB
+
+=item NUM_PREC_RADIX (integer)
+
+The radix value of the data type. For approximate numeric types,
+C<NUM_PREC_RADIX>
+contains the value 2 and C<COLUMN_SIZE> holds the number of bits. For
+exact numeric types, C<NUM_PREC_RADIX> contains the value 10 and C<COLUMN_SIZE> holds
+the number of decimal digits. NULL (C<undef>) is returned either for data types
+for which this is not applicable or if the driver cannot report this information.
+
+=item INTERVAL_PRECISION (integer)
+
+The interval leading precision for interval types. NULL is returned
+either for data types for which this is not applicable or if the driver
+cannot report this information.
+
+=back
+
+For example, to find the type name for the fields in a select statement
+you can do:
+
+  @names = map { scalar $dbh->type_info($_)->{TYPE_NAME} } @{ $sth->{TYPE} }
+
+Since DBI and ODBC drivers vary in how they map their types into the
+ISO standard types you may need to search for more than one type.
+Here's an example looking for a usable type to store a date:
+
+  $my_date_type = $dbh->type_info( [ SQL_DATE, SQL_TIMESTAMP ] );
+
+Similarly, to more reliably find a type to store small integers, you could
+use a list starting with C<SQL_SMALLINT>, C<SQL_INTEGER>, C<SQL_DECIMAL>, etc.
+
+See also L</"Standards Reference Information">.
+
+
+=item C<quote>
+
+  $sql = $dbh->quote($value);
+  $sql = $dbh->quote($value, $data_type);
+
+Quote a string literal for use as a literal value in an SQL statement,
+by escaping any special characters (such as quotation marks)
+contained within the string and adding the required type of outer
+quotation marks.
+
+  $sql = sprintf "SELECT foo FROM bar WHERE baz = %s",
+                $dbh->quote("Don't");
+
+For most database types, quote would return C<'Don''t'> (including the
+outer quotation marks).
+
+An undefined C<$value> value will be returned as the string C<NULL> (without
+single quotation marks) to match how NULLs are represented in SQL.
+
+If C<$data_type> is supplied, it is used to try to determine the required
+quoting behaviour by using the information returned by L</type_info>.
+As a special case, the standard numeric types are optimized to return
+C<$value> without calling C<type_info>.
+
+Quote will probably I<not> be able to deal with all possible input
+(such as binary data or data containing newlines), and is not related in
+any way with escaping or quoting shell meta-characters.
+
+It is valid for the quote() method to return an SQL expression that
+evaluates to the desired string. For example:
+
+  $quoted = $dbh->quote("one\ntwo\0three")
+
+may return something like:
+
+  CONCAT('one', CHAR(12), 'two', CHAR(0), 'three')
+
+The quote() method should I<not> be used with L</"Placeholders and
+Bind Values">.
+
+=item C<quote_identifier>
+
+  $sql = $dbh->quote_identifier( $name );
+  $sql = $dbh->quote_identifier( $catalog, $schema, $table, \%attr );
+
+Quote an identifier (table name etc.) for use in an SQL statement,
+by escaping any special characters (such as double quotation marks)
+it contains and adding the required type of outer quotation marks.
+
+Undefined names are ignored and the remainder are quoted and then
+joined together, typically with a dot (C<.>) character. For example:
+
+  $id = $dbh->quote_identifier( undef, 'Her schema', 'My table' );
+
+would, for most database types, return C<"Her schema"."My table">
+(including all the double quotation marks).
+
+If three names are supplied then the first is assumed to be a
+catalog name and special rules may be applied based on what L</get_info>
+returns for SQL_CATALOG_NAME_SEPARATOR (41) and SQL_CATALOG_LOCATION (114).
+For example, for Oracle:
+
+  $id = $dbh->quote_identifier( 'link', 'schema', 'table' );
+
+would return C<"schema"."table"@"link">.
+
+=item C<take_imp_data>
+
+  $imp_data = $dbh->take_imp_data;
+
+Leaves the $dbh in an almost dead, zombie-like, state and returns
+a binary string of raw implementation data from the driver which
+describes the current database connection. Effectively it detaches
+the underlying database API connection data from the DBI handle.
+After calling take_imp_data(), all other methods except C<DESTROY>
+will generate a warning and return undef.
+
+Why would you want to do this? You don't, forget I even mentioned it.
+Unless, that is, you're implementing something advanced like a
+multi-threaded connection pool.
+
+The returned $imp_data can be passed as a C<dbi_imp_data> attribute
+to a later connect() call, even in a separate thread in the same
+process, where the driver can use it to 'adopt' the existing
+connection that the implementation data was taken from.
+
+Some things to keep in mind...
+
+B<*> the $imp_data holds the only reference to the underlying
+database API connection data. That connection is still 'live' and
+won't be cleaned up properly unless the $imp_data is used to create
+a new $dbh which can then disconnect() normally.
+
+B<*> using the same $imp_data to create more than one other new
+$dbh at a time may well lead to unpleasant problems. Don't do that.
+
+The C<take_imp_data> method was added in DBI 1.36.
+
+=back
+
+
+=head2 Database Handle Attributes
+
+This section describes attributes specific to database handles.
+
+Changes to these database handle attributes do not affect any other
+existing or future database handles.
+
+Attempting to set or get the value of an unknown attribute generates a warning,
+except for private driver-specific attributes (which all have names
+starting with a lowercase letter).
+
+Example:
+
+  $h->{AutoCommit} = ...;	# set/write
+  ... = $h->{AutoCommit};	# get/read
+
+=over 4
+
+=item C<AutoCommit>  (boolean)
+
+If true, then database changes cannot be rolled-back (undone).  If false,
+then database changes automatically occur within a "transaction", which
+must either be committed or rolled back using the C<commit> or C<rollback>
+methods.
+
+Drivers should always default to C<AutoCommit> mode (an unfortunate
+choice largely forced on the DBI by ODBC and JDBC conventions.)
+
+Attempting to set C<AutoCommit> to an unsupported value is a fatal error.
+This is an important feature of the DBI. Applications that need
+full transaction behaviour can set C<$dbh-E<gt>{AutoCommit} = 0> (or
+set C<AutoCommit> to 0 via L</connect>)
+without having to check that the value was assigned successfully.
+
+For the purposes of this description, we can divide databases into three
+categories:
+
+  Databases which don't support transactions at all.
+  Databases in which a transaction is always active.
+  Databases in which a transaction must be explicitly started (C<'BEGIN WORK'>).
+
+B<* Databases which don't support transactions at all>
+
+For these databases, attempting to turn C<AutoCommit> off is a fatal error.
+C<commit> and C<rollback> both issue warnings about being ineffective while
+C<AutoCommit> is in effect.
+
+B<* Databases in which a transaction is always active>
+
+These are typically mainstream commercial relational databases with
+"ANSI standard" transaction behaviour.
+If C<AutoCommit> is off, then changes to the database won't have any
+lasting effect unless L</commit> is called (but see also
+L</disconnect>). If L</rollback> is called then any changes since the
+last commit are undone.
+
+If C<AutoCommit> is on, then the effect is the same as if the DBI
+called C<commit> automatically after every successful database
+operation. So calling C<commit> or C<rollback> explicitly while
+C<AutoCommit> is on would be ineffective because the changes would
+have already been commited.
+
+Changing C<AutoCommit> from off to on will trigger a L</commit>.
+
+For databases which don't support a specific auto-commit mode, the
+driver has to commit each statement automatically using an explicit
+C<COMMIT> after it completes successfully (and roll it back using an
+explicit C<ROLLBACK> if it fails).  The error information reported to the
+application will correspond to the statement which was executed, unless
+it succeeded and the commit or rollback failed.
+
+B<* Databases in which a transaction must be explicitly started>
+
+For these databases, the intention is to have them act like databases in
+which a transaction is always active (as described above).
+
+To do this, the driver will automatically begin an explicit transaction
+when C<AutoCommit> is turned off, or after a L</commit> or
+L</rollback> (or when the application issues the next database
+operation after one of those events).
+
+In this way, the application does not have to treat these databases
+as a special case.
+
+See L</commit>, L</disconnect> and L</Transactions> for other important
+notes about transactions.
+
+
+=item C<Driver>  (handle)
+
+Holds the handle of the parent driver. The only recommended use for this
+is to find the name of the driver using:
+
+  $dbh->{Driver}->{Name}
+
+
+=item C<Name>  (string)
+
+Holds the "name" of the database. Usually (and recommended to be) the
+same as the "C<dbi:DriverName:...>" string used to connect to the database,
+but with the leading "C<dbi:DriverName:>" removed.
+
+
+=item C<Statement>  (string, read-only)
+
+Returns the statement string passed to the most recent L</prepare> method
+called in this database handle, even if that method failed. This is especially
+useful where C<RaiseError> is enabled and the exception handler checks $@
+and sees that a 'prepare' method call failed.
+
+
+=item C<RowCacheSize>  (integer)
+
+A hint to the driver indicating the size of the local row cache that the
+application would like the driver to use for future C<SELECT> statements.
+If a row cache is not implemented, then setting C<RowCacheSize> is ignored
+and getting the value returns C<undef>.
+
+Some C<RowCacheSize> values have special meaning, as follows:
+
+  0 - Automatically determine a reasonable cache size for each C<SELECT>
+  1 - Disable the local row cache
+ >1 - Cache this many rows
+ <0 - Cache as many rows that will fit into this much memory for each C<SELECT>.
+
+Note that large cache sizes may require a very large amount of memory
+(I<cached rows * maximum size of row>). Also, a large cache will cause
+a longer delay not only for the first fetch, but also whenever the
+cache needs refilling.
+
+See also the L</RowsInCache> statement handle attribute.
+
+=item C<Username>  (string)
+
+Returns the username used to connect to the database.
+
+
+=back
+
+
+=head1 DBI STATEMENT HANDLE OBJECTS
+
+This section lists the methods and attributes associated with DBI
+statement handles.
+
+=head2 Statement Handle Methods
+
+The DBI defines the following methods for use on DBI statement handles:
+
+=over 4
+
+=item C<bind_param>
+
+  $sth->bind_param($p_num, $bind_value)
+  $sth->bind_param($p_num, $bind_value, \%attr)
+  $sth->bind_param($p_num, $bind_value, $bind_type)
+
+The C<bind_param> method takes a copy of $bind_value and associates it
+(binds it) with a placeholder, identified by $p_num, embedded in
+the prepared statement. Placeholders are indicated with question
+mark character (C<?>). For example:
+
+  $dbh->{RaiseError} = 1;        # save having to check each method call
+  $sth = $dbh->prepare("SELECT name, age FROM people WHERE name LIKE ?");
+  $sth->bind_param(1, "John%");  # placeholders are numbered from 1
+  $sth->execute;
+  DBI::dump_results($sth);
+
+See L</"Placeholders and Bind Values"> for more information.
+
+
+B<Data Types for Placeholders>
+
+The C<\%attr> parameter can be used to hint at the data type the
+placeholder should have. Typically, the driver is only interested in
+knowing if the placeholder should be bound as a number or a string.
+
+  $sth->bind_param(1, $value, { TYPE => SQL_INTEGER });
+
+As a short-cut for the common case, the data type can be passed
+directly, in place of the C<\%attr> hash reference. This example is
+equivalent to the one above:
+
+  $sth->bind_param(1, $value, SQL_INTEGER);
+
+The C<TYPE> value indicates the standard (non-driver-specific) type for
+this parameter. To specify the driver-specific type, the driver may
+support a driver-specific attribute, such as C<{ ora_type =E<gt> 97 }>.
+
+The SQL_INTEGER and other related constants can be imported using
+
+  use DBI qw(:sql_types);
+
+See L</"DBI Constants"> for more information.
+
+The data type for a placeholder cannot be changed after the first
+C<bind_param> call. In fact the whole \%attr parameter is 'sticky'
+in the sense that a driver only needs to consider the \%attr parameter
+for the first call, for a given $sth and parameter. After that the driver
+may ignore the \%attr parameter for that placeholder.
+
+Perl only has string and number scalar data types. All database types
+that aren't numbers are bound as strings and must be in a format the
+database will understand except where the bind_param() TYPE attribute
+specifies a type that implies a particular format. For example, given:
+
+  $sth->bind_param(1, $value, SQL_DATETIME);
+
+the driver should expect $value to be in the ODBC standard SQL_DATETIME
+format, which is 'YYYY-MM-DD HH:MM:SS'. Similarly for SQL_DATE, SQL_TIME etc.
+
+As an alternative to specifying the data type in the C<bind_param> call,
+you can let the driver pass the value as the default type (C<VARCHAR>).
+You can then use an SQL function to convert the type within the statement.
+For example:
+
+  INSERT INTO price(code, price) VALUES (?, CONVERT(MONEY,?))
+
+The C<CONVERT> function used here is just an example. The actual function
+and syntax will vary between different databases and is non-portable.
+
+See also L</"Placeholders and Bind Values"> for more information.
+
+
+=item C<bind_param_inout>
+
+  $rc = $sth->bind_param_inout($p_num, \$bind_value, $max_len)  or die $sth->errstr;
+  $rv = $sth->bind_param_inout($p_num, \$bind_value, $max_len, \%attr)     or ...
+  $rv = $sth->bind_param_inout($p_num, \$bind_value, $max_len, $bind_type) or ...
+
+This method acts like L</bind_param>, but also enables values to be
+updated by the statement. The statement is typically
+a call to a stored procedure. The C<$bind_value> must be passed as a
+reference to the actual value to be used.
+
+Note that unlike L</bind_param>, the C<$bind_value> variable is not
+copied when C<bind_param_inout> is called. Instead, the value in the
+variable is read at the time L</execute> is called.
+
+The additional C<$max_len> parameter specifies the minimum amount of
+memory to allocate to C<$bind_value> for the new value. If the value
+returned from the database is too
+big to fit, then the execution should fail. If unsure what value to use,
+pick a generous length, i.e., a length larger than the longest value that would ever be
+returned.  The only cost of using a larger value than needed is wasted memory.
+
+Undefined values or C<undef> are used to indicate null values.
+See also L</"Placeholders and Bind Values"> for more information.
+
+
+=item C<bind_param_array>
+
+  $rc = $sth->bind_param_array($p_num, $array_ref_or_value)
+  $rc = $sth->bind_param_array($p_num, $array_ref_or_value, \%attr)
+  $rc = $sth->bind_param_array($p_num, $array_ref_or_value, $bind_type)
+
+The C<bind_param_array> method is used to bind an array of values
+to a placeholder embedded in the prepared statement which is to be executed
+with L</execute_array>. For example:
+
+  $dbh->{RaiseError} = 1;        # save having to check each method call
+  $sth = $dbh->prepare("INSERT INTO staff (first_name, last_name, dept) VALUES(?, ?, ?)");
+  $sth->bind_param_array(1, [ 'John', 'Mary', 'Tim' ]);
+  $sth->bind_param_array(2, [ 'Booth', 'Todd', 'Robinson' ]);
+  $sth->bind_param_array(3, "SALES"); # scalar will be reused for each row
+  $sth->execute_array( { ArrayTupleStatus => \my @tuple_status } );
+
+The C<%attr> ($bind_type) argument is the same as defined for L</bind_param>.
+Refer to L</bind_param> for general details on using placeholders.
+
+(Note that bind_param_array() can I<not> be used to expand a
+placeholder into a list of values for a statement like "SELECT foo
+WHERE bar IN (?)".  A placeholder can only ever represent one value
+per execution.)
+
+Scalar values, including C<undef>, may also be bound by
+C<bind_param_array>. In which case the same value will be used for each
+L</execute> call. Driver-specific implementations may behave
+differently, e.g., when binding to a stored procedure call, some
+databases may permit mixing scalars and arrays as arguments.
+
+The default implementation provided by DBI (for drivers that have
+not implemented array binding) is to iteratively call L</execute> for
+each parameter tuple provided in the bound arrays.  Drivers may
+provide more optimized implementations using whatever bulk operation
+support the database API provides. The default driver behaviour should 
+match the default DBI behaviour, but always consult your driver
+documentation as there may be driver specific issues to consider.
+
+Note that the default implementation currently only supports non-data
+returning statements (INSERT, UPDATE, but not SELECT). Also,
+C<bind_param_array> and L</bind_param> cannot be mixed in the same
+statement execution, and C<bind_param_array> must be used with
+L</execute_array>; using C<bind_param_array> will have no effect
+for L</execute>.
+
+The C<bind_param_array> method was added in DBI 1.22.
+
+=item C<execute>
+
+  $rv = $sth->execute                or die $sth->errstr;
+  $rv = $sth->execute(@bind_values)  or die $sth->errstr;
+
+Perform whatever processing is necessary to execute the prepared
+statement.  An C<undef> is returned if an error occurs.  A successful
+C<execute> always returns true regardless of the number of rows affected,
+even if it's zero (see below). It is always important to check the
+return status of C<execute> (and most other DBI methods) for errors
+if you're not using L</RaiseError>.
+
+For a I<non>-C<SELECT> statement, C<execute> returns the number of rows
+affected, if known. If no rows were affected, then C<execute> returns
+"C<0E0>", which Perl will treat as 0 but will regard as true. Note that it
+is I<not> an error for no rows to be affected by a statement. If the
+number of rows affected is not known, then C<execute> returns -1.
+
+For C<SELECT> statements, execute simply "starts" the query within the
+database engine. Use one of the fetch methods to retrieve the data after
+calling C<execute>.  The C<execute> method does I<not> return the number of
+rows that will be returned by the query (because most databases can't
+tell in advance), it simply returns a true value.
+
+If any arguments are given, then C<execute> will effectively call
+L</bind_param> for each value before executing the statement.  Values
+bound in this way are usually treated as C<SQL_VARCHAR> types unless
+the driver can determine the correct type (which is rare), or unless
+C<bind_param> (or C<bind_param_inout>) has already been used to
+specify the type.
+
+If execute() is called on a statement handle that's still active
+($sth->{Active} is true) then it should effectively call finish()
+to tidy up the previous execution results before starting this new
+execution.
+
+=item C<execute_array>
+
+  $rv = $sth->execute_array(\%attr) or die $sth->errstr;
+  $rv = $sth->execute_array(\%attr, @bind_values) or die $sth->errstr;
+
+Execute the prepared statement once for each parameter tuple
+(group of values) provided either in the @bind_values, or by prior
+calls to L</bind_param_array>, or via a reference passed in \%attr.
+
+The execute_array() method returns the number of tuples executed,
+or C<undef> if an error occured. Like execute(), a successful
+execute_array() always returns true regardless of the number of
+tuples executed, even if it's zero.  See the C<ArrayTupleStatus>
+attribute below for how to determine the execution status for each
+tuple.
+
+Bind values for the tuples to be executed may be supplied row-wise
+by an C<ArrayTupleFetch> attribute, or else column-wise in the
+C<@bind_values> argument, or else column-wise by prior calls to
+L</bind_param_array>.
+
+Where column-wise binding is used (via the C<@bind_values> argument
+or calls to bind_param_array()) the maximum number of elements in
+any one of the bound value arrays determines the number of tuples
+executed. Placeholders with fewer values in their parameter arrays
+are treated as if padded with undef (NULL) values.
+
+If a scalar value is bound, instead of an array reference, it is
+treated as a I<variable> length array with all elements having the
+same value. It's does not influence the number of tuples executed,
+so if all bound arrays have zero elements then zero tuples will
+be executed. If I<all> bound values are scalars then one tuple
+will be executed, making execute_array() act just like execute().
+
+The C<ArrayTupleFetch> attribute can be used to specify a reference
+to a subroutine that will be called to provide the bind values for
+each tuple execution. The subroutine should return an reference to
+an array which contains the appropriate number of bind values, or
+return an undef if there is no more data to execute.
+
+As a convienience, the C<ArrayTupleFetch> attribute can also be
+used to specify a statement handle. In which case the fetchrow_arrayref()
+method will be called on the given statement handle in order to
+provide the bind values for each tuple execution.
+
+The values specified via bind_param_array() or the @bind_values
+parameter may be either scalars, or arrayrefs.  If any C<@bind_values>
+are given, then C<execute_array> will effectively call L</bind_param_array>
+for each value before executing the statement.  Values bound in
+this way are usually treated as C<SQL_VARCHAR> types unless the
+driver can determine the correct type (which is rare), or unless
+C<bind_param>, C<bind_param_inout>, C<bind_param_array>, or
+C<bind_param_inout_array> has already been used to specify the type.
+See L</bind_param_array> for details.
+
+The mandatory C<ArrayTupleStatus> attribute is used to specify a
+reference to an array which will receive the execute status of each
+executed parameter tuple.
+
+For tuples which are successfully executed, the element at the same
+ordinal position in the status array is the resulting rowcount.
+If the execution of a tuple causes an error, then the corresponding
+status array element will be set to a reference to an array containing
+the error code and error string set by the failed execution.
+
+If B<any> tuple execution returns an error, C<execute_array> will
+return C<undef>. In that case, the application should inspect the
+status array to determine which parameter tuples failed.
+Some databases may not continue executing tuples beyond the first
+failure. In this case the status array will either hold fewer
+elements, or the elements beyond the failure will be undef.
+
+If all parameter tuples are successfully executed, C<execute_array>
+returns the number tuples executed.  If no tuples were executed,
+then execute_array() returns "C<0E0>", just like execute() does,
+which Perl will treat as 0 but will regard as true.
+
+For example:
+
+  $sth = $dbh->prepare("INSERT INTO staff (first_name, last_name) VALUES (?, ?)");
+  my $tuples = $sth->execute_array(
+      { ArrayTupleStatus => \my @tuple_status },
+      \@first_names,
+      \@last_names,
+  );
+  if ($tuples) {
+      print "Successfully inserted $tuples records\n";
+  }
+  else {
+      for my $tuple (0..@last_names-1) {
+          my $status = $tuple_status[$tuple];
+          $status = [0, "Skipped"] unless defined $status;
+          next unless ref $status;
+          printf "Failed to insert (%s, %s): %s\n",
+              $first_names[$tuple], $last_names[$tuple], $status->[1];
+      }
+  }
+
+Support for data returning statements such as SELECT is driver-specific
+and subject to change. At present, the default implementation
+provided by DBI only supports non-data returning statements.
+
+Transaction semantics when using array binding are driver and
+database specific.  If C<AutoCommit> is on, the default DBI
+implementation will cause each parameter tuple to be inidividually
+committed (or rolled back in the event of an error). If C<AutoCommit>
+is off, the application is responsible for explicitly committing
+the entire set of bound parameter tuples.  Note that different
+drivers and databases may have different behaviours when some
+parameter tuples cause failures. In some cases, the driver or
+database may automatically rollback the effect of all prior parameter
+tuples that succeeded in the transaction; other drivers or databases
+may retain the effect of prior successfully executed parameter
+tuples. Be sure to check your driver and database for its specific
+behaviour.
+
+Note that, in general, performance will usually be better with
+C<AutoCommit> turned off, and using explicit C<commit> after each
+C<execute_array> call.
+
+The C<execute_array> method was added in DBI 1.22, and ArrayTupleFetch
+was added in 1.36.
+
+=item C<execute_for_fetch>
+
+  $rc = $sth->execute_for_fetch($fetch_tuple_sub);
+  $rc = $sth->execute_for_fetch($fetch_tuple_sub, \@tuple_status);
+
+The execute_for_fetch() method is used to perform bulk operations
+and is most often used via the execute_array() method, not directly.
+
+The fetch subroutine, referenced by $fetch_tuple_sub, is expected
+to return a reference to an array (known as a 'tuple') or undef.
+
+The execute_for_fetch() method calls $fetch_tuple_sub, without any
+parameters, until it returns a false value. Each tuple returned is
+used to provide bind values for an $sth->execute(@$tuple) call.
+
+If there were any errors then C<undef> is returned and the @tuple_status
+array can be used to discover which tuples failed and with what errors.
+If there were no errors then execute_for_fetch() returns the number
+of tuples executed. Like execute() and execute_array() a zero is
+returned as "0E0" so execute_for_fetch() is only false on error.
+
+If \@tuple_status is passed then the execute_for_fetch method uses
+it to return status information. The tuple_status array holds one
+element per tuple. If the corresponding execute() did not fail then
+the element holds the return value from execute(), which is typically
+a row count. If the execute() did fail then the element holds a
+reference to an array containing ($sth->err, $sth->errstr, $sth->state).
+
+Although each tuple returned by $fetch_tuple_sub is effectively used
+to call $sth->execute(@$tuple_array_ref) the exact timing may vary.
+Drivers are free to accumulate sets of tuples to pass to the
+database server in bulk group operations for more efficient execution.
+However, the $fetch_tuple_sub is specifically allowed to return
+the same array reference each time (which is what fetchrow_arrayref()
+usually does).
+
+For example:
+
+  my $sel = $dbh1->prepare("select foo, bar from table1");
+  $sel->execute;
+
+  my $ins = $dbh2->prepare("insert into table2 (foo, bar) values (?,?)");
+  my $fetch_tuple_sub = sub { $sel->fetchrow_arrayref };
+
+  my @tuple_status;
+  $rc = $ins->execute_for_fetch($fetch_tuple_sub, \@tuple_status);
+  my @errors = grep { ref $_ } @tuple_status;
+
+Similarly, if you already have an array containing the data rows
+to be processed you'd use a subroutine to shift off and return
+each array ref in turn:
+
+  $ins->execute_for_fetch( sub { shift @array_of_arrays }, \@tuple_status);
+
+The C<execute_for_fetch> method was added in DBI 1.38.
+
+
+=item C<fetchrow_arrayref>
+
+  $ary_ref = $sth->fetchrow_arrayref;
+  $ary_ref = $sth->fetch;    # alias
+
+Fetches the next row of data and returns a reference to an array
+holding the field values.  Null fields are returned as C<undef>
+values in the array.
+This is the fastest way to fetch data, particularly if used with
+C<$sth-E<gt>bind_columns>.
+
+If there are no more rows or if an error occurs, then C<fetchrow_arrayref>
+returns an C<undef>. You should check C<$sth-E<gt>err> afterwards (or use the
+C<RaiseError> attribute) to discover if the C<undef> returned was due to an
+error.
+
+Note that the same array reference is returned for each fetch, so don't
+store the reference and then use it after a later fetch.  Also, the
+elements of the array are also reused for each row, so take care if you
+want to take a reference to an element. See also L</bind_columns>.
+
+=item C<fetchrow_array>
+
+ @ary = $sth->fetchrow_array;
+
+An alternative to C<fetchrow_arrayref>. Fetches the next row of data
+and returns it as a list containing the field values.  Null fields
+are returned as C<undef> values in the list.
+
+If there are no more rows or if an error occurs, then C<fetchrow_array>
+returns an empty list. You should check C<$sth-E<gt>err> afterwards (or use
+the C<RaiseError> attribute) to discover if the empty list returned was
+due to an error.
+
+If called in a scalar context for a statement handle that has more
+than one column, it is undefined whether the driver will return
+the value of the first column or the last. So don't do that.
+Also, in a scalar context, an C<undef> is returned if there are no
+more rows or if an error occurred. That C<undef> can't be distinguished
+from an C<undef> returned because the first field value was NULL.
+For these reasons you should exercise some caution if you use
+C<fetchrow_array> in a scalar context.
+
+=item C<fetchrow_hashref>
+
+ $hash_ref = $sth->fetchrow_hashref;
+ $hash_ref = $sth->fetchrow_hashref($name);
+
+An alternative to C<fetchrow_arrayref>. Fetches the next row of data
+and returns it as a reference to a hash containing field name and field
+value pairs.  Null fields are returned as C<undef> values in the hash.
+
+If there are no more rows or if an error occurs, then C<fetchrow_hashref>
+returns an C<undef>. You should check C<$sth-E<gt>err> afterwards (or use the
+C<RaiseError> attribute) to discover if the C<undef> returned was due to an
+error.
+
+The optional C<$name> parameter specifies the name of the statement handle
+attribute. For historical reasons it defaults to "C<NAME>", however using either
+"C<NAME_lc>" or "C<NAME_uc>" is recomended for portability.
+
+The keys of the hash are the same names returned by C<$sth-E<gt>{$name}>. If
+more than one field has the same name, there will only be one entry in
+the returned hash for those fields.
+
+Because of the extra work C<fetchrow_hashref> and Perl have to perform, it
+is not as efficient as C<fetchrow_arrayref> or C<fetchrow_array>.
+
+By default a reference to a new hash is returned for each row.
+It is likely that a future version of the DBI will support an
+attribute which will enable the same hash to be reused for each
+row. This will give a significant performance boost, but it won't
+be enabled by default because of the risk of breaking old code.
+
+
+=item C<fetchall_arrayref>
+
+  $tbl_ary_ref = $sth->fetchall_arrayref;
+  $tbl_ary_ref = $sth->fetchall_arrayref( $slice );
+  $tbl_ary_ref = $sth->fetchall_arrayref( $slice, $max_rows  );
+
+The C<fetchall_arrayref> method can be used to fetch all the data to be
+returned from a prepared and executed statement handle. It returns a
+reference to an array that contains one reference per row.
+
+If there are no rows to return, C<fetchall_arrayref> returns a reference
+to an empty array. If an error occurs, C<fetchall_arrayref> returns the
+data fetched thus far, which may be none.  You should check C<$sth-E<gt>err>
+afterwards (or use the C<RaiseError> attribute) to discover if the data is
+complete or was truncated due to an error.
+
+If $slice is an array reference, C<fetchall_arrayref> uses L</fetchrow_arrayref>
+to fetch each row as an array ref. If the $slice array is not empty
+then it is used as a slice to select individual columns by perl array
+index number (starting at 0, unlike column and parameter numbers which
+start at 1).
+
+With no parameters, or if $slice is undefined, C<fetchall_arrayref>
+acts as if passed an empty array ref.
+
+If $slice is a hash reference, C<fetchall_arrayref> uses L</fetchrow_hashref>
+to fetch each row as a hash reference. If the $slice hash is empty then
+fetchrow_hashref() is simply called in a tight loop and the keys in the hashes
+have whatever name lettercase is returned by default from fetchrow_hashref.
+(See L</FetchHashKeyName> attribute.) If the $slice hash is not
+empty, then it is used as a slice to select individual columns by
+name.  The values of the hash should be set to 1.  The key names
+of the returned hashes match the letter case of the names in the
+parameter hash, regardless of the L</FetchHashKeyName> attribute.
+
+For example, to fetch just the first column of every row:
+
+  $tbl_ary_ref = $sth->fetchall_arrayref([0]);
+
+To fetch the second to last and last column of every row:
+
+  $tbl_ary_ref = $sth->fetchall_arrayref([-2,-1]);
+
+To fetch all fields of every row as a hash ref:
+
+  $tbl_ary_ref = $sth->fetchall_arrayref({});
+
+To fetch only the fields called "foo" and "bar" of every row as a hash ref
+(with keys named "foo" and "BAR"):
+
+  $tbl_ary_ref = $sth->fetchall_arrayref({ foo=>1, BAR=>1 });
+
+The first two examples return a reference to an array of array refs.
+The third and forth return a reference to an array of hash refs.
+
+If $max_rows is defined and greater than or equal to zero then it
+is used to limit the number of rows fetched before returning.
+fetchall_arrayref() can then be called again to fetch more rows.
+This is especially useful when you need the better performance of
+fetchall_arrayref() but don't have enough memory to fetch and return
+all the rows in one go. Here's an example:
+
+  my $rows = []; # cache for batches of rows
+  while( my $row = ( shift(@$rows) || # get row from cache, or reload cache:
+                     shift(@{$rows=$sth->fetchall_arrayref(undef,10_000)||[]}) )
+  ) {
+    ...
+  }
+
+That can be the fastest way to fetch and process lots of rows using the DBI,
+but it depends on the relative cost of method calls vs memory allocation.
+
+A standard C<while> loop with column binding is often faster because
+the cost of allocating memory for the batch of rows is greater than
+the saving by reducing method calls. It's possible that the DBI may
+provide a way to reuse the memory of a previous batch in future, which
+would then shift the balance back towards fetchall_arrayref().
+
+
+=item C<fetchall_hashref>
+
+  $hash_ref = $sth->fetchall_hashref($key_field);
+
+The C<fetchall_hashref> method can be used to fetch all the data to be
+returned from a prepared and executed statement handle. It returns a reference
+to a hash containing a key for each distinct value of the $key_field column
+that was fetched For each key the corresponding value is a reference to a hash
+containing all the selected columns and their values, as returned by fetchrow_hashref().
+
+If there are no rows to return, C<fetchall_hashref> returns a reference
+to an empty hash. If an error occurs, C<fetchall_hashref> returns the
+data fetched thus far, which may be none.  You should check
+C<$sth-E<gt>err> afterwards (or use the C<RaiseError> attribute) to
+discover if the data is complete or was truncated due to an error.
+
+The $key_field parameter provides the name of the field that holds the
+value to be used for the key for the returned hash.  For example:
+
+  $dbh->{FetchHashKeyName} = 'NAME_lc';
+  $sth = $dbh->prepare("SELECT FOO, BAR, ID, NAME, BAZ FROM TABLE");
+  $sth->execute;
+  $hash_ref = $sth->fetchall_hashref('id');
+  print "Name for id 42 is $hash_ref->{42}->{name}\n";
+
+The $key_field parameter can also be specified as an integer column
+number (counting from 1).  If $key_field doesn't match any column in
+the statement, as a name first then as a number, then an error is
+returned.
+
+For queries returing more than one 'key' column, you can specify
+multiple column names by passing $key_field as a reference to an
+array containing one or more key column names (or index numbers).
+For example:
+
+  $sth = $dbh->prepare("SELECT foo, bar, baz FROM table");
+  $sth->execute;
+  $hash_ref = $sth->fetchall_hashref( [ qw(foo bar) ] );
+  print "For foo 42 and bar 38, baz is $hash_ref->{42}->{38}->{baz}\n";
+
+The fetchall_hashref() method is normally used only where the key
+fields values for each row are unique.  If multiple rows are returned
+with the same values for the key fields then later rows overwrite
+earlier ones.
+
+=item C<finish>
+
+  $rc  = $sth->finish;
+
+Indicate that no more data will be fetched from this statement handle
+before it is either executed again or destroyed.  The C<finish> method
+is rarely needed, and frequently overused, but can sometimes be
+helpful in a few very specific situations to allow the server to free
+up resources (such as sort buffers).
+
+When all the data has been fetched from a C<SELECT> statement, the
+driver should automatically call C<finish> for you. So you should
+I<not> normally need to call it explicitly I<except> when you know
+that you've not fetched all the data from a statement handle.
+The most common example is when you only want to fetch one row,
+but in that case the C<selectrow_*> methods are usually better anyway.
+Adding calls to C<finish> after each fetch loop is a common mistake,
+don't do it, it can mask genuine problems like uncaught fetch errors.
+
+Consider a query like:
+
+  SELECT foo FROM table WHERE bar=? ORDER BY foo
+
+where you want to select just the first (smallest) "foo" value from a
+very large table. When executed, the database server will have to use
+temporary buffer space to store the sorted rows. If, after executing
+the handle and selecting one row, the handle won't be re-executed for
+some time and won't be destroyed, the C<finish> method can be used to tell
+the server that the buffer space can be freed.
+
+Calling C<finish> resets the L</Active> attribute for the statement.  It
+may also make some statement handle attributes (such as C<NAME> and C<TYPE>)
+unavailable if they have not already been accessed (and thus cached).
+
+The C<finish> method does not affect the transaction status of the
+database connection.  It has nothing to do with transactions. It's mostly an
+internal "housekeeping" method that is rarely needed.
+See also L</disconnect> and the L</Active> attribute.
+
+The C<finish> method should have been called C<discard_pending_rows>.
+
+
+=item C<rows>
+
+  $rv = $sth->rows;
+
+Returns the number of rows affected by the last row affecting command,
+or -1 if the number of rows is not known or not available.
+
+Generally, you can only rely on a row count after a I<non>-C<SELECT>
+C<execute> (for some specific operations like C<UPDATE> and C<DELETE>), or
+after fetching all the rows of a C<SELECT> statement.
+
+For C<SELECT> statements, it is generally not possible to know how many
+rows will be returned except by fetching them all.  Some drivers will
+return the number of rows the application has fetched so far, but
+others may return -1 until all rows have been fetched.  So use of the
+C<rows> method or C<$DBI::rows> with C<SELECT> statements is not
+recommended.
+
+One alternative method to get a row count for a C<SELECT> is to execute a
+"SELECT COUNT(*) FROM ..." SQL statement with the same "..." as your
+query and then fetch the row count from that.
+
+
+=item C<bind_col>
+
+  $rc = $sth->bind_col($column_number, \$var_to_bind);
+  $rc = $sth->bind_col($column_number, \$var_to_bind, \%attr );
+  $rc = $sth->bind_col($column_number, \$var_to_bind, $bind_type );
+
+Binds a Perl variable and/or some attributes to an output column
+(field) of a C<SELECT> statement.  Column numbers count up from 1.
+You do not need to bind output columns in order to fetch data.
+For maximum portability between drivers, bind_col() should be called
+after execute() and not before.
+See also C<bind_columns> for an example.
+
+The binding is performed at a low level using Perl aliasing.
+Whenever a row is fetched from the database $var_to_bind appears
+to be automatically updated simply because it refers to the same
+memory location as the corresponding column value.  This makes using
+bound variables very efficient. Multiple variables can be bound
+to a single column, but there's rarely any point. Binding a tied
+variable doesn't work, currently.
+
+The L</bind_param> method
+performs a similar, but opposite, function for input variables.
+
+B<Data Types for Column Binding>
+
+The C<\%attr> parameter can be used to hint at the data type
+formatting the column should have. For example, you can use:
+
+  $sth->bind_col(1, undef, { TYPE => SQL_DATETIME });
+
+to specify that you'd like the column (which presumably is some
+kind of datetime type) to be returned in the standard format for
+SQL_DATETIME, which is 'YYYY-MM-DD HH:MM:SS', rather than the
+native formatting the database would normally use.
+
+There's no $var_to_bind in that example to emphasize the point
+that bind_col() works on the underlying column value and not just
+a particular bound variable.
+
+As a short-cut for the common case, the data type can be passed
+directly, in place of the C<\%attr> hash reference. This example is
+equivalent to the one above:
+
+  $sth->bind_col(1, undef, SQL_DATETIME);
+
+The C<TYPE> value indicates the standard (non-driver-specific) type for
+this parameter. To specify the driver-specific type, the driver may
+support a driver-specific attribute, such as C<{ ora_type =E<gt> 97 }>.
+
+The SQL_DATETIME and other related constants can be imported using
+
+  use DBI qw(:sql_types);
+
+See L</"DBI Constants"> for more information.
+
+The data type for a bind variable cannot be changed after the first
+C<bind_col> call. In fact the whole \%attr parameter is 'sticky'
+in the sense that a driver only needs to consider the \%attr parameter
+for the first call for a given $sth and column.
+
+The TYPE attribute for bind_col() was first specified in DBI 1.41.
+
+
+=item C<bind_columns>
+
+  $rc = $sth->bind_columns(@list_of_refs_to_vars_to_bind);
+
+Calls L</bind_col> for each column of the C<SELECT> statement.
+The C<bind_columns> method will die if the number of references does not
+match the number of fields.
+
+For maximum portability between drivers, bind_columns() should be called
+after execute() and not before.
+
+For example:
+
+  $dbh->{RaiseError} = 1; # do this, or check every call for errors
+  $sth = $dbh->prepare(q{ SELECT region, sales FROM sales_by_region });
+  $sth->execute;
+  my ($region, $sales);
+
+  # Bind Perl variables to columns:
+  $rv = $sth->bind_columns(\$region, \$sales);
+
+  # you can also use Perl's \(...) syntax (see perlref docs):
+  #     $sth->bind_columns(\($region, $sales));
+
+  # Column binding is the most efficient way to fetch data
+  while ($sth->fetch) {
+      print "$region: $sales\n";
+  }
+
+For compatibility with old scripts, the first parameter will be
+ignored if it is C<undef> or a hash reference.
+
+Here's a more fancy example that binds columns to the values I<inside>
+a hash (thanks to H.Merijn Brand):
+
+  $sth->execute;
+  my %row;
+  $sth->bind_columns( \( @row{ @{$sth->{NAME_lc} } } ));
+  while ($sth->fetch) {
+      print "$row{region}: $row{sales}\n";
+  }
+
+
+=item C<dump_results>
+
+  $rows = $sth->dump_results($maxlen, $lsep, $fsep, $fh);
+
+Fetches all the rows from C<$sth>, calls C<DBI::neat_list> for each row, and
+prints the results to C<$fh> (defaults to C<STDOUT>) separated by C<$lsep>
+(default C<"\n">). C<$fsep> defaults to C<", "> and C<$maxlen> defaults to 35.
+
+This method is designed as a handy utility for prototyping and
+testing queries. Since it uses L</neat_list> to
+format and edit the string for reading by humans, it is not recomended
+for data transfer applications.
+
+=back
+
+
+=head2 Statement Handle Attributes
+
+This section describes attributes specific to statement handles. Most
+of these attributes are read-only.
+
+Changes to these statement handle attributes do not affect any other
+existing or future statement handles.
+
+Attempting to set or get the value of an unknown attribute generates a warning,
+except for private driver specific attributes (which all have names
+starting with a lowercase letter).
+
+Example:
+
+  ... = $h->{NUM_OF_FIELDS};	# get/read
+
+Some drivers cannot provide valid values for some or all of these
+attributes until after C<$sth-E<gt>execute> has been successfully
+called. Typically the attribute will be C<undef> in these situations.
+
+Some attributes, like NAME, are not appropriate to some types of
+statement, like SELECT. Typically the attribute will be C<undef>
+in these situations.
+
+See also L</finish> to learn more about the effect it
+may have on some attributes.
+
+=over 4
+
+=item C<NUM_OF_FIELDS>  (integer, read-only)
+
+Number of fields (columns) in the data the prepared statement may return.
+Statements that don't return rows of data, like C<DELETE> and C<CREATE>
+set C<NUM_OF_FIELDS> to 0.
+
+
+=item C<NUM_OF_PARAMS>  (integer, read-only)
+
+The number of parameters (placeholders) in the prepared statement.
+See SUBSTITUTION VARIABLES below for more details.
+
+
+=item C<NAME>  (array-ref, read-only)
+
+Returns a reference to an array of field names for each column. The
+names may contain spaces but should not be truncated or have any
+trailing space. Note that the names have the letter case (upper, lower
+or mixed) as returned by the driver being used. Portable applications
+should use L</NAME_lc> or L</NAME_uc>.
+
+  print "First column name: $sth->{NAME}->[0]\n";
+
+=item C<NAME_lc>  (array-ref, read-only)
+
+Like L</NAME> but always returns lowercase names.
+
+=item C<NAME_uc>  (array-ref, read-only)
+
+Like L</NAME> but always returns uppercase names.
+
+=item C<NAME_hash>  (hash-ref, read-only)
+
+=item C<NAME_lc_hash>  (hash-ref, read-only)
+
+=item C<NAME_uc_hash>  (hash-ref, read-only)
+
+The C<NAME_hash>, C<NAME_lc_hash>, and C<NAME_uc_hash> attributes
+return column name information as a reference to a hash.
+
+The keys of the hash are the names of the columns.  The letter case of
+the keys corresponds to the letter case returned by the C<NAME>,
+C<NAME_lc>, and C<NAME_uc> attributes respectively (as described above).
+
+The value of each hash entry is the perl index number of the
+corresponding column (counting from 0). For example:
+
+  $sth = $dbh->prepare("select Id, Name from table");
+  $sth->execute;
+  @row = $sth->fetchrow_array;
+  print "Name $row[ $sth->{NAME_lc_hash}{name} ]\n";
+
+
+=item C<TYPE>  (array-ref, read-only)
+
+Returns a reference to an array of integer values for each
+column. The value indicates the data type of the corresponding column.
+
+The values correspond to the international standards (ANSI X3.135
+and ISO/IEC 9075) which, in general terms, means ODBC. Driver-specific
+types that don't exactly match standard types should generally return
+the same values as an ODBC driver supplied by the makers of the
+database. That might include private type numbers in ranges the vendor
+has officially registered with the ISO working group:
+
+  ftp://sqlstandards.org/SC32/SQL_Registry/
+
+Where there's no vendor-supplied ODBC driver to be compatible with,
+the DBI driver can use type numbers in the range that is now
+officially reserved for use by the DBI: -9999 to -9000.
+
+All possible values for C<TYPE> should have at least one entry in the
+output of the C<type_info_all> method (see L</type_info_all>).
+
+=item C<PRECISION>  (array-ref, read-only)
+
+Returns a reference to an array of integer values for each column.
+
+For numeric columns, the value is the maximum number of digits
+(without considering a sign character or decimal point). Note that
+the "display size" for floating point types (REAL, FLOAT, DOUBLE)
+can be up to 7 characters greater than the precision (for the
+sign + decimal point + the letter E + a sign + 2 or 3 digits).
+
+For any character type column the value is the OCTET_LENGTH,
+in other words the number of bytes, not characters.
+
+(More recent standards refer to this as COLUMN_SIZE but we stick
+with PRECISION for backwards compatibility.)
+
+=item C<SCALE>  (array-ref, read-only)
+
+Returns a reference to an array of integer values for each column.
+NULL (C<undef>) values indicate columns where scale is not applicable.
+
+=item C<NULLABLE>  (array-ref, read-only)
+
+Returns a reference to an array indicating the possibility of each
+column returning a null.  Possible values are C<0>
+(or an empty string) = no, C<1> = yes, C<2> = unknown.
+
+  print "First column may return NULL\n" if $sth->{NULLABLE}->[0];
+
+
+=item C<CursorName>  (string, read-only)
+
+Returns the name of the cursor associated with the statement handle, if
+available. If not available or if the database driver does not support the
+C<"where current of ..."> SQL syntax, then it returns C<undef>.
+
+
+=item C<Database>  (dbh, read-only)
+
+Returns the parent $dbh of the statement handle.
+
+
+=item C<ParamValues>  (hash ref, read-only)
+
+Returns a reference to a hash containing the values currently bound
+to placeholders.  The keys of the hash are the 'names' of the
+placeholders, typically integers starting at 1.  Returns undef if
+not supported by the driver.
+
+See L</ShowErrorStatement> for an example of how this is used.
+
+If the driver supports C<ParamValues> but no values have been bound
+yet then the driver should return a hash with placeholders names
+in the keys but all the values undef, but some drivers may return
+a ref to an empty hash.
+
+It is possible that the values in the hash returned by C<ParamValues>
+are not I<exactly> the same as those passed to bind_param() or execute().
+The driver may have slightly modified values in some way based on the
+TYPE the value was bound with. For example a floating point value
+bound as an SQL_INTEGER type may be returned as an integer.
+The values returned by C<ParamValues> can be passed to another
+bind_param() method with the same TYPE and will be seen by the
+database as the same value.
+
+It is also possible that the keys in the hash returned by C<ParamValues>
+are not exactly the same as those implied by the prepared statement.
+For example, DBD::Oracle translates 'C<?>' placeholders into 'C<:pN>'
+where N is a sequence number starting at 1.
+
+The C<ParamValues> attribute was added in DBI 1.28.
+
+
+=item C<Statement>  (string, read-only)
+
+Returns the statement string passed to the L</prepare> method.
+
+
+=item C<RowsInCache>  (integer, read-only)
+
+If the driver supports a local row cache for C<SELECT> statements, then
+this attribute holds the number of un-fetched rows in the cache. If the
+driver doesn't, then it returns C<undef>. Note that some drivers pre-fetch
+rows on execute, whereas others wait till the first fetch.
+
+See also the L</RowCacheSize> database handle attribute.
+
+=back
+
+=head1 OTHER METHODS
+
+=over 4
+
+=item C<install_method>
+
+    DBD::Foo::db->install_method($method_name, \%attr);
+
+Installs the driver-private method named by $method_name into the
+DBI method dispatcher so it can be called directly, avoiding the
+need to use the func() method.
+
+It is called as a static method on the driver class to which the
+method belongs. The method name must begin with the corresponding
+registered driver-private prefix. For example, for DBD::Oracle
+$method_name must being with 'C<ora_>', and for DBD::AnyData it
+must begin with 'C<ad_>'.
+
+The attributes can be used to provide fine control over how the DBI
+dispatcher handles the dispatching of the method. However, at this
+point, it's undocumented and very liable to change. (Volunteers to
+polish up and document the interface are very welcome to get in
+touch via dbi-dev@perl.org)
+
+Methods installed using install_method default to the standard error
+handling behaviour for DBI methods: clearing err and errstr before
+calling the method, and checking for errors to trigger RaiseError
+etc. on return. This differs from the default behaviour of func().
+
+Note for driver authors: The DBD::Foo::xx->install_method call won't
+work until the class-hierarchy has been setup. Normally the DBI
+looks after that just after the driver is loaded. This means
+install_method() can't be called at the time the driver is loaded
+unless the class-hierarchy is set up first. The way to do that is
+to call the setup_driver() method:
+
+    DBI->setup_driver('DBD::Foo');
+
+before using install_method().
+
+
+=back
+
+=head1 FURTHER INFORMATION
+
+=head2 Catalog Methods
+
+An application can retrieve metadata information from the DBMS by issuing
+appropriate queries on the views of the Information Schema. Unfortunately,
+C<INFORMATION_SCHEMA> views are seldom supported by the DBMS.
+Special methods (catalog methods) are available to return result sets
+for a small but important portion of that metadata:
+
+  column_info
+  foreign_key_info
+  primary_key_info
+  table_info
+
+All catalog methods accept arguments in order to restrict the result sets.
+Passing C<undef> to an optional argument does not constrain the search for
+that argument.
+However, an empty string ('') is treated as a regular search criteria
+and will only match an empty value.
+
+B<Note>: SQL/CLI and ODBC differ in the handling of empty strings. An
+empty string will not restrict the result set in SQL/CLI.
+
+Most arguments in the catalog methods accept only I<ordinary values>, e.g.
+the arguments of C<primary_key_info()>.
+Such arguments are treated as a literal string, i.e. the case is significant
+and quote characters are taken literally.
+
+Some arguments in the catalog methods accept I<search patterns> (strings
+containing '_' and/or '%'), e.g. the C<$table> argument of C<column_info()>.
+Passing '%' is equivalent to leaving the argument C<undef>.
+
+B<Caveat>: The underscore ('_') is valid and often used in SQL identifiers.
+Passing such a value to a search pattern argument may return more rows than
+expected!
+To include pattern characters as literals, they must be preceded by an
+escape character which can be achieved with
+
+  $esc = $dbh->get_info( 14 );  # SQL_SEARCH_PATTERN_ESCAPE
+  $search_pattern =~ s/([_%])/$esc$1/g;
+
+The ODBC and SQL/CLI specifications define a way to change the default
+behaviour described above: All arguments (except I<list value arguments>)
+are treated as I<identifier> if the C<SQL_ATTR_METADATA_ID> attribute is
+set to C<SQL_TRUE>.
+I<Quoted identifiers> are very similar to I<ordinary values>, i.e. their
+body (the string within the quotes) is interpreted literally.
+I<Unquoted identifiers> are compared in UPPERCASE.
+
+The DBI (currently) does not support the C<SQL_ATTR_METADATA_ID> attribute,
+i.e. it behaves like an ODBC driver where C<SQL_ATTR_METADATA_ID> is set to
+C<SQL_FALSE>.
+
+
+=head2 Transactions
+
+Transactions are a fundamental part of any robust database system. They
+protect against errors and database corruption by ensuring that sets of
+related changes to the database take place in atomic (indivisible,
+all-or-nothing) units.
+
+This section applies to databases that support transactions and where
+C<AutoCommit> is off.  See L</AutoCommit> for details of using C<AutoCommit>
+with various types of databases.
+
+The recommended way to implement robust transactions in Perl
+applications is to use C<RaiseError> and S<C<eval { ... }>>
+(which is very fast, unlike S<C<eval "...">>). For example:
+
+  $dbh->{AutoCommit} = 0;  # enable transactions, if possible
+  $dbh->{RaiseError} = 1;
+  eval {
+      foo(...)        # do lots of work here
+      bar(...)        # including inserts
+      baz(...)        # and updates
+      $dbh->commit;   # commit the changes if we get this far
+  };
+  if ($@) {
+      warn "Transaction aborted because $@";
+      # now rollback to undo the incomplete changes
+      # but do it in an eval{} as it may also fail
+      eval { $dbh->rollback };
+      # add other application on-error-clean-up code here
+  }
+
+If the C<RaiseError> attribute is not set, then DBI calls would need to be
+manually checked for errors, typically like this:
+
+  $h->method(@args) or die $h->errstr;
+
+With C<RaiseError> set, the DBI will automatically C<die> if any DBI method
+call on that handle (or a child handle) fails, so you don't have to
+test the return value of each method call. See L</RaiseError> for more
+details.
+
+A major advantage of the C<eval> approach is that the transaction will be
+properly rolled back if I<any> code (not just DBI calls) in the inner
+application dies for any reason. The major advantage of using the
+C<$h-E<gt>{RaiseError}> attribute is that all DBI calls will be checked
+automatically. Both techniques are strongly recommended.
+
+After calling C<commit> or C<rollback> many drivers will not let you
+fetch from a previously active C<SELECT> statement handle that's a child
+of the same database handle. A typical way round this is to connect the
+the database twice and use one connection for C<SELECT> statements.
+
+See L</AutoCommit> and L</disconnect> for other important information
+about transactions.
+
+
+=head2 Handling BLOB / LONG / Memo Fields
+
+Many databases support "blob" (binary large objects), "long", or similar
+datatypes for holding very long strings or large amounts of binary
+data in a single field. Some databases support variable length long
+values over 2,000,000,000 bytes in length.
+
+Since values of that size can't usually be held in memory, and because
+databases can't usually know in advance the length of the longest long
+that will be returned from a C<SELECT> statement (unlike other data
+types), some special handling is required.
+
+In this situation, the value of the C<$h-E<gt>{LongReadLen}>
+attribute is used to determine how much buffer space to allocate
+when fetching such fields.  The C<$h-E<gt>{LongTruncOk}> attribute
+is used to determine how to behave if a fetched value can't fit
+into the buffer.
+
+See the description of L</LongReadLen> for more information.
+
+When trying to insert long or binary values, placeholders should be used
+since there are often limits on the maximum size of an C<INSERT>
+statement and the L</quote> method generally can't cope with binary
+data.  See L</Placeholders and Bind Values>.
+
+
+=head2 Simple Examples
+
+Here's a complete example program to select and fetch some data:
+
+  my $data_source = "dbi::DriverName:db_name";
+  my $dbh = DBI->connect($data_source, $user, $password)
+      or die "Can't connect to $data_source: $DBI::errstr";
+
+  my $sth = $dbh->prepare( q{
+          SELECT name, phone
+          FROM mytelbook
+  }) or die "Can't prepare statement: $DBI::errstr";
+
+  my $rc = $sth->execute
+      or die "Can't execute statement: $DBI::errstr";
+
+  print "Query will return $sth->{NUM_OF_FIELDS} fields.\n\n";
+  print "Field names: @{ $sth->{NAME} }\n";
+
+  while (($name, $phone) = $sth->fetchrow_array) {
+      print "$name: $phone\n";
+  }
+  # check for problems which may have terminated the fetch early
+  die $sth->errstr if $sth->err;
+
+  $dbh->disconnect;
+
+Here's a complete example program to insert some data from a file.
+(This example uses C<RaiseError> to avoid needing to check each call).
+
+  my $dbh = DBI->connect("dbi:DriverName:db_name", $user, $password, {
+      RaiseError => 1, AutoCommit => 0
+  });
+
+  my $sth = $dbh->prepare( q{
+      INSERT INTO table (name, phone) VALUES (?, ?)
+  });
+
+  open FH, "<phone.csv" or die "Unable to open phone.csv: $!";
+  while (<FH>) {
+      chomp;
+      my ($name, $phone) = split /,/;
+      $sth->execute($name, $phone);
+  }
+  close FH;
+
+  $dbh->commit;
+  $dbh->disconnect;
+
+Here's how to convert fetched NULLs (undefined values) into empty strings:
+
+  while($row = $sth->fetchrow_arrayref) {
+    # this is a fast and simple way to deal with nulls:
+    foreach (@$row) { $_ = '' unless defined }
+    print "@$row\n";
+  }
+
+The C<q{...}> style quoting used in these examples avoids clashing with
+quotes that may be used in the SQL statement. Use the double-quote like
+C<qq{...}> operator if you want to interpolate variables into the string.
+See L<perlop/"Quote and Quote-like Operators"> for more details.
+
+=head2 Threads and Thread Safety
+
+Perl 5.7 and later support a new threading model called iThreads.
+(The old "5.005 style" threads are not supported by the DBI.)
+
+In the iThreads model each thread has it's own copy of the perl
+interpreter.  When a new thread is created the original perl
+interpreter is 'cloned' to create a new copy for the new thread.
+
+If the DBI and drivers are loaded and handles created before the
+thread is created then it will get a cloned copy of the DBI, the
+drivers and the handles.
+
+However, the internal pointer data within the handles will refer
+to the DBI and drivers in the original interpreter. Using those
+handles in the new interpreter thread is not safe, so the DBI detects
+this and croaks on any method call using handles that don't belong
+to the current thread (except for DESTROY).
+
+Because of this (possibly temporary) restriction, newly created
+threads must make their own connctions to the database. Handles
+can't be shared across threads.
+
+But BEWARE, some underlying database APIs (the code the DBD driver
+uses to talk to the database, often supplied by the database vendor)
+are not thread safe. If it's not thread safe, then allowing more
+than one thread to enter the code at the same time may cause
+subtle/serious problems. In some cases allowing more than
+one thread to enter the code, even if I<not> at the same time,
+can cause problems. You have been warned.
+
+Using DBI with perl threads is not yet recommended for production
+environments. For more information see
+L<http://www.perlmonks.org/index.pl?node_id=288022>
+
+Note: There is a bug in perl 5.8.2 when configured with threads
+and debugging enabled (bug #24463) which causes a DBI test to fail.
+
+=head2 Signal Handling and Canceling Operations
+
+[The following only applies to systems with unix-like signal handling.
+I'd welcome additions for other systems, especially Windows.]
+
+The first thing to say is that signal handling in Perl versions less
+than 5.8 is I<not> safe. There is always a small risk of Perl
+crashing and/or core dumping when, or after, handling a signal
+because the signal could arrive and be handled while internal data
+structures are being changed. If the signal handling code
+used those same internal data structures it could cause all manner
+of subtle and not-so-subtle problems.  The risk was reduced with
+5.4.4 but was still present in all perls up through 5.8.0.
+
+Beginning in perl 5.8.0 perl implements 'safe' signal handling if
+your system has the POSIX sigaction() routine. Now when a signal
+is delivered perl just makes a note of it but does I<not> run the
+%SIG handler. The handling is 'defered' until a 'safe' moment.
+
+Although this change made signal handling safe, it also lead to
+a problem with signals being defered for longer than you'd like.
+If a signal arrived while executing a system call, such as waiting
+for data on a network connection, the signal is noted and then the
+system call that was executing returns with an EINTR error code
+to indicate that it was interrupted. All fine so far.
+
+The problem comes when the code that made the system call sees the
+EINTR code and decides it's going to call it again. Perl doesn't
+do that, but database code sometimes does. If that happens then the
+signal handler doesn't get called untill later. Maybe much later.
+
+Fortunately there are ways around this which we'll discuss below.
+Unfortunately they make signals unsafe again.
+
+The two most common uses of signals in relation to the DBI are for
+canceling operations when the user types Ctrl-C (interrupt), and for
+implementing a timeout using C<alarm()> and C<$SIG{ALRM}>. 
+
+=over 4
+
+=item Cancel
+
+The DBI provides a C<cancel> method for statement handles. The
+C<cancel> method should abort the current operation and is designed
+to be called from a signal handler.  For example:
+
+  $SIG{INT} = sub { $sth->cancel };
+
+However, few drivers implement this (the DBI provides a default
+method that just returns C<undef>) and, even if implemented, there
+is still a possibility that the statement handle, and even the
+parent database handle, will not be usable afterwards.
+
+If C<cancel> returns true, then it has successfully
+invoked the database engine's own cancel function.  If it returns false,
+then C<cancel> failed. If it returns C<undef>, then the database
+driver does not have cancel implemented.
+
+=item Timeout
+
+The traditional way to implement a timeout is to set C<$SIG{ALRM}>
+to refer to some code that will be executed when an ALRM signal
+arrives and then to call alarm($seconds) to schedule an ALRM signal
+to be delivered $seconds in the future. For example:
+
+  eval {
+    local $SIG{ALRM} = sub { die "TIMEOUT\n" };
+    alarm($seconds);
+    ... code to execute with timeout here ...
+    alarm(0);  # cancel alarm (if code ran fast)
+  };
+  alarm(0);    # cancel alarm (if eval failed)
+  if ( $@ eq "TIMEOUT" ) { ... }
+
+Unfortunately, as described above, this won't always work as expected,
+depending on your perl version and the underlying database code.
+
+With Oracle for instance (DBD::Oracle), if the system which hosts
+the database is down the DBI->connect() call will hang for several
+minutes before returning an error.
+
+=back
+
+The solution on these systems is to use the C<POSIX::sigaction()>
+routine to gain low level access to how the signal handler is installed.
+
+The code would look something like this (for the DBD-Oracle connect()):
+
+   use POSIX ':signal_h';
+
+   my $mask = POSIX::SigSet->new( SIGALRM ); # signals to mask in the handler
+   my $action = POSIX::SigAction->new( 
+       sub { die "connect timeout" },        # the handler code ref
+       $mask,
+       # not using (perl 5.8.2 and later) 'safe' switch or sa_flags
+   );
+   my $oldaction = POSIX::SigAction->new();
+   sigaction( 'ALRM', $action, $oldaction );
+   my $dbh;
+   eval {
+      alarm(5); # seconds before time out
+      $dbh = DBI->connect("dbi:Oracle:$dsn" ... );
+      alarm(0); # cancel alarm (if connect worked fast)
+   };
+   alarm(0);    # cancel alarm (if eval failed)
+   sigaction( 'ALRM', $oldaction );  # restore original signal handler
+   if ( $@ ) ....
+
+Similar techniques can be used for canceling statement execution.
+
+Unfortunately, this solution is somewhat messy, and it does I<not> work with 
+perl versions less than perl 5.8 where C<POSIX::sigaction()> appears to be broken.  
+
+For a cleaner implementation that works across perl versions, see Lincoln Baxter's
+Sys::SigAction module at L<http://search.cpan.org/~lbaxter/Sys-SigAction/>.
+The documentation for Sys::SigAction includes an longer discussion
+of this problem, and a DBD::Oracle test script.
+
+Be sure to read all the signal handling sections of the L<perlipc> manual.
+
+And finally, two more points to keep firmly in mind. Firstly,
+remember that what we've done here is essentially revert to old
+style I<unsafe> handling of these signals. So do as little as
+possible in the handler.  Ideally just die(). Secondly, the handles
+in use at the time the signal is handled may not be safe to use
+afterwards.
+
+
+=head2 Subclassing the DBI
+
+DBI can be subclassed and extended just like any other object
+oriented module.  Before we talk about how to do that, it's important
+to be clear about how the DBI classes and how they work together.
+
+By default C<$dbh = DBI-E<gt>connect(...)> returns a $dbh blessed
+into the C<DBI::db> class.  And the C<$dbh-E<gt>prepare> method
+returns an $sth blessed into the C<DBI::st> class (actually it
+simply changes the last four characters of the calling handle class
+to be C<::st>).
+
+The leading 'C<DBI>' is known as the 'root class' and the extra
+'C<::db>' or 'C<::st>' are the 'handle type suffixes'. If you want
+to subclass the DBI you'll need to put your overriding methods into
+the appropriate classes.  For example, if you want to use a root class
+of C<MySubDBI> and override the do(), prepare() and execute() methods,
+then your do() and prepare() methods should be in the C<MySubDBI::db>
+class and the execute() method should be in the C<MySubDBI::st> class.
+
+To setup the inheritance hierarchy the @ISA variable in C<MySubDBI::db>
+should include C<DBI::db> and the @ISA variable in C<MySubDBI::st>
+should include C<DBI::st>.  The C<MySubDBI> root class itself isn't
+currently used for anything visible and so, apart from setting @ISA
+to include C<DBI>, it should be left empty.
+
+So, having put your overriding methods into the right classes, and
+setup the inheritance hierarchy, how do you get the DBI to use them?
+You have two choices, either a static method call using the name
+of your subclass:
+
+  $dbh = MySubDBI->connect(...);
+
+or specifying a C<RootClass> attribute:
+
+  $dbh = DBI->connect(..., { RootClass => 'MySubDBI' });
+
+The only difference between the two is that using an explicit
+RootClass attribute will make the DBI automatically attempt to load
+a module by that name if the class doesn't exist.
+
+If both forms are used then the attribute takes precedence.
+
+When subclassing is being used then, after a successful new
+connect, the DBI->connect method automatically calls:
+
+  $dbh->connected($dsn, $user, $pass, \%attr);
+
+The default method does nothing. The call is made just to simplify
+any post-connection setup that your subclass may want to perform.
+If your subclass supplies a connected method, it should be part of the
+MySubDBI::db package.
+
+Here's a brief example of a DBI subclass.  A more thorough example
+can be found in t/subclass.t in the DBI distribution.
+
+  package MySubDBI;
+
+  use strict;
+
+  use DBI;
+  use vars qw(@ISA);
+  @ISA = qw(DBI);
+
+  package MySubDBI::db;
+  use vars qw(@ISA);
+  @ISA = qw(DBI::db);
+
+  sub prepare {
+    my ($dbh, @args) = @_;
+    my $sth = $dbh->SUPER::prepare(@args)
+        or return;
+    $sth->{private_mysubdbi_info} = { foo => 'bar' };
+    return $sth;
+  }
+
+  package MySubDBI::st;
+  use vars qw(@ISA);
+  @ISA = qw(DBI::st);
+
+  sub fetch {
+    my ($sth, @args) = @_;
+    my $row = $sth->SUPER::fetch(@args)
+        or return;
+    do_something_magical_with_row_data($row)
+        or return $sth->set_err(1234, "The magic failed", undef, "fetch");
+    return $row;
+  }
+
+When calling a SUPER::method that returns a handle, be careful to
+check the return value before trying to do other things with it in
+your overridden method. This is especially important if you want
+to set a hash attribute on the handle, as Perl's autovivification
+will bite you by (in)conveniently creating an unblessed hashref,
+which your method will then return with usually baffling results
+later on.  It's best to check right after the call and return undef
+immediately on error, just like DBI would and just like the example
+above.
+
+If your method needs to record an error it should call the set_err()
+method with the error code and error string, as shown in the example
+above. The error code and error string will be recorded in the
+handle and available via C<$h-E<gt>err> and C<$DBI::errstr> etc.
+The set_err() method always returns an undef or empty list as
+approriate. Since your method should nearly always return an undef
+or empty list as soon as an error is detected it's handy to simply
+return what set_err() returns, as shown in the example above.
+
+If the handle has C<RaiseError>, C<PrintError>, or C<HandleError>
+etc. set then the set_err() method will honour them. This means
+that if C<RaiseError> is set then set_err() won't return in the
+normal way but will 'throw an exception' that can be caught with
+an C<eval> block.
+
+You can stash private data into DBI handles
+via C<$h-E<gt>{private_..._*}>.  See the entry under L</ATTRIBUTES
+COMMON TO ALL HANDLES> for info and important caveats.
+
+
+=head1 TRACING
+
+The DBI has a powerful tracing mechanism built in. It enables you
+to see what's going on 'behind the scenes', both within the DBI and
+the drivers you're using.
+
+=head2 Trace Settings
+
+Which details are written to the trace output is controlled by a
+combination of a I<trace level>, an integer from 0 to 15, and a set
+of I<trace flags> that are either on or off. Together these are known
+as the I<trace settings> and are stored together in a single integer.
+For normal use you only need to set the trace level, and generally
+only to a value between 1 and 4.
+
+Each handle has it's own trace settings, and so does the DBI.
+When you call a method the DBI merges the handles settings into its
+own for the duration of the call: the trace flags of the handle are
+OR'd into the trace flags of the DBI, and if the handle has a higher
+trace level then the DBI trace level is raised to match it.
+The previous DBI trace setings are restored when the called method
+returns.
+
+=head2 Trace Levels
+
+Trace I<levels> are as follows:
+
+  0 - Trace disabled.
+  1 - Trace DBI method calls returning with results or errors.
+  2 - Trace method entry with parameters and returning with results.
+  3 - As above, adding some high-level information from the driver
+      and some internal information from the DBI.
+  4 - As above, adding more detailed information from the driver.
+  5 to 15 - As above but with more and more obscure information.
+
+Trace level 1 is best for a simple overview of what's happening.
+Trace level 2 is a good choice for general purpose tracing.
+Levels 3 and above are best reserved for investigating a specific
+problem, when you need to see "inside" the driver and DBI.
+
+The trace output is detailed and typically very useful. Much of the
+trace output is formatted using the L</neat> function, so strings
+in the trace output may be edited and truncated by that function.
+
+=head2 Trace Flags
+
+Trace I<flags> are used to enable tracing of specific activities
+within the DBI and drivers. The DBI defines some trace flags and
+drivers can define others. DBI trace flag names begin with a capital
+letter and driver specific names begin with a lowercase letter, as
+usual.
+
+Curently the DBI only defines two trace flags:
+
+  ALL - turn on all DBI and driver flags (not recommended)
+  SQL - trace SQL statements executed (not yet implemented)
+
+The L</parse_trace_flags> and L</parse_trace_flag> methods are used
+to convert trace flag names into the coresponding integer bit flags.
+
+=head2 Enabling Trace
+
+The C<$h-E<gt>trace> method sets the trace settings for a handle
+and C<DBI-E<gt>trace> does the same for the DBI.
+
+In addition to the L</trace> method, you can enable the same trace
+information, and direct the output to a file, by setting the
+C<DBI_TRACE> environment variable before starting Perl.
+See L</DBI_TRACE> for more information.
+
+Finally, you can set, or get, the trace settings for a handle using
+the C<TraceLevel> attribute.
+
+All of those methods use parse_trace_flags() and so allow you set
+both the trace level and multiple trace flags by using a string
+containing the trace level and/or flag names separated by vertical
+bar ("C<|>") or comma ("C<,>") characters. For example:
+
+  local $h->{TraceLevel} = "3|SQL|foo";
+
+=head2 Trace Output
+
+Initially trace output is written to C<STDERR>.  Both the
+C<$h-E<gt>trace> and C<DBI-E<gt>trace> methods take an optional
+$trace_filename parameter. If specified, and can be opened in
+append mode, then I<all> trace output (currently including that
+from other handles) is redirected to that file.  A warning is
+generated if the file can't be opened.
+
+Further calls to trace() without a $trace_filename do not alter where
+the trace output is sent. If $trace_filename is undefined, then
+trace output is sent to C<STDERR> and the previous trace file is closed.
+
+Currently $trace_filename can't be a filehandle. But meanwhile you
+can use the special strings C<"STDERR"> and C<"STDOUT"> to select
+those filehandles.
+
+=head2 Tracing Tips
+
+You can add tracing to your own application code using the
+L</trace_msg> method.
+
+It can sometimes be handy to compare trace files from two different
+runs of the same script. However using a tool like C<diff> doesn't work
+well because the trace file is full of object addresses that may
+differ each run. Here's a handy little command to strip those out:
+
+  perl -pe 's/\b0x[\da-f]{6,}/0xNNNN/gi; s/\b[\da-f]{6,}/<long number>/gi'
+
+
+=head1 DBI ENVIRONMENT VARIABLES
+
+The DBI module recognizes a number of environment variables, but most of
+them should not be used most of the time.
+It is better to be explicit about what you are doing to avoid the need
+for environment variables, especially in a web serving system where web
+servers are stingy about which environment variables are available.
+
+=head2 DBI_DSN
+
+The DBI_DSN environment variable is used by DBI->connect if you do not
+specify a data source when you issue the connect.
+It should have a format such as "dbi:Driver:databasename".
+
+=head2 DBI_DRIVER
+
+The DBI_DRIVER environment variable is used to fill in the database
+driver name in DBI->connect if the data source string starts "dbi::"
+(thereby omitting the driver).
+If DBI_DSN omits the driver name, DBI_DRIVER can fill the gap.
+
+=head2 DBI_AUTOPROXY
+
+The DBI_AUTOPROXY environment variable takes a string value that starts
+"dbi:Proxy:" and is typically followed by "hostname=...;port=...".
+It is used to alter the behaviour of DBI->connect.
+For full details, see DBI::Proxy documentation.
+
+=head2 DBI_USER
+
+The DBI_USER environment variable takes a string value that is used as
+the user name if the DBI->connect call is given undef (as distinct from
+an empty string) as the username argument.
+Be wary of the security implications of using this.
+
+=head2 DBI_PASS
+
+The DBI_PASS environment variable takes a string value that is used as
+the password if the DBI->connect call is given undef (as distinct from
+an empty string) as the password argument.
+Be extra wary of the security implications of using this.
+
+=head2 DBI_DBNAME (obsolete)
+
+The DBI_DBNAME environment variable takes a string value that is used only when the
+obsolescent style of DBI->connect (with driver name as fourth parameter) is used, and
+when no value is provided for the first (database name) argument.
+
+=head2 DBI_TRACE
+
+The DBI_TRACE environment variable specifies the global default
+trace settings for the DBI at startup. Can also be used to direct
+trace output to a file. When the DBI is loaded it does:
+
+  DBI->trace(split /=/, $ENV{DBI_TRACE}, 2) if $ENV{DBI_TRACE};
+
+So if C<DBI_TRACE> contains an "C<=>" character then what follows
+it is used as the name of the file to append the trace to.
+
+output appended to that file. If the name begins with a number
+followed by an equal sign (C<=>), then the number and the equal sign are
+stripped off from the name, and the number is used to set the trace
+level. For example:
+
+  DBI_TRACE=1=dbitrace.log perl your_test_script.pl
+
+On Unix-like systems using a Bourne-like shell, you can do this easily
+on the command line:
+
+  DBI_TRACE=2 perl your_test_script.pl
+
+See L</TRACING> for more information.
+
+=head2 PERL_DBI_DEBUG (obsolete)
+
+An old variable that should no longer be used; equivalent to DBI_TRACE.
+
+=head2 DBI_PROFILE
+
+The DBI_PROFILE environment variable can be used to enable profiling
+of DBI method calls. See <DBI::Profile> for more information.
+
+=head2 DBI_PUREPERL
+
+The DBI_PUREPERL environment variable can be used to enable the
+use of DBI::PurePerl.  See <DBI::PurePerl> for more information.
+
+=head1 WARNING AND ERROR MESSAGES
+
+=head2 Fatal Errors
+
+=over 4
+
+=item Can't call method "prepare" without a package or object reference
+
+The C<$dbh> handle you're using to call C<prepare> is probably undefined because
+the preceding C<connect> failed. You should always check the return status of
+DBI methods, or use the L</RaiseError> attribute.
+
+=item Can't call method "execute" without a package or object reference
+
+The C<$sth> handle you're using to call C<execute> is probably undefined because
+the preceeding C<prepare> failed. You should always check the return status of
+DBI methods, or use the L</RaiseError> attribute.
+
+=item DBI/DBD internal version mismatch
+
+The DBD driver module was built with a different version of DBI than
+the one currently being used.  You should rebuild the DBD module under
+the current version of DBI.
+
+(Some rare platforms require "static linking". On those platforms, there
+may be an old DBI or DBD driver version actually embedded in the Perl
+executable being used.)
+
+=item DBD driver has not implemented the AutoCommit attribute
+
+The DBD driver implementation is incomplete. Consult the author.
+
+=item Can't [sg]et %s->{%s}: unrecognised attribute
+
+You attempted to set or get an unknown attribute of a handle.  Make
+sure you have spelled the attribute name correctly; case is significant
+(e.g., "Autocommit" is not the same as "AutoCommit").
+
+=back
+
+=head1 Pure-Perl DBI
+
+A pure-perl emulation of the DBI is included in the distribution
+for people using pure-perl drivers who, for whatever reason, can't
+install the compiled DBI. See L<DBI::PurePerl>.
+
+=head1 SEE ALSO
+
+=head2 Driver and Database Documentation
+
+Refer to the documentation for the DBD driver that you are using.
+
+Refer to the SQL Language Reference Manual for the database engine that you are using.
+
+=head2 ODBC and SQL/CLI Standards Reference Information
+
+More detailed information about the semantics of certain DBI methods
+that are based on ODBC and SQL/CLI standards is available on-line
+via microsoft.com, for ODBC, and www.jtc1sc32.org for the SQL/CLI
+standard:
+
+ DBI method        ODBC function     SQL/CLI Working Draft
+ ----------        -------------     ---------------------
+ column_info       SQLColumns        Page 124
+ foreign_key_info  SQLForeignKeys    Page 163
+ get_info          SQLGetInfo        Page 214
+ primary_key_info  SQLPrimaryKeys    Page 254
+ table_info        SQLTables         Page 294
+ type_info         SQLGetTypeInfo    Page 239
+
+For example, for ODBC information on SQLColumns you'd visit:
+
+  http://msdn.microsoft.com/library/en-us/odbc/htm/odbcsqlcolumns.asp
+
+If that URL ceases to work then use the MSDN search facility at:
+
+  http://search.microsoft.com/us/dev/
+
+and search for C<SQLColumns returns> using the exact phrase option.
+The link you want will probably just be called C<SQLColumns> and will
+be part of the Data Access SDK.
+
+And for SQL/CLI standard information on SQLColumns you'd read page 124 of
+the (very large) SQL/CLI Working Draft available from:
+
+  http://www.jtc1sc32.org/sc32/jtc1sc32.nsf/Attachments/7E3B41486BD99C3488256B410064C877/$FILE/32N0744T.PDF
+
+=head2 Standards Reference Information
+
+A hyperlinked, browsable version of the BNF syntax for SQL92 (plus
+Oracle 7 SQL and PL/SQL) is available here:
+
+  http://cui.unige.ch/db-research/Enseignement/analyseinfo/SQL92/BNFindex.html
+
+A BNF syntax for SQL3 is available here:
+
+  http://www.sqlstandards.org/SC32/WG3/Progression_Documents/Informal_working_drafts/iso-9075-2-1999.bnf
+
+The following links provide further useful information about SQL.
+Some of these are rather dated now but may still be useful.
+
+  http://www.jcc.com/SQLPages/jccs_sql.htm
+  http://www.contrib.andrew.cmu.edu/~shadow/sql.html
+  http://www.altavista.com/query?q=sql+tutorial
+
+
+=head2 Books and Articles
+
+Programming the Perl DBI, by Alligator Descartes and Tim Bunce.
+L<http://books.perl.org/book/154>
+
+Programming Perl 3rd Ed. by Larry Wall, Tom Christiansen & Jon Orwant.
+L<http://books.perl.org/book/134>
+
+Learning Perl by Randal Schwartz.
+L<http://books.perl.org/book/101>
+
+Details of many other books related to perl can be found at L<http://books.perl.org>
+
+=head2 Perl Modules
+
+Index of DBI related modules available from CPAN:
+
+ http://search.cpan.org/search?mode=module&query=DBIx%3A%3A
+ http://search.cpan.org/search?mode=doc&query=DBI
+
+For a good comparison of RDBMS-OO mappers and some OO-RDBMS mappers
+(including Class::DBI, Alzabo, and DBIx::RecordSet in the former
+category and Tangram and SPOPS in the latter) see the Perl
+Object-Oriented Persistence project pages at:
+
+ http://poop.sourceforge.net
+
+A similar page for Java toolkits can be found at:
+
+ http://c2.com/cgi-bin/wiki?ObjectRelationalToolComparison
+
+=head2 Mailing List
+
+The I<dbi-users> mailing list is the primary means of communication among
+users of the DBI and its related modules. For details send email to:
+
+ dbi-users-help@perl.org
+
+There are typically between 700 and 900 messages per month.  You have
+to subscribe in order to be able to post. However you can opt for a
+'post-only' subscription.
+
+Mailing list archives (of variable quality) are held at:
+
+ http://groups.google.com/groups?group=perl.dbi.users
+ http://www.xray.mpe.mpg.de/mailing-lists/dbi/
+ http://www.mail-archive.com/dbi-users%40perl.org/
+
+=head2 Assorted Related WWW Links
+
+The DBI "Home Page":
+
+ http://dbi.perl.org/
+
+Other DBI related links:
+
+ http://tegan.deltanet.com/~phlip/DBUIdoc.html
+ http://dc.pm.org/perl_db.html
+ http://wdvl.com/Authoring/DB/Intro/toc.html
+ http://www.hotwired.com/webmonkey/backend/tutorials/tutorial1.html
+ http://bumppo.net/lists/macperl/1999/06/msg00197.html
+ http://gmax.oltrelinux.com/dbirecipes.html
+
+Other database related links:
+
+ http://www.jcc.com/sql_stnd.html
+ http://cuiwww.unige.ch/OSG/info/FreeDB/FreeDB.home.html
+
+Security, especially the "SQL Injection" attack:
+
+ http://www.ngssoftware.com/research/papers.html
+ http://www.ngssoftware.com/papers/advanced_sql_injection.pdf
+ http://www.ngssoftware.com/papers/more_advanced_sql_injection.pdf
+ http://www.esecurityplanet.com/trends/article.php/2243461
+ http://www.spidynamics.com/papers/SQLInjectionWhitePaper.pdf
+ http://www.webcohort.com/Blindfolded_SQL_Injection.pdf
+ http://online.securityfocus.com/infocus/1644
+
+Commercial and Data Warehouse Links
+
+ http://www.dwinfocenter.org
+ http://www.datawarehouse.com
+ http://www.datamining.org
+ http://www.olapcouncil.org
+ http://www.idwa.org
+ http://www.knowledgecenters.org/dwcenter.asp
+
+Recommended Perl Programming Links
+
+ http://language.perl.com/style/
+
+
+=head2 FAQ
+
+Please also read the DBI FAQ which is installed as a DBI::FAQ module.
+You can use I<perldoc> to read it by executing the C<perldoc DBI::FAQ> command.
+
+=head1 AUTHORS
+
+DBI by Tim Bunce.  This pod text by Tim Bunce, J. Douglas Dunlop,
+Jonathan Leffler and others.  Perl by Larry Wall and the
+C<perl5-porters>.
+
+=head1 COPYRIGHT
+
+The DBI module is Copyright (c) 1994-2004 Tim Bunce. Ireland.
+All rights reserved.
+
+You may distribute under the terms of either the GNU General Public
+License or the Artistic License, as specified in the Perl README file.
+
+=head1 SUPPORT / WARRANTY
+
+The DBI is free Open Source software. IT COMES WITHOUT WARRANTY OF ANY KIND.
+
+=head2 Support
+
+My consulting company, Data Plan Services, offers annual and
+multi-annual support contracts for the DBI. These provide sustained
+support for DBI development, and sustained value for you in return.
+Contact me for details.
+
+=head2 Sponsor Enhancements
+
+The DBI Roadmap is available at L<http://search.cpan.org/~timb/DBI/Roadmap.pod>
+
+If your company would benefit from a specific new DBI feature,
+please consider sponsoring its development.  Work is performed
+rapidly, and usually on a fixed-price payment-on-delivery basis.
+Contact me for details.
+
+Using such targeted financing allows you to contribute to DBI
+development, and rapidly get something specific and valuable in return.
+
+=head1 ACKNOWLEDGEMENTS
+
+I would like to acknowledge the valuable contributions of the many
+people I have worked with on the DBI project, especially in the early
+years (1992-1994). In no particular order: Kevin Stock, Buzz Moschetti,
+Kurt Andersen, Ted Lemon, William Hails, Garth Kennedy, Michael Peppler,
+Neil S. Briscoe, Jeff Urlwin, David J. Hughes, Jeff Stander,
+Forrest D Whitcher, Larry Wall, Jeff Fried, Roy Johnson, Paul Hudson,
+Georg Rehfeld, Steve Sizemore, Ron Pool, Jon Meek, Tom Christiansen,
+Steve Baumgarten, Randal Schwartz, and a whole lot more.
+
+Then, of course, there are the poor souls who have struggled through
+untold and undocumented obstacles to actually implement DBI drivers.
+Among their ranks are Jochen Wiedmann, Alligator Descartes, Jonathan
+Leffler, Jeff Urlwin, Michael Peppler, Henrik Tougaard, Edwin Pratomo,
+Davide Migliavacca, Jan Pazdziora, Peter Haworth, Edmund Mergl, Steve
+Williams, Thomas Lowery, and Phlip Plumlee. Without them, the DBI would
+not be the practical reality it is today.  I'm also especially grateful
+to Alligator Descartes for starting work on the first edition of the
+"Programming the Perl DBI" book and letting me jump on board.
+
+The DBI and DBD::Oracle were originally developed while I was Technical
+Director (CTO) of the Paul Ingram Group (www.ig.co.uk).  So I'd
+especially like to thank Paul for his generosity and vision in
+supporting this work for many years.
+
+=head1 CONTRIBUTING
+
+As you can see above, many people have contributed to the DBI and
+drivers in many ways over many years.
+
+If you'd like to help then see L<http://dbi.perl.org/contributing>
+and L<http://search.cpan.org/~timb/DBI/Roadmap.pod>
+
+If you'd like the DBI to do something new or different then a good way
+to make that happen is to do it yourself and send me a patch to the
+source code that shows the changes. (But read "Speak before you patch"
+below.)
+
+=head2 Browsing the source code repository
+
+Use http://svn.perl.org/modules/dbi/trunk (basic)
+or  http://svn.perl.org/viewcvs/modules/ (more useful)
+
+=head2 How to create a patch using Subversion
+
+The DBI source code is maintained using Subversion (a replacement
+for CVS, see L<http://subversion.tigris.org/>). To access the source
+you'll need to install a Subversion client. Then, to get the source
+code, do:
+
+  svn checkout http://svn.perl.org/modules/dbi/trunk
+
+If it prompts for a username and password use your perl.org account
+if you have one, else just 'guest' and 'guest'. The source code will
+be in a new subdirectory called C<trunk>.
+
+To keep informed about changes to the source you can send an empty email
+to dbi-changes@perl.org after which you'll get an email with the
+change log message and diff of each change checked-in to the source.
+
+After making your changes you can generate a patch file, but before
+you do, make sure your source is still upto date using:
+
+  svn update
+
+If you get any conflicts reported you'll need to fix them first.
+Then generate the patch file from within the C<trunk> directory using:
+
+  svn diff > foo.patch
+
+Read the patch file, as a sanity check, and then email it to dbi-dev@perl.org.
+
+=head2 How to create a patch without Subversion
+
+Unpack a fresh copy of the distribution:
+
+  tar xfz DBI-1.40.tar.gz
+
+Rename the newly created top level directory:
+
+  mv DBI-1.40 DBI-1.40.your_foo
+
+Edit the contents of DBI-1.40.your_foo/* till it does what you want.
+
+Test your changes and then remove all temporary files:
+
+  make test && make distclean
+
+Go back to the directory you originally unpacked the distribution:
+
+  cd ..
+
+Unpack I<another> copy of the original distribution you started with:
+
+  tar xfz DBI-1.40.tar.gz
+
+Then create a patch file by performing a recursive C<diff> on the two
+top level directories:
+
+  diff -r -u DBI-1.40 DBI-1.40.your_foo > DBI-1.40.your_foo.patch
+
+=head2 Speak before you patch
+
+For anything non-trivial or possibly controversial it's a good idea
+to discuss (on dbi-dev@perl.org) the changes you propose before
+actually spending time working on them. Otherwise you run the risk
+of them being rejected because they don't fit into some larger plans
+you may not be aware of.
+
+=head1 TRANSLATIONS
+
+A German translation of this manual (possibly slightly out of date) is
+available, thanks to O'Reilly, at:
+
+  http://www.oreilly.de/catalog/perldbiger/
+
+Some other translations:
+
+ http://cronopio.net/perl/                              - Spanish
+ http://member.nifty.ne.jp/hippo2000/dbimemo.htm        - Japanese
+
+
+=head1 TRAINING
+
+References to DBI related training resources. No recommendation implied.
+
+  http://www.treepax.co.uk/
+  http://www.keller.com/dbweb/
+
+(If you offer professional DBI related training services,
+please send me your details so I can add them here.)
+
+=head1 FREQUENTLY ASKED QUESTIONS
+
+See the DBI FAQ for a more comprehensive list of FAQs. Use the
+C<perldoc DBI::FAQ> command to read it.
+
+=head2 Why doesn't my CGI script work right?
+
+Read the information in the references below.  Please do I<not> post
+CGI related questions to the I<dbi-users> mailing list (or to me).
+
+ http://www.perl.com/cgi-bin/pace/pub/doc/FAQs/cgi/perl-cgi-faq.html
+ http://www3.pair.com/webthing/docs/cgi/faqs/cgifaq.shtml
+ http://www-genome.wi.mit.edu/WWW/faqs/www-security-faq.html
+ http://www.boutell.com/faq/
+ http://www.perl.com/perl/faq/
+
+=head2 How can I maintain a WWW connection to a database?
+
+For information on the Apache httpd server and the C<mod_perl> module see
+
+  http://perl.apache.org/
+
+=head1 OTHER RELATED WORK AND PERL MODULES
+
+=over 4
+
+=item Apache::DBI by E.Mergl@bawue.de
+
+To be used with the Apache daemon together with an embedded Perl
+interpreter like C<mod_perl>. Establishes a database connection which
+remains open for the lifetime of the HTTP daemon. This way the CGI
+connect and disconnect for every database access becomes superfluous.
+
+=item JDBC Server by Stuart 'Zen' Bishop zen@bf.rmit.edu.au
+
+The server is written in Perl. The client classes that talk to it are
+of course in Java. Thus, a Java applet or application will be able to
+comunicate via the JDBC API with any database that has a DBI driver installed.
+The URL used is in the form C<jdbc:dbi://host.domain.etc:999/Driver/DBName>.
+It seems to be very similar to some commercial products, such as jdbcKona.
+
+=item Remote Proxy DBD support
+
+As of DBI 1.02, a complete implementation of a DBD::Proxy driver and the
+DBI::ProxyServer are part of the DBI distribution.
+
+=item SQL Parser
+
+See also the SQL::Statement module, SQL parser and engine.
+
+=back
+
+=cut
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Bundle/DBI.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Bundle/DBI.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Bundle/DBI.pm	(revision 14139)
@@ -0,0 +1,51 @@
+# -*- perl -*-
+
+package Bundle::DBI;
+
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/o);
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bundle::DBI - A bundle to install DBI and required modules.
+
+=head1 SYNOPSIS
+
+  perl -MCPAN -e 'install Bundle::DBI'
+
+=head1 CONTENTS
+
+DBI - for to get to know thyself
+
+DBI::Shell 11.91 - the DBI command line shell
+
+Storable 2.06 - for DBD::Proxy and DBI::ProxyServer
+
+Net::Daemon 0.37 - for DBD::Proxy and DBI::ProxyServer
+
+RPC::PlServer 0.2016 - for DBD::Proxy and DBI::ProxyServer
+
+DBD::Multiplex 1.19 - treat multiple db handles as one
+
+=head1 DESCRIPTION
+
+This bundle includes all the modules used by the Perl Database
+Interface (DBI) module, created by Tim Bunce.
+
+A I<Bundle> is a module that simply defines a collection of other
+modules.  It is used by the L<CPAN> module to automate the fetching,
+building and installing of modules from the CPAN ftp archive sites.
+
+This bundle does not deal with the various database drivers (e.g.
+DBD::Informix, DBD::Oracle etc), most of which require software from
+sources other than CPAN. You'll need to fetch and build those drivers
+yourself.
+
+=head1 AUTHORS
+
+Jonathan Leffler, Jochen Wiedmann and Tim Bunce.
+
+=cut
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Bundle/LWP.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Bundle/LWP.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Bundle/LWP.pm	(revision 14139)
@@ -0,0 +1,43 @@
+package Bundle::LWP;
+
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bundle::LWP - install all libwww-perl related modules
+
+=head1 SYNOPSIS
+
+ perl -MCPAN -e 'install Bundle::LWP'
+
+=head1 CONTENTS
+
+MIME::Base64       - Used in authentication headers
+
+Digest::MD5        - Needed to do Digest authentication
+
+URI 1.10           - There are URIs everywhere
+
+Net::FTP 2.58      - If you want ftp://-support
+
+HTML::Tagset       - Needed by HTML::Parser
+
+HTML::Parser       - Need by HTML::HeadParser
+
+HTML::HeadParser   - To get the correct $res->base
+
+LWP                - The reason why you need the modules above
+
+=head1 DESCRIPTION
+
+This bundle defines all reqreq modules for libwww-perl.  Bundles have
+special meaning for the CPAN module.  When you install the bundle
+module all modules mentioned in L</CONTENTS> will be installed instead.
+
+=head1 SEE ALSO
+
+L<CPAN/Bundles>
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBD/DBM.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBD/DBM.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBD/DBM.pm	(revision 14139)
@@ -0,0 +1,1031 @@
+#######################################################################
+#
+#  DBD::DBM - a DBI driver for DBM files
+#
+#  Copyright (c) 2004 by Jeff Zucker < jzucker AT cpan.org >
+#
+#  All rights reserved.
+#
+#  You may freely distribute and/or modify this  module under the terms
+#  of either the GNU  General Public License (GPL) or the Artistic License,
+#  as specified in the Perl README file.
+#
+#  USERS - see the pod at the bottom of this file
+#
+#  DBD AUTHORS - see the comments in the code
+#
+#######################################################################
+require 5.005_03;
+use strict;
+
+#################
+package DBD::DBM;
+#################
+use base qw( DBD::File );
+use vars qw($VERSION $ATTRIBUTION $drh $methods_already_installed);
+$VERSION     = '0.02';
+$ATTRIBUTION = 'DBD::DBM by Jeff Zucker';
+
+# no need to have driver() unless you need private methods
+#
+sub driver ($;$) {
+    my($class, $attr) = @_;
+    return $drh if $drh;
+
+    # do the real work in DBD::File
+    #
+    $attr->{Attribution} = 'DBD::DBM by Jeff Zucker';
+    my $this = $class->SUPER::driver($attr);
+
+    # install private methods
+    #
+    # this requires that dbm_ (or foo_) be a registered prefix
+    # but you can write private methods before official registration
+    # by hacking the $dbd_prefix_registry in a private copy of DBI.pm
+    #
+    if ( $DBI::VERSION >= 1.37 and !$methods_already_installed++ ) {
+        DBD::DBM::db->install_method('dbm_versions');
+        DBD::DBM::st->install_method('dbm_schema');
+    }
+
+    $this;
+}
+
+sub CLONE {
+    undef $drh;
+}
+
+#####################
+package DBD::DBM::dr;
+#####################
+$DBD::DBM::dr::imp_data_size = 0;
+@DBD::DBM::dr::ISA = qw(DBD::File::dr);
+
+# you can get by without connect() if you don't have to check private
+# attributes, DBD::File will gather the connection string arguements for you
+#
+sub connect ($$;$$$) {
+    my($drh, $dbname, $user, $auth, $attr)= @_;
+
+    # create a 'blank' dbh
+    my $this = DBI::_new_dbh($drh, {
+	Name => $dbname,
+    });
+
+    # parse the connection string for name=value pairs
+    if ($this) {
+
+        # define valid private attributes
+        #
+        # attempts to set non-valid attrs in connect() or
+        # with $dbh->{attr} will throw errors
+        #
+        # the attrs here *must* start with dbm_ or foo_
+        #
+        # see the STORE methods below for how to check these attrs
+        #
+        $this->{dbm_valid_attrs} = {
+            dbm_tables            => 1  # per-table information
+          , dbm_type              => 1  # the global DBM type e.g. SDBM_File
+          , dbm_mldbm             => 1  # the global MLDBM serializer
+          , dbm_cols              => 1  # the global column names
+          , dbm_version           => 1  # verbose DBD::DBM version
+          , dbm_ext               => 1  # file extension
+          , dbm_lockfile          => 1  # lockfile extension
+          , dbm_store_metadata    => 1  # column names, etc.
+          , dbm_berkeley_flags    => 1  # for BerkeleyDB
+        };
+
+	my($var, $val);
+	$this->{f_dir} = $DBD::File::haveFileSpec ? File::Spec->curdir() : '.';
+	while (length($dbname)) {
+	    if ($dbname =~ s/^((?:[^\\;]|\\.)*?);//s) {
+		$var = $1;
+	    } else {
+		$var = $dbname;
+		$dbname = '';
+	    }
+	    if ($var =~ /^(.+?)=(.*)/s) {
+		$var = $1;
+		($val = $2) =~ s/\\(.)/$1/g;
+
+                # in the connect string the attr names
+                # can either have dbm_ (or foo_) prepended or not
+                # this will add the prefix if it's missing
+                #
+                $var = 'dbm_' . $var unless $var =~ /^dbm_/
+                                     or     $var eq 'f_dir';
+		# XXX should pass back to DBI via $attr for connect() to STORE
+		$this->{$var} = $val;
+	    }
+	}
+	$this->{f_version} = $DBD::File::VERSION;
+        $this->{dbm_version} = $DBD::DBM::VERSION;
+        for (qw( nano_version statement_version)) {
+            $this->{'sql_'.$_} = $DBI::SQL::Nano::versions->{$_}||'';
+        }
+        $this->{sql_handler} = ($this->{sql_statement_version})
+                             ? 'SQL::Statement'
+   	                     : 'DBI::SQL::Nano';
+    }
+    $this->STORE('Active',1);
+    return $this;
+}
+
+# you could put some :dr private methods here
+
+# you may need to over-ride some DBD::File::dr methods here
+# but you can probably get away with just letting it do the work
+# in most cases
+
+#####################
+package DBD::DBM::db;
+#####################
+$DBD::DBM::db::imp_data_size = 0;
+@DBD::DBM::db::ISA = qw(DBD::File::db);
+
+# the ::db::STORE method is what gets called when you set
+# a lower-cased database handle attribute such as $dbh->{somekey}=$someval;
+#
+# STORE should check to make sure that "somekey" is a valid attribute name
+# but only if it is really one of our attributes (starts with dbm_ or foo_)
+# You can also check for valid values for the attributes if needed
+# and/or perform other operations
+#
+sub STORE ($$$) {
+    my ($dbh, $attrib, $value) = @_;
+
+    # use DBD::File's STORE unless its one of our own attributes
+    #
+    return $dbh->SUPER::STORE($attrib,$value) unless $attrib =~ /^dbm_/;
+
+    # throw an error if it has our prefix but isn't a valid attr name
+    #
+    if ( $attrib ne 'dbm_valid_attrs'          # gotta start somewhere :-)
+     and !$dbh->{dbm_valid_attrs}->{$attrib} ) {
+        return $dbh->set_err( 1,"Invalid attribute '$attrib'!");
+    }
+    else {
+
+        # check here if you need to validate values
+        # or conceivably do other things as well
+        #
+	$dbh->{$attrib} = $value;
+        return 1;
+    }
+}
+
+# and FETCH is done similar to STORE
+#
+sub FETCH ($$) {
+    my ($dbh, $attrib) = @_;
+
+    return $dbh->SUPER::FETCH($attrib) unless $attrib =~ /^dbm_/;
+
+    # throw an error if it has our prefix but isn't a valid attr name
+    #
+    if ( $attrib ne 'dbm_valid_attrs'          # gotta start somewhere :-)
+     and !$dbh->{dbm_valid_attrs}->{$attrib} ) {
+        return $dbh->set_err( 1,"Invalid attribute '$attrib'");
+    }
+    else {
+
+        # check here if you need to validate values
+        # or conceivably do other things as well
+        #
+	return $dbh->{$attrib};
+    }
+}
+
+
+# this is an example of a private method
+# these used to be done with $dbh->func(...)
+# see above in the driver() sub for how to install the method
+#
+sub dbm_versions {
+    my $dbh   = shift;
+    my $table = shift || '';
+    my $dtype = $dbh->{dbm_tables}->{$table}->{type}
+             || $dbh->{dbm_type}
+             || 'SDBM_File';
+    my $mldbm = $dbh->{dbm_tables}->{$table}->{mldbm}
+             || $dbh->{dbm_mldbm}
+             || '';
+    $dtype   .= ' + MLDBM + ' . $mldbm if $mldbm;
+
+    my %version = ( DBI => $DBI::VERSION );
+    $version{"DBI::PurePerl"} = $DBI::PurePerl::VERSION	if $DBI::PurePerl;
+    $version{OS}   = "$^O ($Config::Config{osvers})";
+    $version{Perl} = "$] ($Config::Config{archname})";
+    my $str = sprintf "%-16s %s\n%-16s %s\n%-16s %s\n",
+      'DBD::DBM'         , $dbh->{Driver}->{Version} . " using $dtype"
+    , '  DBD::File'      , $dbh->{f_version}
+    , '  DBI::SQL::Nano' , $dbh->{sql_nano_version}
+    ;
+    $str .= sprintf "%-16s %s\n",
+    , '  SQL::Statement' , $dbh->{sql_statement_version}
+      if $dbh->{sql_handler} eq 'SQL::Statement';
+    for (sort keys %version) {
+        $str .= sprintf "%-16s %s\n", $_, $version{$_};
+    }
+    return "$str\n";
+}
+
+# you may need to over-ride some DBD::File::db methods here
+# but you can probably get away with just letting it do the work
+# in most cases
+
+#####################
+package DBD::DBM::st;
+#####################
+$DBD::DBM::st::imp_data_size = 0;
+@DBD::DBM::st::ISA = qw(DBD::File::st);
+
+sub dbm_schema {
+    my($sth,$tname)=@_;
+    return $sth->set_err(1,'No table name supplied!') unless $tname;
+    return $sth->set_err(1,"Unknown table '$tname'!")
+       unless $sth->{Database}->{dbm_tables}
+          and $sth->{Database}->{dbm_tables}->{$tname};
+    return $sth->{Database}->{dbm_tables}->{$tname}->{schema};
+}
+# you could put some :st private methods here
+
+# you may need to over-ride some DBD::File::st methods here
+# but you can probably get away with just letting it do the work
+# in most cases
+
+############################
+package DBD::DBM::Statement;
+############################
+use base qw( DBD::File::Statement );
+use IO::File;  # for locking only
+use Fcntl;
+
+my $HAS_FLOCK = eval { flock STDOUT, 0; 1 };
+
+# you must define open_table;
+# it is done at the start of all executes;
+# it doesn't necessarily have to "open" anything;
+# you must define the $tbl and at least the col_names and col_nums;
+# anything else you put in depends on what you need in your
+# ::Table methods below; you must bless the $tbl into the
+# appropriate class as shown
+#
+# see also the comments inside open_table() showing the difference
+# between global, per-table, and default settings
+#
+sub open_table ($$$$$) {
+    my($self, $data, $table, $createMode, $lockMode) = @_;
+    my $dbh = $data->{Database};
+
+    my $tname = $table || $self->{tables}->[0]->{name};
+    my $file;
+    ($table,$file) = $self->get_file_name($data,$tname);
+
+    # note the use of three levels of attribute settings below
+    # first it looks for a per-table setting
+    # if none is found, it looks for a global setting
+    # if none is found, it sets a default
+    #
+    # your DBD may not need this, gloabls and defaults may be enough
+    #
+    my $dbm_type = $dbh->{dbm_tables}->{$tname}->{type}
+                || $dbh->{dbm_type}
+                || 'SDBM_File';
+    $dbh->{dbm_tables}->{$tname}->{type} = $dbm_type;
+
+    my $serializer = $dbh->{dbm_tables}->{$tname}->{mldbm}
+                  || $dbh->{dbm_mldbm}
+                  || '';
+    $dbh->{dbm_tables}->{$tname}->{mldbm} = $serializer if $serializer;
+
+    my $ext =  '' if $dbm_type eq 'GDBM_File'
+                  or $dbm_type eq 'DB_File'
+                  or $dbm_type eq 'BerkeleyDB';
+    # XXX NDBM_File on FreeBSD (and elsewhere?) may actually be Berkeley
+    # behind the scenes and so create a single .db file.
+    $ext = '.pag' if $dbm_type eq 'NDBM_File'
+                  or $dbm_type eq 'SDBM_File'
+                  or $dbm_type eq 'ODBM_File';
+    $ext = $dbh->{dbm_ext} if defined $dbh->{dbm_ext};
+    $ext = $dbh->{dbm_tables}->{$tname}->{ext}
+        if defined $dbh->{dbm_tables}->{$tname}->{ext};
+    $ext = '' unless defined $ext;
+
+    my $open_mode = O_RDONLY;
+       $open_mode = O_RDWR                 if $lockMode;
+       $open_mode = O_RDWR|O_CREAT|O_TRUNC if $createMode;
+
+    my($tie_type);
+
+    if ( $serializer ) {
+       require 'MLDBM.pm';
+       $MLDBM::UseDB      = $dbm_type;
+       $MLDBM::UseDB      = 'BerkeleyDB::Hash' if $dbm_type eq 'BerkeleyDB';
+       $MLDBM::Serializer = $serializer;
+       $tie_type = 'MLDBM';
+    }
+    else {
+       require "$dbm_type.pm";
+       $tie_type = $dbm_type;
+    }
+
+    # Second-guessing the file extension isn't great here (or in general)
+    # could replace this by trying to open the file in non-create mode
+    # first and dieing if that succeeds.
+    # Currently this test doesn't work where NDBM is actually Berkeley (.db)
+    die "Cannot CREATE '$file$ext' because it already exists"
+        if $createMode and (-e "$file$ext");
+
+    # LOCKING
+    #
+    my($nolock,$lockext,$lock_table);
+    $lockext = $dbh->{dbm_tables}->{$tname}->{lockfile};
+    $lockext = $dbh->{dbm_lockfile} if !defined $lockext;
+    if ( (defined $lockext and $lockext == 0) or !$HAS_FLOCK
+    ) {
+        undef $lockext;
+        $nolock = 1;
+    }
+    else {
+        $lockext ||= '.lck';
+    }
+    # open and flock the lockfile, creating it if necessary
+    #
+    if (!$nolock) {
+        $lock_table = $self->SUPER::open_table(
+            $data, "$table$lockext", $createMode, $lockMode
+        );
+    }
+
+    # TIEING
+    #
+    # allow users to pass in a pre-created tied object
+    #
+    my @tie_args;
+    if ($dbm_type eq 'BerkeleyDB') {
+       my $DB_CREATE = 1;  # but import constants if supplied
+       my $DB_RDONLY = 16; #
+       my %flags;
+       if (my $f = $dbh->{dbm_berkeley_flags}) {
+           $DB_CREATE  = $f->{DB_CREATE} if $f->{DB_CREATE};
+           $DB_RDONLY  = $f->{DB_RDONLY} if $f->{DB_RDONLY};
+           delete $f->{DB_CREATE};
+           delete $f->{DB_RDONLY};
+           %flags = %$f;
+       }
+       $flags{'-Flags'} = $DB_RDONLY;
+       $flags{'-Flags'} = $DB_CREATE if $lockMode or $createMode;
+        my $t = 'BerkeleyDB::Hash';
+           $t = 'MLDBM' if $serializer;
+	@tie_args = ($t, -Filename=>$file, %flags);
+    }
+    else {
+        @tie_args = ($tie_type, $file, $open_mode, 0666);
+    }
+    my %h;
+    if ( $self->{command} ne 'DROP') {
+	my $tie_class = shift @tie_args;
+	eval { tie %h, $tie_class, @tie_args };
+	die "Cannot tie(%h $tie_class @tie_args): $@" if $@;
+    }
+
+
+    # COLUMN NAMES
+    #
+    my $store = $dbh->{dbm_tables}->{$tname}->{store_metadata};
+       $store = $dbh->{dbm_store_metadata} unless defined $store;
+       $store = 1 unless defined $store;
+    $dbh->{dbm_tables}->{$tname}->{store_metadata} = $store;
+
+    my($meta_data,$schema,$col_names);
+    $meta_data = $col_names = $h{"_metadata \0"} if $store;
+    if ($meta_data and $meta_data =~ m~<dbd_metadata>(.+)</dbd_metadata>~is) {
+        $schema  = $col_names = $1;
+        $schema  =~ s~.*<schema>(.+)</schema>.*~$1~is;
+        $col_names =~ s~.*<col_names>(.+)</col_names>.*~$1~is;
+    }
+    $col_names ||= $dbh->{dbm_tables}->{$tname}->{c_cols}
+               || $dbh->{dbm_tables}->{$tname}->{cols}
+               || $dbh->{dbm_cols}
+               || ['k','v'];
+    $col_names = [split /,/,$col_names] if (ref $col_names ne 'ARRAY');
+    $dbh->{dbm_tables}->{$tname}->{cols}   = $col_names;
+    $dbh->{dbm_tables}->{$tname}->{schema} = $schema;
+
+    my $i;
+    my %col_nums  = map { $_ => $i++ } @$col_names;
+
+    my $tbl = {
+	table_name     => $tname,
+	file           => $file,
+	ext            => $ext,
+        hash           => \%h,
+        dbm_type       => $dbm_type,
+        store_metadata => $store,
+        mldbm          => $serializer,
+        lock_fh        => $lock_table->{fh},
+        lock_ext       => $lockext,
+        nolock         => $nolock,
+	col_nums       => \%col_nums,
+	col_names      => $col_names
+    };
+
+    my $class = ref($self);
+    $class =~ s/::Statement/::Table/;
+    bless($tbl, $class);
+    $tbl;
+}
+
+# DELETE is only needed for backward compat with old SQL::Statement
+# it can be removed when the next SQL::Statement is released
+#
+# It is an example though of how you can subclass SQL::Statement/Nano
+# in your DBD ... if you needed to, you could over-ride CREATE
+# SELECT, etc.
+#
+# Note also the use of $dbh->{sql_handler} to differentiate
+# between SQL::Statement and DBI::SQL::Nano
+#
+# Your driver may support only one of those two SQL engines, but
+# your users will have more options if you support both
+#
+# Generally, you don't need to do anything to support both, but
+# if you subclass them like this DELETE function does, you may
+# need some minor changes to support both (similar to the first
+# if statement in DELETE, everything else is the same)
+#
+sub DELETE ($$$) {
+    my($self, $data, $params) = @_;
+    my $dbh   = $data->{Database};
+    my($table,$tname,@where_args);
+    if ($dbh->{sql_handler} eq 'SQL::Statement') {
+       my($eval,$all_cols) = $self->open_tables($data, 0, 1);
+       return undef unless $eval;
+       $eval->params($params);
+       $self->verify_columns($eval, $all_cols);
+       $table = $eval->table($self->tables(0)->name());
+       @where_args = ($eval,$self->tables(0)->name());
+    }
+    else {
+        $table = $self->open_tables($data, 0, 1);
+        $self->verify_columns($table);
+        @where_args = ($table);
+    }
+    my($affected) = 0;
+    my(@rows, $array);
+    if ( $table->can('delete_one_row') ) {
+        while (my $array = $table->fetch_row($data)) {
+            if ($self->eval_where(@where_args,$array)) {
+                ++$affected;
+                $array = $self->{fetched_value} if $self->{fetched_from_key};
+                $table->delete_one_row($data,$array);
+                return ($affected, 0) if $self->{fetched_from_key};
+            }
+        }
+        return ($affected, 0);
+    }
+    while ($array = $table->fetch_row($data)) {
+        if ($self->eval_where($table,$array)) {
+            ++$affected;
+        } else {
+            push(@rows, $array);
+        }
+    }
+    $table->seek($data, 0, 0);
+    foreach $array (@rows) {
+        $table->push_row($data, $array);
+    }
+    $table->truncate($data);
+    return ($affected, 0);
+}
+
+########################
+package DBD::DBM::Table;
+########################
+use base qw( DBD::File::Table );
+
+# you must define drop
+# it is called from execute of a SQL DROP statement
+#
+sub drop ($$) {
+    my($self,$data) = @_;
+    untie %{$self->{hash}} if $self->{hash};
+    my $ext = $self->{ext};
+    unlink $self->{file}.$ext if -f $self->{file}.$ext;
+    unlink $self->{file}.'.dir' if -f $self->{file}.'.dir'
+                               and $ext eq '.pag';
+    if (!$self->{nolock}) {
+        $self->{lock_fh}->close if $self->{lock_fh};
+        unlink $self->{file}.$self->{lock_ext}
+            if -f $self->{file}.$self->{lock_ext};
+    }
+    return 1;
+}
+
+# you must define fetch_row, it is called on all fetches;
+# it MUST return undef when no rows are left to fetch;
+# checking for $ary[0] is specific to hashes so you'll
+# probably need some other kind of check for nothing-left.
+# as Janis might say: "undef's just another word for
+# nothing left to fetch" :-)
+#
+sub fetch_row ($$$) {
+    my($self, $data, $row) = @_;
+    # fetch with %each
+    #
+    my @ary = each %{$self->{hash}};
+    @ary = each %{$self->{hash}} if $self->{store_metadata}
+                                 and $ary[0]
+                                 and $ary[0] eq "_metadata \0";
+
+    return undef unless defined $ary[0];
+    if (ref $ary[1] eq 'ARRAY') {
+       @ary = ( $ary[0], @{$ary[1]} );
+    }
+    return (@ary) if wantarray;
+    return \@ary;
+
+    # fetch without %each
+    #
+    # $self->{keys} = [sort keys %{$self->{hash}}] unless $self->{keys};
+    # my $key = shift @{$self->{keys}};
+    # $key = shift @{$self->{keys}} if $self->{store_metadata}
+    #                             and $key
+    #                             and $key eq "_metadata \0";
+    # return undef unless defined $key;
+    # my @ary;
+    # $row = $self->{hash}->{$key};
+    # if (ref $row eq 'ARRAY') {
+    #   @ary = ( $key, @{$row} );
+    # }
+    # else {
+    #    @ary = ($key,$row);
+    # }
+    # return (@ary) if wantarray;
+    # return \@ary;
+}
+
+# you must define push_row
+# it is called on inserts and updates
+#
+sub push_row ($$$) {
+    my($self, $data, $row_aryref) = @_;
+    my $key = shift @$row_aryref;
+    if ( $self->{mldbm} ) {
+        $self->{hash}->{$key}= $row_aryref;
+    }
+    else {
+        $self->{hash}->{$key}=$row_aryref->[0];
+    }
+    1;
+}
+
+# this is where you grab the column names from a CREATE statement
+# if you don't need to do that, it must be defined but can be empty
+#
+sub push_names ($$$) {
+    my($self, $data, $row_aryref) = @_;
+    $data->{Database}->{dbm_tables}->{$self->{table_name}}->{c_cols}
+       = $row_aryref;
+    next unless $self->{store_metadata};
+    my $stmt = $data->{f_stmt};
+    my $col_names = join ',', @{$row_aryref};
+    my $schema = $data->{Database}->{Statement};
+       $schema =~ s/^[^\(]+\((.+)\)$/$1/s;
+       $schema = $stmt->schema_str if $stmt->can('schema_str');
+    $self->{hash}->{"_metadata \0"} = "<dbd_metadata>"
+                                    . "<schema>$schema</schema>"
+                                    . "<col_names>$col_names</col_names>"
+                                    . "</dbd_metadata>"
+                                    ;
+}
+
+# fetch_one_row, delete_one_row, update_one_row
+# are optimized for hash-style lookup without looping;
+# if you don't need them, omit them, they're optional
+# but, in that case you may need to define
+# truncate() and seek(), see below
+#
+sub fetch_one_row ($$;$) {
+    my($self,$key_only,$value) = @_;
+    return $self->{col_names}->[0] if $key_only;
+    return [$value, $self->{hash}->{$value}];
+}
+sub delete_one_row ($$$) {
+    my($self,$data,$aryref) = @_;
+    delete $self->{hash}->{$aryref->[0]};
+}
+sub update_one_row ($$$) {
+    my($self,$data,$aryref) = @_;
+    my $key = shift @$aryref;
+    return undef unless defined $key;
+    if( ref $aryref->[0] eq 'ARRAY'){
+        return  $self->{hash}->{$key}=$aryref;
+    }
+    $self->{hash}->{$key}=$aryref->[0];
+}
+
+# you may not need to explicitly DESTROY the ::Table
+# put cleanup code to run when the execute is done
+#
+sub DESTROY ($) {
+    my $self=shift;
+    untie %{$self->{hash}} if $self->{hash};
+    # release the flock on the lock file
+    $self->{lock_fh}->close if !$self->{nolock} and $self->{lock_fh};
+}
+
+# truncate() and seek() must be defined to satisfy DBI::SQL::Nano
+# *IF* you define the *_one_row methods above, truncate() and
+# seek() can be empty or you can use them without actually
+# truncating or seeking anything but if you don't define the
+# *_one_row methods, you may need to define these
+
+# if you need to do something after a series of
+# deletes or updates, you can put it in truncate()
+# which is called at the end of executing
+#
+sub truncate ($$) {
+    my($self,$data) = @_;
+    1;
+}
+
+# seek() is only needed if you use IO::File
+# though it could be used for other non-file operations
+# that you need to do before "writes" or truncate()
+#
+sub seek ($$$$) {
+    my($self, $data, $pos, $whence) = @_;
+}
+
+# Th, th, th, that's all folks!  See DBD::File and DBD::CSV for other
+# examples of creating pure perl DBDs.  I hope this helped.
+# Now it's time to go forth and create your own DBD!
+# Remember to check in with dbi-dev@perl.org before you get too far.
+# We may be able to make suggestions or point you to other related
+# projects.
+
+1;
+__END__
+
+=pod
+
+=head1 NAME
+
+DBD::DBM - a DBI driver for DBM & MLDBM files
+
+=head1 SYNOPSIS
+
+ use DBI;
+ $dbh = DBI->connect('dbi:DBM:');                # defaults to SDBM_File
+ $dbh = DBI->connect('DBI:DBM(RaiseError=1):');  # defaults to SDBM_File
+ $dbh = DBI->connect('dbi:DBM:type=GDBM_File');  # defaults to GDBM_File
+ $dbh = DBI->connect('dbi:DBM:mldbm=Storable');  # MLDBM with SDBM_File
+                                                 # and Storable
+
+or
+
+ $dbh = DBI->connect('dbi:DBM:', undef, undef);
+ $dbh = DBI->connect('dbi:DBM:', undef, undef, { dbm_type => 'ODBM_File' });
+
+and other variations on connect() as shown in the DBI docs and with
+the dbm_ attributes shown below
+
+... and then use standard DBI prepare, execute, fetch, placeholders, etc.,
+see L<QUICK START> for an example
+
+=head1 DESCRIPTION
+
+DBD::DBM is a database management sytem that can work right out of the box.  If you have a standard installation of Perl and a standard installation of DBI, you can begin creating, accessing, and modifying database tables without any further installation.  You can also add some other modules to it for more robust capabilities if you wish.
+
+The module uses a DBM file storage layer.  DBM file storage is common on many platforms and files can be created with it in many languges.  That means that, in addition to creating files with DBI/SQL, you can also use DBI/SQL to access and modify files created by other DBM modules and programs.  You can also use those programs to access files created with DBD::DBM.
+
+DBM files are stored in binary format optimized for quick retrieval when using a key field.  That optimization can be used advantageously to make DBD::DBM SQL operations that use key fields very fast.  There are several different "flavors" of DBM - different storage formats supported by different sorts of perl modules such as SDBM_File and MLDBM.  This module supports all of the flavors that perl supports and, when used with MLDBM, supports tables with any number of columns and insertion of Perl objects into tables.
+
+DBD::DBM has been tested with the following DBM types: SDBM_File, NDBM_File, ODBM_File, GDBM_File, DB_File, BerekeleyDB.  Each type was tested both with and without MLDBM.
+
+=head1 QUICK START
+
+DBD::DBM operates like all other DBD drivers - it's basic syntax and operation is specified by DBI.  If you're not familiar with DBI, you should start by reading L<DBI> and the documents it points to and then come back and read this file.  If you are familiar with DBI, you already know most of what you need to know to operate this module.  Just jump in and create a test script something like the one shown below.
+
+You should be aware that there are several options for the SQL engine underlying DBD::DBM, see L<Supported SQL syntax>.  There are also many options for DBM support, see especially the section on L<Adding multi-column support with MLDBM>.
+
+But here's a sample to get you started.
+
+ use DBI;
+ my $dbh = DBI->connect('dbi:DBM:');
+ $dbh->{RaiseError} = 1;
+ for my $sql( split /;\n+/,"
+     CREATE TABLE user ( user_name TEXT, phone TEXT );
+     INSERT INTO user VALUES ('Fred Bloggs','233-7777');
+     INSERT INTO user VALUES ('Sanjay Patel','777-3333');
+     INSERT INTO user VALUES ('Junk','xxx-xxxx');
+     DELETE FROM user WHERE user_name = 'Junk';
+     UPDATE user SET phone = '999-4444' WHERE user_name = 'Sanjay Patel';
+     SELECT * FROM user
+ "){
+     my $sth = $dbh->prepare($sql);
+     $sth->execute;
+     $sth->dump_results if $sth->{NUM_OF_FIELDS};
+ }
+ $dbh->disconnect;
+
+=head1 USAGE
+
+=head2 Specifiying Files and Directories
+
+DBD::DBM will automatically supply an appropriate file extension for the type of DBM you are using.  For example, if you use SDBM_File, a table called "fruit" will be stored in two files called "fruit.pag" and "fruit.dir".  You should I<never> specify the file extensions in your SQL statements.
+
+However, I am not aware (and therefore DBD::DBM is not aware) of all possible extensions for various DBM types.  If your DBM type uses an extension other than .pag and .dir, you should set the I<dbm_ext> attribute to the extension. B<And> you should write me with the name of the implementation and extension so I can add it to DBD::DBM!  Thanks in advance for that :-).
+
+    $dbh = DBI->connect('dbi:DBM:ext=.db');  # .db extension is used
+    $dbh = DBI->connect('dbi:DBM:ext=');     # no extension is used
+
+or
+
+    $dbh->{dbm_ext}='.db';                      # global setting
+    $dbh->{dbm_tables}->{'qux'}->{ext}='.db';   # setting for table 'qux'
+
+By default files are assumed to be in the current working directory.  To have the module look in a different directory, specify the I<f_dir> attribute in either the connect string or by setting the database handle attribute.
+
+For example, this will look for the file /foo/bar/fruit (or /foo/bar/fruit.pag for DBM types that use that extension)
+
+   my $dbh = DBI->connect('dbi:DBM:f_dir=/foo/bar');
+   my $ary = $dbh->selectall_arrayref(q{ SELECT * FROM fruit });
+
+And this will too:
+
+   my $dbh = DBI->connect('dbi:DBM:');
+   $dbh->{f_dir} = '/foo/bar';
+   my $ary = $dbh->selectall_arrayref(q{ SELECT x FROM fruit });
+
+You can also use delimited identifiers to specify paths directly in SQL statements.  This looks in the same place as the two examples above but without setting I<f_dir>:
+
+   my $dbh = DBI->connect('dbi:DBM:');
+   my $ary = $dbh->selectall_arrayref(q{
+       SELECT x FROM "/foo/bar/fruit"
+   });
+
+If you have SQL::Statement installed, you can use table aliases:
+
+   my $dbh = DBI->connect('dbi:DBM:');
+   my $ary = $dbh->selectall_arrayref(q{
+       SELECT f.x FROM "/foo/bar/fruit" AS f
+   });
+
+See the L<GOTCHAS AND WARNINGS> for using DROP on tables.
+
+=head2 Table locking and flock()
+
+Table locking is accomplished using a lockfile which has the same name as the table's file but with the file extension '.lck' (or a lockfile extension that you suppy, see belwo).  This file is created along with the table during a CREATE and removed during a DROP.  Every time the table itself is opened, the lockfile is flocked().  For SELECT, this is an shared lock.  For all other operations, it is an exclusive lock.
+
+Since the locking depends on flock(), it only works on operating systems that support flock().  In cases where flock() is not implemented, DBD::DBM will not complain, it will simply behave as if the flock() had occurred although no actual locking will happen.  Read the documentation for flock() if you need to understand this.
+
+Even on those systems that do support flock(), the locking is only advisory - as is allways the case with flock().  This means that if some other program tries to access the table while DBD::DBM has the table locked, that other program will *succeed* at opening the table.  DBD::DBM's locking only applies to DBD::DBM.  An exception to this would be the situation in which you use a lockfile with the other program that has the same name as the lockfile used in DBD::DBM and that program also uses flock() on that lockfile.  In that case, DBD::DBM and your other program will respect each other's locks.
+
+If you wish to use a lockfile extension other than '.lck', simply specify the dbm_lockfile attribute:
+
+  $dbh = DBI->connect('dbi:DBM:lockfile=.foo');
+  $dbh->{dbm_lockfile} = '.foo';
+  $dbh->{dbm_tables}->{qux}->{lockfile} = '.foo';
+
+If you wish to disable locking, set the dbm_lockfile equal to 0.
+
+  $dbh = DBI->connect('dbi:DBM:lockfile=0');
+  $dbh->{dbm_lockfile} = 0;
+  $dbh->{dbm_tables}->{qux}->{lockfile} = 0;
+
+=head2 Specifying the DBM type
+
+Each "flavor" of DBM stores its files in a different format and has different capabilities and different limitations.  See L<AnyDBM_File> for a comparison of DBM types.
+
+By default, DBD::DBM uses the SDBM_File type of storage since SDBM_File comes with Perl itself.  But if you have other types of DBM storage available, you can use any of them with DBD::DBM also.
+
+You can specify the DBM type using the "dbm_type" attribute which can be set in the connection string or with the $dbh->{dbm_type} attribute for global settings or with the $dbh->{dbm_tables}->{$table_name}->{type} attribute for per-table settings in cases where a single script is accessing more than one kind of DBM file.
+
+In the connection string, just set type=TYPENAME where TYPENAME is any DBM type such as GDBM_File, DB_File, etc.  Do I<not> use MLDBM as your dbm_type, that is set differently, see below.
+
+ my $dbh=DBI->connect('dbi:DBM:');               # uses the default SDBM_File
+ my $dbh=DBI->connect('dbi:DBM:type=GDBM_File'); # uses the GDBM_File
+
+You can also use $dbh->{dbm_type} to set global DBM type:
+
+ $dbh->{dbm_type} = 'GDBM_File';  # set the global DBM type
+ print $dbh->{dbm_type};          # display the global DBM type
+
+If you are going to have several tables in your script that come from different DBM types, you can use the $dbh->{dbm_tables} hash to store different settings for the various tables.  You can even use this to perform joins on files that have completely different storage mechanisms.
+
+ my $dbh->('dbi:DBM:type=GDBM_File');
+ #
+ # sets global default of GDBM_File
+
+ my $dbh->{dbm_tables}->{foo}->{type} = 'DB_File';
+ #
+ # over-rides the global setting, but only for the table called "foo"
+
+ print $dbh->{dbm_tables}->{foo}->{type};
+ #
+ # prints the dbm_type for the table "foo"
+
+=head2 Adding multi-column support with MLDBM
+
+Most of the DBM types only support two columns.  However a CPAN module called MLDBM overcomes this limitation by allowing more than two columns.  It does this by serializing the data - basically it puts a reference to an array into the second column.  It can also put almost any kind of Perl object or even Perl coderefs into columns.
+
+If you want more than two columns, you must install MLDBM.  It's available for many platforms and is easy to install.
+
+MLDBM can use three different modules to serialize the column - Data::Dumper, Storable, and FreezeThaw.  Data::Dumper is the default, Storable is the fastest.  MLDBM can also make use of user-defined serialization methods.  All of this is available to you through DBD::DBM with just one attribute setting.
+
+To use MLDBM with DBD::DBM, you need to set the dbm_mldbm attribute to the name of the serialization module.
+
+Some examples:
+
+ $dbh=DBI->connect('dbi:DBM:mldbm=Storable');  # use MLDBM with Storable
+ $dbh=DBI->connect(
+    'dbi:DBM:mldbm=MySerializer'           # use MLDBM with a user defined module
+ );
+ $dbh->{dbm_mldbm} = 'MySerializer';       # same as above
+ print $dbh->{dbm_mldbm}                   # show the MLDBM serializer
+ $dbh->{dbm_tables}->{foo}->{mldbm}='Data::Dumper';   # set Data::Dumper for table "foo"
+ print $dbh->{dbm_tables}->{foo}->{mldbm}; # show serializer for table "foo"
+
+MLDBM works on top of other DBM modules so you can also set a DBM type along with setting dbm_mldbm.  The examples above would default to using SDBM_File with MLDBM.  If you wanted GDBM_File instead, here's how:
+
+ $dbh = DBI->connect('dbi:DBM:type=GDBM_File;mldbm=Storable');
+ #
+ # uses GDBM_File with MLDBM and Storable
+
+SDBM_File, the default file type is quite limited, so if you are going to use MLDBM, you should probably use a different type, see L<AnyDBM_File>.
+
+See below for some L<GOTCHAS AND WARNINGS> about MLDBM.
+
+=head2 Support for Berkeley DB
+
+The Berkeley DB storage type is supported through two different Perl modules - DB_File (which supports only features in old versions of Berkeley DB) and BerkeleyDB (which supports all versions).  DBD::DBM supports specifying either "DB_File" or "BerkeleyDB" as a I<dbm_type>, with or without MLDBM support.
+
+The "BerkeleyDB" dbm_type is experimental and its interface is likely to chagne.  It currently defaults to BerkeleyDB::Hash and does not currently support ::Btree or ::Recno.
+
+With BerkeleyDB, you can specify initialization flags by setting them in your script like this:
+
+ my $dbh = DBI->connect('dbi:DBM:type=BerkeleyDB;mldbm=Storable');
+ use BerkeleyDB;
+ my $env = new BerkeleyDB::Env -Home => $dir;  # and/or other Env flags
+ $dbh->{dbm_berkeley_flags} = {
+      'DB_CREATE'  => DB_CREATE  # pass in constants
+    , 'DB_RDONLY'  => DB_RDONLY  # pass in constants
+    , '-Cachesize' => 1000       # set a ::Hash flag
+    , '-Env'       => $env       # pass in an environment
+ };
+
+Do I<not> set the -Flags or -Filename flags, those are determined by the SQL (e.g. -Flags => DB_RDONLY is set automatically when you issue a SELECT statement).
+
+Time has not permitted me to provide support in this release of DBD::DBM for further Berkeley DB features such as transactions, concurrency, locking, etc.  I will be working on these in the future and would value suggestions, patches, etc.
+
+See L<DB_File> and L<BerkeleyDB> for further details.
+
+=head2 Supported SQL syntax
+
+DBD::DBM uses a subset of SQL.  The robustness of that subset depends on what other modules you have installed. Both options support basic SQL operations including CREATE TABLE, DROP TABLE, INSERT, DELETE, UPDATE, and SELECT.
+
+B<Option #1:> By default, this module inherits its SQL support from DBI::SQL::Nano that comes with DBI.  Nano is, as its name implies, a *very* small SQL engine.  Although limited in scope, it is faster than option #2 for some operations.  See L<DBI::SQL::Nano> for a description of the SQL it supports and comparisons of it with option #2.
+
+B<Option #2:> If you install the pure Perl CPAN module SQL::Statement, DBD::DBM will use it instead of Nano.  This adds support for table aliases, for functions, for joins, and much more.  If you're going to use DBD::DBM for anything other than very simple tables and queries, you should install SQL::Statement.  You don't have to change DBD::DBM or your scripts in any way, simply installing SQL::Statement will give you the more robust SQL capabilities without breaking scripts written for DBI::SQL::Nano.  See L<SQL::Statement> for a description of the SQL it supports.
+
+To find out which SQL module is working in a given script, you can use the dbm_versions() method or, if you don't need the full output and version numbers, just do this:
+
+ print $dbh->{sql_handler};
+
+That will print out either "SQL::Statement" or "DBI::SQL::Nano".
+
+=head2 Optimizing use of key fields
+
+Most "flavors" of DBM have only two physical columns (but can contain multiple logical columns as explained below).  They work similarly to a Perl hash with the first column serving as the key.  Like a Perl hash, DBM files permit you to do quick lookups by specifying the key and thus avoid looping through all records.  Also like a Perl hash, the keys must be unique.  It is impossible to create two records with the same key.  To put this all more simply and in SQL terms, the key column functions as the PRIMARY KEY.
+
+In DBD::DBM, you can take advantage of the speed of keyed lookups by using a WHERE clause with a single equal comparison on the key field.  For example, the following SQL statements are optimized for keyed lookup:
+
+ CREATE TABLE user ( user_name TEXT, phone TEXT);
+ INSERT INTO user VALUES ('Fred Bloggs','233-7777');
+ # ... many more inserts
+ SELECT phone FROM user WHERE user_name='Fred Bloggs';
+
+The "user_name" column is the key column since it is the first column. The SELECT statement uses the key column in a single equal comparision - "user_name='Fred Bloggs' - so the search will find it very quickly without having to loop through however many names were inserted into the table.
+
+In contrast, thes searches on the same table are not optimized:
+
+ 1. SELECT phone FROM user WHERE user_name < 'Fred';
+ 2. SELECT user_name FROM user WHERE phone = '233-7777';
+
+In #1, the operation uses a less-than (<) comparison rather than an equals comparison, so it will not be optimized for key searching.  In #2, the key field "user_name" is not specified in the WHERE clause, and therefore the search will need to loop through all rows to find the desired result.
+
+=head2 Specifying Column Names
+
+DBM files don't have a standard way to store column names.   DBD::DBM gets around this issue with a DBD::DBM specific way of storing the column names.  B<If you are working only with DBD::DBM and not using files created by or accessed with other DBM programs, you can ignore this section.>
+
+DBD::DBM stores column names as a row in the file with the key I<_metadata \0>.  So this code
+
+ my $dbh = DBI->connect('dbi:DBM:');
+ $dbh->do("CREATE TABLE baz (foo CHAR(10), bar INTEGER)");
+ $dbh->do("INSERT INTO baz (foo,bar) VALUES ('zippy',1)");
+
+Will create a file that has a structure something like this:
+
+  _metadata \0 | foo,bar
+  zippy        | 1
+
+The next time you access this table with DBD::DBM, it will treat the _metadata row as a header rather than as data and will pull the column names from there.  However, if you access the file with something other than DBD::DBM, the row will be treated as a regular data row.
+
+If you do not want the column names stored as a data row in the table you can set the I<dbm_store_metadata> attribute to 0.
+
+ my $dbh = DBI->connect('dbi:DBM:store_metadata=0');
+
+or
+
+ $dbh->{dbm_store_metadata} = 0;
+
+or, for per-table setting
+
+ $dbh->{dbm_tables}->{qux}->{store_metadata} = 0;
+
+By default, DBD::DBM assumes that you have two columns named "k" and "v" (short for "key" and "value").  So if you have I<dbm_store_metadata> set to 1 and you want to use alternate column names, you need to specify the column names like this:
+
+ my $dbh = DBI->connect('dbi:DBM:store_metadata=0;cols=foo,bar');
+
+or
+
+ $dbh->{dbm_store_metadata} = 0;
+ $dbh->{dbm_cols}           = 'foo,bar';
+
+To set the column names on per-table basis, do this:
+
+ $dbh->{dbm_tables}->{qux}->{store_metadata} = 0;
+ $dbh->{dbm_tables}->{qux}->{cols}           = 'foo,bar';
+ #
+ # sets the column names only for table "qux"
+
+If you have a file that was created by another DBM program or created with I<dbm_store_metadata> set to zero and you want to convert it to using DBD::DBM's column name storage, just use one of the methods above to name the columns but *without* specifying I<dbm_store_metadata> as zero.  You only have to do that once - thereafter you can get by without setting either I<dbm_store_metadata> or setting I<dbm_cols> because the names will be stored in the file.
+
+=head2 Statement handle ($sth) attributes and methods
+
+Most statement handle attributes such as NAME, NUM_OF_FIELDS, etc. are available only after an execute.  The same is true of $sth->rows which is available after the execute but does I<not> require a fetch.
+
+=head2 The $dbh->dbm_versions() method
+
+The private method dbm_versions() presents a summary of what other modules are being used at any given time.  DBD::DBM can work with or without many other modules - it can use either SQL::Statement or DBI::SQL::Nano as its SQL engine, it can be run with DBI or DBI::PurePerl, it can use many kinds of DBM modules, and many kinds of serializers when run with MLDBM.  The dbm_versions() method reports on all of that and more.
+
+  print $dbh->dbm_versions;               # displays global settings
+  print $dbh->dbm_versions($table_name);  # displays per table settings
+
+An important thing to note about this method is that when called with no arguments, it displays the *global* settings.  If you over-ride these by setting per-table attributes, these will I<not> be shown unless you specifiy a table name as an argument to the method call.
+
+=head2 Storing Objects
+
+If you are using MLDBM, you can use DBD::DBM to take advantage of its serializing abilities to serialize any Perl object that MLDBM can handle.  To store objects in columns, you should (but don't absolutely need to) declare it as a column of type BLOB (the type is *currently* ignored by the SQL engine, but heh, it's good form).
+
+You *must* use placeholders to insert or refer to the data.
+
+=head1 GOTCHAS AND WARNINGS
+
+Using the SQL DROP command will remove any file that has the name specified in the command with either '.pag' or '.dir' or your {dbm_ext} appended to it.  So
+this be dangerous if you aren't sure what file it refers to:
+
+ $dbh->do(qq{DROP TABLE "/path/to/any/file"});
+
+Each DBM type has limitations.  SDBM_File, for example, can only store values of less than 1,000 characters.  *You* as the script author must ensure that you don't exceed those bounds.  If you try to insert a value that is bigger than the DBM can store, the results will be unpredictable.  See the documentation for whatever DBM you are using for details.
+
+Different DBM implementations return records in different orders.  That means that you can I<not> depend on the order of records unless you use an ORDER BY statement.  DBI::SQL::Nano does not currently support ORDER BY (though it may soon) so if you need ordering, you'll have to install SQL::Statement.
+
+DBM data files are platform-specific.  To move them from one platform to another, you'll need to do something along the lines of dumping your data to CSV on platform #1 and then dumping from CSV to DBM on platform #2.  DBD::AnyData and DBD::CSV can help with that.  There may also be DBM conversion tools for your platforms which would probably be quickest.
+
+When using MLDBM, there is a very powerful serializer - it will allow you to store Perl code or objects in database columns.  When these get de-serialized, they may be evaled - in other words MLDBM (or actually Data::Dumper when used by MLDBM) may take the values and try to execute them in Perl.  Obviously, this can present dangers, so if you don't know what's in a file, be careful before you access it with MLDBM turned on!
+
+See the entire section on L<Table locking and flock()> for gotchas and warnings about the use of flock().
+
+=head1 GETTING HELP, MAKING SUGGESTIONS, AND REPORTING BUGS
+
+If you need help installing or using DBD::DBM, please write to the DBI users mailing list at dbi-users@perl.org or to the comp.lang.perl.modules newsgroup on usenet.  I'm afraid I can't always answer these kinds of questions quickly and there are many on the mailing list or in the newsgroup who can.
+
+If you have suggestions, ideas for improvements, or bugs to report, please write me directly at the email shown below.
+
+When reporting bugs, please send the output of $dbh->dbm_versions($table) for a table that exhibits the bug and, if possible, as small a sample as you can make of the code that produces the bug.  And of course, patches are welcome too :-).
+
+=head1 ACKNOWLEDGEMENTS
+
+Many, many thanks to Tim Bunce for prodding me to write this, and for copious, wise, and patient suggestions all along the way.
+
+=head1 AUTHOR AND COPYRIGHT
+
+This module is written and maintained by
+
+Jeff Zucker < jzucker AT cpan.org >
+
+Copyright (c) 2004 by Jeff Zucker, all rights reserved.
+
+You may freely distribute and/or modify this module under the terms of either the GNU General Public License (GPL) or the Artistic License, as specified in the Perl README file.
+
+=head1 SEE ALSO
+
+L<DBI>, L<SQL::Statement>, L<DBI::SQL::Nano>, L<AnyDBM_File>, L<MLDBM>
+
+=cut
+
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBD/ExampleP.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBD/ExampleP.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBD/ExampleP.pm	(revision 14139)
@@ -0,0 +1,411 @@
+{
+    package DBD::ExampleP;
+
+    use Symbol;
+
+    use DBI qw(:sql_types);
+
+    @EXPORT = qw(); # Do NOT @EXPORT anything.
+    $VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/o);
+
+#   $Id$
+#
+#   Copyright (c) 1994,1997,1998 Tim Bunce
+#
+#   You may distribute under the terms of either the GNU General Public
+#   License or the Artistic License, as specified in the Perl README file.
+
+    @statnames = qw(dev ino mode nlink
+	uid gid rdev size
+	atime mtime ctime
+	blksize blocks name);
+    @statnames{@statnames} = (0 .. @statnames-1);
+
+    @stattypes = (SQL_INTEGER, SQL_INTEGER, SQL_INTEGER, SQL_INTEGER,
+	SQL_INTEGER, SQL_INTEGER, SQL_INTEGER, SQL_INTEGER,
+	SQL_INTEGER, SQL_INTEGER, SQL_INTEGER,
+	SQL_INTEGER, SQL_INTEGER, SQL_VARCHAR);
+    @stattypes{@statnames} = @stattypes;
+    @statprec = ((10) x (@statnames-1), 1024);
+    @statprec{@statnames} = @statprec;
+    die unless @statnames == @stattypes;
+    die unless @statprec  == @stattypes;
+
+    $drh = undef;	# holds driver handle once initialised
+    #$gensym = "SYM000"; # used by st::execute() for filehandles
+
+    sub driver{
+	return $drh if $drh;
+	my($class, $attr) = @_;
+	$class .= "::dr";
+	($drh) = DBI::_new_drh($class, {
+	    'Name' => 'ExampleP',
+	    'Version' => $VERSION,
+	    'Attribution' => 'DBD Example Perl stub by Tim Bunce',
+	    }, ['example implementors private data '.__PACKAGE__]);
+	$drh;
+    }
+
+    sub CLONE {
+	undef $drh;
+    }
+}
+
+
+{   package DBD::ExampleP::dr; # ====== DRIVER ======
+    $imp_data_size = 0;
+    use strict;
+
+    sub connect { # normally overridden, but a handy default
+        my($drh, $dbname, $user, $auth)= @_;
+        my ($outer, $dbh) = DBI::_new_dbh($drh, { Name => $dbname });
+        $dbh->STORE('Active', 1);
+        $dbh->{examplep_get_info} = {};
+        return $outer;
+    }
+
+    sub data_sources {
+	return ("dbi:ExampleP:dir=.");	# possibly usefully meaningless
+    }
+
+    sub DESTROY { undef }
+}
+
+
+{   package DBD::ExampleP::db; # ====== DATABASE ======
+    $imp_data_size = 0;
+    use strict;
+
+    sub prepare {
+	my($dbh, $statement)= @_;
+	my @fields;
+	my($fields, $dir) = $statement =~ m/^\s*select\s+(.*?)\s+from\s+(\S*)/i;
+
+	if (defined $fields and defined $dir) {
+	    @fields = ($fields eq '*')
+			? keys %DBD::ExampleP::statnames
+			: split(/\s*,\s*/, $fields);
+	}
+	else {
+	    return $dbh->set_err(1, "Syntax error in select statement (\"$statement\")")
+		unless $statement =~ m/^\s*set\s+/;
+	    # the SET syntax is just a hack so the ExampleP driver can
+	    # be used to test non-select statements.
+	    # No we have DBI::DBM etc ExampleP should be deprecated
+	}
+
+	my ($outer, $sth) = DBI::_new_sth($dbh, {
+	    'Statement'     => $statement,
+	}, ['example implementors private data '.__PACKAGE__]);
+
+	my @bad = map {
+	    defined $DBD::ExampleP::statnames{$_} ? () : $_
+	} @fields;
+	return $dbh->set_err(1, "Unknown field names: @bad")
+		if @bad;
+
+	$outer->STORE('NUM_OF_FIELDS' => scalar(@fields));
+
+	$sth->{dbd_ex_dir} = $dir if defined($dir) && $dir !~ /\?/;
+	$outer->STORE('NUM_OF_PARAMS' => ($dir) ? $dir =~ tr/?/?/ : 0);
+
+	if (@fields) {
+	    $outer->STORE('NAME'     => \@fields);
+	    $outer->STORE('NULLABLE' => [ (0) x @fields ]);
+	    $outer->STORE('SCALE'    => [ (0) x @fields ]);
+	}
+
+	$outer;
+    }
+
+
+    sub table_info {
+	my $dbh = shift;
+	my ($catalog, $schema, $table, $type) = @_;
+
+	my @types = split(/["']*,["']/, $type || 'TABLE');
+	my %types = map { $_=>$_ } @types;
+
+	# Return a list of all subdirectories
+	my $dh = Symbol::gensym(); # "DBD::ExampleP::".++$DBD::ExampleP::gensym;
+	my $haveFileSpec = eval { require File::Spec };
+	my $dir = $haveFileSpec ? File::Spec->curdir() : ".";
+	my @list;
+	if ($types{VIEW}) {	# for use by test harness
+	    push @list, [ undef, "schema",  "table",  'VIEW', undef ];
+	    push @list, [ undef, "sch-ema", "table",  'VIEW', undef ];
+	    push @list, [ undef, "schema",  "ta-ble", 'VIEW', undef ];
+	    push @list, [ undef, "sch ema", "table",  'VIEW', undef ];
+	    push @list, [ undef, "schema",  "ta ble", 'VIEW', undef ];
+	}
+	if ($types{TABLE}) {
+	    no strict 'refs';
+	    opendir($dh, $dir)
+		or return $dbh->set_err(int($!),
+					"Failed to open directory $dir: $!");
+	    while (defined(my $file = readdir($dh))) {
+		next unless -d $file;
+		my($dev, $ino, $mode, $nlink, $uid) = lstat($file);
+		my $pwnam = undef; # eval { scalar(getpwnam($uid)) } || $uid;
+		push @list, [ $dir, $pwnam, $file, 'TABLE', undef ];
+	    }
+	    close($dh);
+	}
+	# We would like to simply do a DBI->connect() here. However,
+	# this is wrong if we are in a subclass like DBI::ProxyServer.
+	$dbh->{'dbd_sponge_dbh'} ||= DBI->connect("DBI:Sponge:", '','')
+	    or return $dbh->set_err($DBI::err,
+			"Failed to connect to DBI::Sponge: $DBI::errstr");
+
+	my $attr = {
+	    'rows' => \@list,
+	    'NUM_OF_FIELDS' => 5,
+	    'NAME' => ['TABLE_CAT', 'TABLE_SCHEM', 'TABLE_NAME',
+		    'TABLE_TYPE', 'REMARKS'],
+	    'TYPE' => [DBI::SQL_VARCHAR(), DBI::SQL_VARCHAR(),
+		    DBI::SQL_VARCHAR(), DBI::SQL_VARCHAR(), DBI::SQL_VARCHAR() ],
+	    'NULLABLE' => [1, 1, 1, 1, 1]
+	};
+	my $sdbh = $dbh->{'dbd_sponge_dbh'};
+	my $sth = $sdbh->prepare("SHOW TABLES FROM $dir", $attr)
+	    or return $dbh->set_err($sdbh->err(), $sdbh->errstr());
+	$sth;
+    }
+
+
+    sub type_info_all {
+	my ($dbh) = @_;
+	my $ti = [
+	    {	TYPE_NAME	=> 0,
+		DATA_TYPE	=> 1,
+		COLUMN_SIZE	=> 2,
+		LITERAL_PREFIX	=> 3,
+		LITERAL_SUFFIX	=> 4,
+		CREATE_PARAMS	=> 5,
+		NULLABLE	=> 6,
+		CASE_SENSITIVE	=> 7,
+		SEARCHABLE	=> 8,
+		UNSIGNED_ATTRIBUTE=> 9,
+		FIXED_PREC_SCALE=> 10,
+		AUTO_UNIQUE_VALUE => 11,
+		LOCAL_TYPE_NAME	=> 12,
+		MINIMUM_SCALE	=> 13,
+		MAXIMUM_SCALE	=> 14,
+	    },
+	    [ 'VARCHAR', DBI::SQL_VARCHAR, 1024, "'","'", undef, 0, 1, 1, 0, 0,0,undef,0,0 ],
+	    [ 'INTEGER', DBI::SQL_INTEGER,   10, "","",   undef, 0, 0, 1, 0, 0,0,undef,0,0 ],
+	];
+	return $ti;
+    }
+
+
+    sub disconnect {
+	shift->STORE(Active => 0);
+	return 1;
+    }
+
+
+    sub get_info {
+	my ($dbh, $info_type) = @_;
+	return $dbh->{examplep_get_info}->{$info_type};
+    }
+
+
+    sub FETCH {
+	my ($dbh, $attrib) = @_;
+	# In reality this would interrogate the database engine to
+	# either return dynamic values that cannot be precomputed
+	# or fetch and cache attribute values too expensive to prefetch.
+	# else pass up to DBI to handle
+	return $INC{"DBD/ExampleP.pm"} if $attrib eq 'example_driver_path';
+	return $dbh->SUPER::FETCH($attrib);
+    }
+
+
+    sub STORE {
+	my ($dbh, $attrib, $value) = @_;
+	# would normally validate and only store known attributes
+	# else pass up to DBI to handle
+	if ($attrib eq 'AutoCommit') {
+	    # convert AutoCommit values to magic ones to let DBI
+	    # know that the driver has 'handled' the AutoCommit attribute
+	    $value = ($value) ? -901 : -900;
+	}
+	return $dbh->{$attrib} = $value if $attrib =~ /^examplep_/;
+	return $dbh->SUPER::STORE($attrib, $value);
+    }
+
+    sub DESTROY {
+	my $dbh = shift;
+	$dbh->disconnect if $dbh->FETCH('Active');
+	undef
+    }
+
+
+    # This is an example to demonstrate the use of driver-specific
+    # methods via $dbh->func().
+    # Use it as follows:
+    #   my @tables = $dbh->func($re, 'examplep_tables');
+    #
+    # Returns all the tables that match the regular expression $re.
+    sub examplep_tables {
+	my $dbh = shift; my $re = shift;
+	grep { $_ =~ /$re/ } $dbh->tables();
+    }
+
+    sub parse_trace_flag {
+	my ($h, $name) = @_;
+	return 0x01000000 if $name eq 'foo';
+	return 0x02000000 if $name eq 'bar';
+	return 0x04000000 if $name eq 'baz';
+	return 0x08000000 if $name eq 'boo';
+	return 0x10000000 if $name eq 'bop';
+	return $h->SUPER::parse_trace_flag($name);
+    }
+
+}
+
+
+{   package DBD::ExampleP::st; # ====== STATEMENT ======
+    $imp_data_size = 0;
+    use strict; no strict 'refs'; # cause problems with filehandles
+
+    my $haveFileSpec = eval { require File::Spec };
+
+    sub bind_param {
+	my($sth, $param, $value, $attribs) = @_;
+	$sth->{'dbd_param'}->[$param-1] = $value;
+	return 1;
+    }
+
+
+    sub execute {
+	my($sth, @dir) = @_;
+	my $dir;
+
+	if (@dir) {
+	    $sth->bind_param($_, $dir[$_-1]) or return
+		foreach (1..@dir);
+	}
+
+	my $dbd_param = $sth->{'dbd_param'} || [];
+	return $sth->set_err(2, @$dbd_param." values bound when $sth->{NUM_OF_PARAMS} expected")
+	    unless @$dbd_param == $sth->{NUM_OF_PARAMS};
+
+	return 0 unless $sth->{NUM_OF_FIELDS}; # not a select
+
+	$dir = $dbd_param->[0] || $sth->{dbd_ex_dir};
+	return $sth->set_err(2, "No bind parameter supplied")
+	    unless defined $dir;
+
+	$sth->finish;
+
+	#
+	# If the users asks for directory "long_list_4532", then we fake a
+	# directory with files "file4351", "file4350", ..., "file0".
+	# This is a special case used for testing, especially DBD::Proxy.
+	#
+	if ($dir =~ /^long_list_(\d+)$/) {
+	    $sth->{dbd_dir} = [ $1 ];	# array ref indicates special mode
+	    $sth->{dbd_datahandle} = undef;
+	}
+	else {
+	    $sth->{dbd_dir} = $dir;
+	    $sth->{dbd_datahandle} = Symbol::gensym(); # "DBD::ExampleP::".++$DBD::ExampleP::gensym;
+	    opendir($sth->{dbd_datahandle}, $dir)
+		or return $sth->set_err(2, "opendir($dir): $!");
+	}
+	$sth->STORE(Active => 1);
+	return 1;
+    }
+
+
+    sub fetch {
+	my $sth = shift;
+	my $dh  = $sth->{dbd_datahandle};
+	my $dir = $sth->{dbd_dir};
+	my %s;
+
+	if (ref $dir) {		# special fake-data test mode
+	    my $num = $dir->[0]--;
+	    unless ($num > 0) {
+		$sth->finish();
+		return;
+	    }
+	    my $time = time;
+	    @s{@DBD::ExampleP::statnames} =
+		( 2051, 1000+$num, 0644, 2, $>, $), 0, 1024,
+	          $time, $time, $time, 512, 2, "file$num")
+	}
+	else {			# normal mode
+	    my $f = readdir($dh);
+	    unless ($f) {
+		$sth->finish;
+		return;
+	    }
+	    # untaint $f so that we can use this for DBI taint tests
+	    ($f) = ($f =~ m/^(.*)$/);
+	    my $file = $haveFileSpec
+		? File::Spec->catfile($dir, $f) : "$dir/$f";
+	    # put in all the data fields
+	    @s{ @DBD::ExampleP::statnames } = (lstat($file), $f);
+	}
+
+	# return just what fields the query asks for
+	my @new = @s{ @{$sth->{NAME}} };
+
+	return $sth->_set_fbav(\@new);
+    }
+    *fetchrow_arrayref = \&fetch;
+
+
+    sub finish {
+	my $sth = shift;
+	closedir($sth->{dbd_datahandle}) if $sth->{dbd_datahandle};
+	$sth->{dbd_datahandle} = undef;
+	$sth->{dbd_dir} = undef;
+	$sth->SUPER::finish();
+	return 1;
+    }
+
+
+    sub FETCH {
+	my ($sth, $attrib) = @_;
+	# In reality this would interrogate the database engine to
+	# either return dynamic values that cannot be precomputed
+	# or fetch and cache attribute values too expensive to prefetch.
+	if ($attrib eq 'TYPE'){
+	    return [ @DBD::ExampleP::stattypes{ @{ $sth->FETCH(q{NAME_lc}) } } ];
+	}
+	elsif ($attrib eq 'PRECISION'){
+	    return [ @DBD::ExampleP::statprec{  @{ $sth->FETCH(q{NAME_lc}) } } ];
+	}
+	elsif ($attrib eq 'ParamValues') {
+	    my $dbd_param = $sth->{dbd_param} || [];
+	    my %pv = map { $_ => $dbd_param->[$_-1] } 1..@$dbd_param;
+	    return \%pv;
+	}
+	# else pass up to DBI to handle
+	return $sth->SUPER::FETCH($attrib);
+    }
+
+
+    sub STORE {
+	my ($sth, $attrib, $value) = @_;
+	# would normally validate and only store known attributes
+	# else pass up to DBI to handle
+	return $sth->{$attrib} = $value
+	    if $attrib eq 'NAME' or $attrib eq 'NULLABLE' or $attrib eq 'SCALE' or $attrib eq 'PRECISION';
+	return $sth->SUPER::STORE($attrib, $value);
+    }
+
+    sub DESTROY {
+	my $sth = shift;
+	$sth->finish if $sth->SUPER::FETCH('Active');
+    }
+
+    *parse_trace_flag = \&DBD::ExampleP::db::parse_trace_flag;
+}
+
+1;
+# vim: sw=4:ts=8
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBD/File.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBD/File.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBD/File.pm	(revision 14139)
@@ -0,0 +1,798 @@
+# -*- perl -*-
+#
+#   DBD::File - A base class for implementing DBI drivers that
+#               act on plain files
+#
+#  This module is currently maintained by
+#
+#      Jeff Zucker < jzucker AT cpan.org >
+#
+#  The original author is Jochen Wiedmann.
+#
+#  Copyright (C) 2004 by Jeff Zucker
+#  Copyright (C) 1998 by Jochen Wiedmann
+#
+#  All rights reserved.
+#
+#  You may distribute this module under the terms of either the GNU
+#  General Public License or the Artistic License, as specified in
+#  the Perl README file.
+#
+require 5.004;
+use strict;
+
+use DBI ();
+require DBI::SQL::Nano;
+my $haveFileSpec = eval { require File::Spec };
+
+package DBD::File;
+
+use vars qw(@ISA $VERSION $drh $valid_attrs);
+
+$VERSION = '0.33';
+
+$drh = undef;		# holds driver handle(s) once initialised
+
+sub driver ($;$) {
+    my($class, $attr) = @_;
+
+    # Drivers typically use a singleton object for the $drh
+    # We use a hash here to have one singleton per subclass.
+    # (Otherwise DBD::CSV and DBD::DBM, for example, would
+    # share the same driver object which would cause problems.)
+    # An alternative would be not not cache the $drh here at all
+    # and require that subclasses do that. Subclasses should do
+    # their own caching, so caching here just provides extra safety.
+    return $drh->{$class} if $drh->{$class};
+
+    DBI->setup_driver('DBD::File'); # only needed once but harmless to repeat
+    $attr ||= {};
+    no strict qw(refs);
+    if (!$attr->{Attribution}) {
+	$attr->{Attribution} = "$class by Jeff Zucker"
+	    if $class eq 'DBD::File';
+	$attr->{Attribution} ||= ${$class . '::ATTRIBUTION'}
+	    || "oops the author of $class forgot to define this";
+    }
+    $attr->{Version} ||= ${$class . '::VERSION'};
+    ($attr->{Name} = $class) =~ s/^DBD\:\:// unless $attr->{Name};
+
+    $drh->{$class} = DBI::_new_drh($class . "::dr", $attr);
+    $drh->{$class}->STORE(ShowErrorStatement => 1);
+    return $drh->{$class};
+}
+
+sub CLONE {
+    undef $drh;
+}
+
+package DBD::File::dr; # ====== DRIVER ======
+
+$DBD::File::dr::imp_data_size = 0;
+
+sub connect ($$;$$$) {
+    my($drh, $dbname, $user, $auth, $attr)= @_;
+
+    # create a 'blank' dbh
+    my $this = DBI::_new_dbh($drh, {
+	'Name' => $dbname,
+	'USER' => $user,
+	'CURRENT_USER' => $user,
+    });
+
+    if ($this) {
+	my($var, $val);
+	$this->{f_dir} = $haveFileSpec ? File::Spec->curdir() : '.';
+	while (length($dbname)) {
+	    if ($dbname =~ s/^((?:[^\\;]|\\.)*?);//s) {
+		$var = $1;
+	    } else {
+		$var = $dbname;
+		$dbname = '';
+	    }
+	    if ($var =~ /^(.+?)=(.*)/s) {
+		$var = $1;
+		($val = $2) =~ s/\\(.)/$1/g;
+		$this->{$var} = $val;
+	    }
+	}
+        $this->{f_valid_attrs} = {
+            f_version    => 1  # DBD::File version
+          , f_dir        => 1  # base directory
+          , f_tables     => 1  # base directory
+        };
+        $this->{sql_valid_attrs} = {
+            sql_handler           => 1  # Nano or S:S
+          , sql_nano_version      => 1  # Nano version
+          , sql_statement_version => 1  # S:S version
+        };
+    }
+    $this->STORE('Active',1);
+    return set_versions($this);
+}
+
+sub set_versions {
+    my $this = shift;
+    $this->{f_version} = $DBD::File::VERSION;
+    for (qw( nano_version statement_version)) {
+        $this->{'sql_'.$_} = $DBI::SQL::Nano::versions->{$_}||'';
+    }
+    $this->{sql_handler} = ($this->{sql_statement_version})
+                         ? 'SQL::Statement'
+	                 : 'DBI::SQL::Nano';
+    return $this;
+}
+
+sub data_sources ($;$) {
+    my($drh, $attr) = @_;
+    my($dir) = ($attr and exists($attr->{'f_dir'})) ?
+	$attr->{'f_dir'} : $haveFileSpec ? File::Spec->curdir() : '.';
+    my($dirh) = Symbol::gensym();
+    if (!opendir($dirh, $dir)) {
+        $drh->set_err(1, "Cannot open directory $dir: $!");
+	return undef;
+    }
+    my($file, @dsns, %names, $driver);
+    if ($drh->{'ImplementorClass'} =~ /^dbd\:\:([^\:]+)\:\:/i) {
+	$driver = $1;
+    } else {
+	$driver = 'File';
+    }
+    while (defined($file = readdir($dirh))) {
+	my $d = $haveFileSpec ?
+	    File::Spec->catdir($dir, $file) : "$dir/$file";
+        # allow current dir ... it can be a data_source too
+	if ( $file ne ($haveFileSpec ? File::Spec->updir() : '..')
+	    and  -d $d) {
+	    push(@dsns, "DBI:$driver:f_dir=$d");
+	}
+    }
+    @dsns;
+}
+
+sub disconnect_all {
+}
+
+sub DESTROY {
+    undef;
+}
+
+
+package DBD::File::db; # ====== DATABASE ======
+
+$DBD::File::db::imp_data_size = 0;
+
+sub ping { return (shift->FETCH('Active')) ? 1 : 0 };
+
+sub prepare ($$;@) {
+    my($dbh, $statement, @attribs)= @_;
+
+    # create a 'blank' sth
+    my $sth = DBI::_new_sth($dbh, {'Statement' => $statement});
+
+    if ($sth) {
+	my $class = $sth->FETCH('ImplementorClass');
+	$class =~ s/::st$/::Statement/;
+	my($stmt);
+
+        # if using SQL::Statement version > 1
+        # cache the parser object if the DBD supports parser caching
+        # SQL::Nano and older SQL::Statements don't support this
+
+	if ( $dbh->{sql_handler} eq 'SQL::Statement'
+             and $dbh->{sql_statement_version} > 1)
+           {
+            my $parser = $dbh->{csv_sql_parser_object};
+            $parser ||= eval { $dbh->func('csv_cache_sql_parser_object') };
+            if ($@) {
+  	        $stmt = eval { $class->new($statement) };
+	    }
+            else {
+  	        $stmt = eval { $class->new($statement,$parser) };
+	    }
+        }
+        else {
+	    $stmt = eval { $class->new($statement) };
+	}
+	if ($@) {
+	    $dbh->set_err(1, $@);
+	    undef $sth;
+	} else {
+	    $sth->STORE('f_stmt', $stmt);
+	    $sth->STORE('f_params', []);
+	    $sth->STORE('NUM_OF_PARAMS', scalar($stmt->params()));
+	}
+    }
+    $sth;
+}
+sub csv_cache_sql_parser_object {
+    my $dbh = shift;
+    my $parser = {
+            dialect    => 'CSV',
+            RaiseError => $dbh->FETCH('RaiseError'),
+            PrintError => $dbh->FETCH('PrintError'),
+        };
+    my $sql_flags  = $dbh->FETCH('sql_flags') || {};
+    %$parser = (%$parser,%$sql_flags);
+    $parser = SQL::Parser->new($parser->{dialect},$parser);
+    $dbh->{csv_sql_parser_object} = $parser;
+    return $parser;
+}
+sub disconnect ($) {
+    shift->STORE('Active',0);
+    1;
+}
+sub FETCH ($$) {
+    my ($dbh, $attrib) = @_;
+    if ($attrib eq 'AutoCommit') {
+	return 1;
+    } elsif ($attrib eq (lc $attrib)) {
+	# Driver private attributes are lower cased
+
+        # Error-check for valid attributes
+        # not implemented yet, see STORE
+        #
+        return $dbh->{$attrib};
+    }
+    # else pass up to DBI to handle
+    return $dbh->SUPER::FETCH($attrib);
+}
+
+sub STORE ($$$) {
+    my ($dbh, $attrib, $value) = @_;
+
+    if ($attrib eq 'AutoCommit') {
+	return 1 if $value; # is already set
+	die("Can't disable AutoCommit");
+    } elsif ($attrib eq (lc $attrib)) {
+	# Driver private attributes are lower cased
+
+  # I'm not implementing this yet becuase other drivers may be
+  # setting f_ and sql_ attrs I don't know about
+  # I'll investigate and publicize warnings to DBD authors
+  # then implement this
+  #
+        # return to implementor if not f_ or sql_
+        # not implemented yet
+        # my $class = $dbh->FETCH('ImplementorClass');
+        #
+        # if ( !$dbh->{f_valid_attrs}->{$attrib}
+        # and !$dbh->{sql_valid_attrs}->{$attrib}
+        # ) {
+	#    return $dbh->set_err( 1,"Invalid attribute '$attrib'");
+        # }
+        # else {
+  	#    $dbh->{$attrib} = $value;
+	# }
+
+        if ($attrib eq 'f_dir') {
+  	    return $dbh->set_err( 1,"No such directory '$value'")
+                unless -d $value;
+	}
+	$dbh->{$attrib} = $value;
+	return 1;
+    }
+    return $dbh->SUPER::STORE($attrib, $value);
+}
+
+sub DESTROY ($) {
+    my $dbh = shift;
+    $dbh->disconnect if $dbh->SUPER::FETCH('Active');
+}
+
+sub type_info_all ($) {
+    [
+     {   TYPE_NAME         => 0,
+	 DATA_TYPE         => 1,
+	 PRECISION         => 2,
+	 LITERAL_PREFIX    => 3,
+	 LITERAL_SUFFIX    => 4,
+	 CREATE_PARAMS     => 5,
+	 NULLABLE          => 6,
+	 CASE_SENSITIVE    => 7,
+	 SEARCHABLE        => 8,
+	 UNSIGNED_ATTRIBUTE=> 9,
+	 MONEY             => 10,
+	 AUTO_INCREMENT    => 11,
+	 LOCAL_TYPE_NAME   => 12,
+	 MINIMUM_SCALE     => 13,
+	 MAXIMUM_SCALE     => 14,
+     },
+     [ 'VARCHAR', DBI::SQL_VARCHAR(),
+       undef, "'","'", undef,0, 1,1,0,0,0,undef,1,999999
+       ],
+     [ 'CHAR', DBI::SQL_CHAR(),
+       undef, "'","'", undef,0, 1,1,0,0,0,undef,1,999999
+       ],
+     [ 'INTEGER', DBI::SQL_INTEGER(),
+       undef,  "", "", undef,0, 0,1,0,0,0,undef,0,  0
+       ],
+     [ 'REAL', DBI::SQL_REAL(),
+       undef,  "", "", undef,0, 0,1,0,0,0,undef,0,  0
+       ],
+     [ 'BLOB', DBI::SQL_LONGVARBINARY(),
+       undef, "'","'", undef,0, 1,1,0,0,0,undef,1,999999
+       ],
+     [ 'BLOB', DBI::SQL_LONGVARBINARY(),
+       undef, "'","'", undef,0, 1,1,0,0,0,undef,1,999999
+       ],
+     [ 'TEXT', DBI::SQL_LONGVARCHAR(),
+       undef, "'","'", undef,0, 1,1,0,0,0,undef,1,999999
+       ]
+     ]
+}
+
+
+{
+    my $names = ['TABLE_QUALIFIER', 'TABLE_OWNER', 'TABLE_NAME',
+                 'TABLE_TYPE', 'REMARKS'];
+
+    sub table_info ($) {
+	my($dbh) = @_;
+	my($dir) = $dbh->{f_dir};
+	my($dirh) = Symbol::gensym();
+	if (!opendir($dirh, $dir)) {
+	    $dbh->set_err(1, "Cannot open directory $dir: $!");
+	    return undef;
+	}
+	my($file, @tables, %names);
+	while (defined($file = readdir($dirh))) {
+	    if ($file ne '.'  &&  $file ne '..'  &&  -f "$dir/$file") {
+		my $user = eval { getpwuid((stat(_))[4]) };
+		push(@tables, [undef, $user, $file, "TABLE", undef]);
+	    }
+	}
+	if (!closedir($dirh)) {
+	    $dbh->set_err(1, "Cannot close directory $dir: $!");
+	    return undef;
+	}
+
+	my $dbh2 = $dbh->{'csv_sponge_driver'};
+	if (!$dbh2) {
+	    $dbh2 = $dbh->{'csv_sponge_driver'} = DBI->connect("DBI:Sponge:");
+	    if (!$dbh2) {
+	        $dbh->set_err(1, $DBI::errstr);
+		return undef;
+	    }
+	}
+
+	# Temporary kludge: DBD::Sponge dies if @tables is empty. :-(
+	return undef if !@tables;
+
+	my $sth = $dbh2->prepare("TABLE_INFO", { 'rows' => \@tables,
+						 'NAMES' => $names });
+	if (!$sth) {
+	    $dbh->set_err(1, $dbh2->errstr);
+	}
+	$sth;
+    }
+}
+sub list_tables ($) {
+    my $dbh = shift;
+    my($sth, @tables);
+    if (!($sth = $dbh->table_info())) {
+	return ();
+    }
+    while (my $ref = $sth->fetchrow_arrayref()) {
+	push(@tables, $ref->[2]);
+    }
+    @tables;
+}
+
+sub quote ($$;$) {
+    my($self, $str, $type) = @_;
+    if (defined($type)  &&
+	($type == DBI::SQL_NUMERIC()   ||
+	 $type == DBI::SQL_DECIMAL()   ||
+	 $type == DBI::SQL_INTEGER()   ||
+	 $type == DBI::SQL_SMALLINT()  ||
+	 $type == DBI::SQL_FLOAT()     ||
+	 $type == DBI::SQL_REAL()      ||
+	 $type == DBI::SQL_DOUBLE()    ||
+	 $type == DBI::TINYINT())) {
+	return $str;
+    }
+    if (!defined($str)) { return "NULL" }
+    $str =~ s/\\/\\\\/sg;
+    $str =~ s/\0/\\0/sg;
+    $str =~ s/\'/\\\'/sg;
+    $str =~ s/\n/\\n/sg;
+    $str =~ s/\r/\\r/sg;
+    "'$str'";
+}
+
+sub commit ($) {
+    my($dbh) = shift;
+    if ($dbh->FETCH('Warn')) {
+	warn("Commit ineffective while AutoCommit is on", -1);
+    }
+    1;
+}
+
+sub rollback ($) {
+    my($dbh) = shift;
+    if ($dbh->FETCH('Warn')) {
+	warn("Rollback ineffective while AutoCommit is on", -1);
+    }
+    0;
+}
+
+package DBD::File::st; # ====== STATEMENT ======
+
+$DBD::File::st::imp_data_size = 0;
+
+sub bind_param ($$$;$) {
+    my($sth, $pNum, $val, $attr) = @_;
+    $sth->{f_params}->[$pNum-1] = $val;
+    1;
+}
+
+sub execute {
+    my $sth = shift;
+    my $params;
+    if (@_) {
+	$sth->{'f_params'} = ($params = [@_]);
+    } else {
+	$params = $sth->{'f_params'};
+    }
+
+    $sth->finish;
+    my $stmt = $sth->{'f_stmt'};
+    my $result = eval { $stmt->execute($sth, $params); };
+    return $sth->set_err(1,$@) if $@;
+    if ($stmt->{'NUM_OF_FIELDS'}) { # is a SELECT statement
+	$sth->STORE(Active => 1);
+	$sth->STORE('NUM_OF_FIELDS', $stmt->{'NUM_OF_FIELDS'})
+	 if !$sth->FETCH('NUM_OF_FIELDS');
+    }
+    return $result;
+}
+sub finish {
+    my $sth = shift;
+    $sth->SUPER::STORE(Active => 0);
+    delete $sth->{f_stmt}->{data};
+    return 1;
+}
+sub fetch ($) {
+    my $sth = shift;
+    my $data = $sth->{f_stmt}->{data};
+    if (!$data  ||  ref($data) ne 'ARRAY') {
+	$sth->set_err(1, "Attempt to fetch row from a Non-SELECT statement");
+	return undef;
+    }
+    my $dav = shift @$data;
+    if (!$dav) {
+        $sth->finish;
+	return undef;
+    }
+    if ($sth->FETCH('ChopBlanks')) {
+	map { $_ =~ s/\s+$// if $_; $_ } @$dav;
+    }
+    $sth->_set_fbav($dav);
+}
+*fetchrow_arrayref = \&fetch;
+
+sub FETCH ($$) {
+    my ($sth, $attrib) = @_;
+    return undef if ($attrib eq 'TYPE'); # Workaround for a bug in DBI 0.93
+    return $sth->FETCH('f_stmt')->{'NAME'} if ($attrib eq 'NAME');
+    if ($attrib eq 'NULLABLE') {
+	my($meta) = $sth->FETCH('f_stmt')->{'NAME'}; # Intentional !
+	if (!$meta) {
+	    return undef;
+	}
+	my($names) = [];
+	my($col);
+	foreach $col (@$meta) {
+	    push(@$names, 1);
+	}
+	return $names;
+    }
+    if ($attrib eq (lc $attrib)) {
+	# Private driver attributes are lower cased
+	return $sth->{$attrib};
+    }
+    # else pass up to DBI to handle
+    return $sth->SUPER::FETCH($attrib);
+}
+
+sub STORE ($$$) {
+    my ($sth, $attrib, $value) = @_;
+    if ($attrib eq (lc $attrib)) {
+	# Private driver attributes are lower cased
+	$sth->{$attrib} = $value;
+	return 1;
+    }
+    return $sth->SUPER::STORE($attrib, $value);
+}
+
+sub DESTROY ($) {
+    my $sth = shift;
+    $sth->finish if $sth->SUPER::FETCH('Active');
+}
+
+sub rows ($) { shift->{'f_stmt'}->{'NUM_OF_ROWS'} };
+
+
+package DBD::File::Statement;
+
+# We may have a working flock() built-in but that doesn't mean that locking
+# will work on NFS (flock() may hang hard)
+my $locking = eval { flock STDOUT, 0; 1 };
+
+# Jochen's old check for flock()
+#
+# my $locking = $^O ne 'MacOS'  &&
+#               ($^O ne 'MSWin32' || !Win32::IsWin95())  &&
+#               $^O ne 'VMS';
+
+@DBD::File::Statement::ISA = qw(DBI::SQL::Nano::Statement);
+
+my $open_table_re =
+    $haveFileSpec ?
+    sprintf('(?:%s|%s|%s)',
+	    quotemeta(File::Spec->curdir()),
+	    quotemeta(File::Spec->updir()),
+	    quotemeta(File::Spec->rootdir()))
+    : '(?:\.?\.)?\/';
+
+sub get_file_name($$$) {
+    my($self,$data,$table)=@_;
+    $table =~ s/^\"//; # handle quoted identifiers
+    $table =~ s/\"$//;
+    my $file = $table;
+    if ( $file !~ /^$open_table_re/o
+     and $file !~ m!^[/\\]!   # root
+     and $file !~ m!^[a-z]\:! # drive letter
+    ) {
+	$file = $haveFileSpec ?
+	    File::Spec->catfile($data->{Database}->{'f_dir'}, $table)
+		: $data->{Database}->{'f_dir'} . "/$table";
+    }
+    return($table,$file);
+}
+
+sub open_table ($$$$$) {
+    my($self, $data, $table, $createMode, $lockMode) = @_;
+    my $file;
+    ($table,$file) = $self->get_file_name($data,$table);
+    require IO::File;
+    my $fh;
+    my $safe_drop = 1 if $self->{ignore_missing_table};
+    if ($createMode) {
+	if (-f $file) {
+	    die "Cannot create table $table: Already exists";
+	}
+	if (!($fh = IO::File->new($file, "a+"))) {
+	    die "Cannot open $file for writing: $!";
+	}
+	if (!$fh->seek(0, 0)) {
+	    die " Error while seeking back: $!";
+	}
+    } else {
+	if (!($fh = IO::File->new($file, ($lockMode ? "r+" : "r")))) {
+	    die " Cannot open $file: $!" unless $safe_drop;
+	}
+    }
+    binmode($fh) if $fh;
+    if ($locking and $fh) {
+	if ($lockMode) {
+	    if (!flock($fh, 2)) {
+		die " Cannot obtain exclusive lock on $file: $!";
+	    }
+	} else {
+	    if (!flock($fh, 1)) {
+		die "Cannot obtain shared lock on $file: $!";
+	    }
+	}
+    }
+    my $columns = {};
+    my $array = [];
+    my $pos = $fh->tell() if $fh;
+    my $tbl = {
+	file => $file,
+	fh => $fh,
+	col_nums => $columns,
+	col_names => $array,
+	first_row_pos => $pos,
+    };
+    my $class = ref($self);
+    $class =~ s/::Statement/::Table/;
+    bless($tbl, $class);
+    $tbl;
+}
+
+
+package DBD::File::Table;
+
+@DBD::File::Table::ISA = qw(DBI::SQL::Nano::Table);
+
+sub drop ($) {
+    my($self) = @_;
+    # We have to close the file before unlinking it: Some OS'es will
+    # refuse the unlink otherwise.
+    $self->{'fh'}->close() if $self->{fh};
+    unlink($self->{'file'});
+    return 1;
+}
+
+sub seek ($$$$) {
+    my($self, $data, $pos, $whence) = @_;
+    if ($whence == 0  &&  $pos == 0) {
+	$pos = $self->{'first_row_pos'};
+    } elsif ($whence != 2  ||  $pos != 0) {
+	die "Illegal seek position: pos = $pos, whence = $whence";
+    }
+    if (!$self->{'fh'}->seek($pos, $whence)) {
+	die "Error while seeking in " . $self->{'file'} . ": $!";
+    }
+}
+
+sub truncate ($$) {
+    my($self, $data) = @_;
+    if (!$self->{'fh'}->truncate($self->{'fh'}->tell())) {
+	die "Error while truncating " . $self->{'file'} . ": $!";
+    }
+    1;
+}
+
+1;
+
+
+__END__
+
+=head1 NAME
+
+DBD::File - Base class for writing DBI drivers
+
+=head1 SYNOPSIS
+
+ This module is a base class for writing other DBDs.
+ It is not intended to function as a DBD itself.
+ If you want to access flatfiles, use DBD::AnyData, or DBD::CSV,
+ (both of which are subclasses of DBD::File).
+
+=head1 DESCRIPTION
+
+The DBD::File module is not a true DBI driver, but an abstract
+base class for deriving concrete DBI drivers from it. The implication is,
+that these drivers work with plain files, for example CSV files or
+INI files. The module is based on the SQL::Statement module, a simple
+SQL engine.
+
+See L<DBI> for details on DBI, L<SQL::Statement> for details on
+SQL::Statement and L<DBD::CSV> or L<DBD::IniFile> for example
+drivers.
+
+
+=head2 Metadata
+
+The following attributes are handled by DBI itself and not by DBD::File,
+thus they all work like expected:
+
+    Active
+    ActiveKids
+    CachedKids
+    CompatMode             (Not used)
+    InactiveDestroy
+    Kids
+    PrintError
+    RaiseError
+    Warn                   (Not used)
+
+The following DBI attributes are handled by DBD::File:
+
+=over 4
+
+=item AutoCommit
+
+Always on
+
+=item ChopBlanks
+
+Works
+
+=item NUM_OF_FIELDS
+
+Valid after C<$sth->execute>
+
+=item NUM_OF_PARAMS
+
+Valid after C<$sth->prepare>
+
+=item NAME
+
+Valid after C<$sth->execute>; undef for Non-Select statements.
+
+=item NULLABLE
+
+Not really working, always returns an array ref of one's, as DBD::CSV
+doesn't verify input data. Valid after C<$sth->execute>; undef for
+Non-Select statements.
+
+=back
+
+These attributes and methods are not supported:
+
+    bind_param_inout
+    CursorName
+    LongReadLen
+    LongTruncOk
+
+Additional to the DBI attributes, you can use the following dbh
+attribute:
+
+=over 4
+
+=item f_dir
+
+This attribute is used for setting the directory where CSV files are
+opened. Usually you set it in the dbh, it defaults to the current
+directory ("."). However, it is overwritable in the statement handles.
+
+=back
+
+
+=head2 Driver private methods
+
+=over 4
+
+=item data_sources
+
+The C<data_sources> method returns a list of subdirectories of the current
+directory in the form "DBI:CSV:f_dir=$dirname".
+
+If you want to read the subdirectories of another directory, use
+
+    my($drh) = DBI->install_driver("CSV");
+    my(@list) = $drh->data_sources('f_dir' => '/usr/local/csv_data' );
+
+=item list_tables
+
+This method returns a list of file names inside $dbh->{'f_dir'}.
+Example:
+
+    my($dbh) = DBI->connect("DBI:CSV:f_dir=/usr/local/csv_data");
+    my(@list) = $dbh->func('list_tables');
+
+Note that the list includes all files contained in the directory, even
+those that have non-valid table names, from the view of SQL.
+
+=back
+
+=head1 KNOWN BUGS
+
+=over 8
+
+=item *
+
+The module is using flock() internally. However, this function is not
+available on all platforms. Using flock() is disabled on MacOS and
+Windows 95: There's no locking at all (perhaps not so important on
+MacOS and Windows 95, as there's a single user anyways).
+
+=back
+
+
+=head1 AUTHOR AND COPYRIGHT
+
+This module is currently maintained by
+
+Jeff Zucker < jzucker @ cpan.org >
+
+The original author is Jochen Wiedmann.
+
+Copyright (C) 2004 by Jeff Zucker
+Copyright (C) 1998 by Jochen Wiedmann
+
+All rights reserved.
+
+You may freely distribute and/or modify this module under the terms of either the GNU General Public License (GPL) or the Artistic License, as specified in
+the Perl README file.
+
+=head1 SEE ALSO
+
+L<DBI>, L<Text::CSV_XS>, L<SQL::Statement>
+
+
+=cut
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBD/NullP.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBD/NullP.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBD/NullP.pm	(revision 14139)
@@ -0,0 +1,125 @@
+{
+    package DBD::NullP;
+
+    require DBI;
+
+    @EXPORT = qw(); # Do NOT @EXPORT anything.
+    $VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/o);
+
+#   $Id$
+#
+#   Copyright (c) 1994, Tim Bunce
+#
+#   You may distribute under the terms of either the GNU General Public
+#   License or the Artistic License, as specified in the Perl README file.
+
+    $drh = undef;	# holds driver handle once initialised
+
+    sub driver{
+	return $drh if $drh;
+	my($class, $attr) = @_;
+	$class .= "::dr";
+	($drh) = DBI::_new_drh($class, {
+	    'Name' => 'NullP',
+	    'Version' => $VERSION,
+	    'Attribution' => 'DBD Example Null Perl stub by Tim Bunce',
+	    }, [ qw'example implementors private data']);
+	$drh;
+    }
+
+    sub CLONE {
+        undef $drh;
+    }
+}
+
+
+{   package DBD::NullP::dr; # ====== DRIVER ======
+    $imp_data_size = 0;
+    use strict;
+    # we use default (dummy) connect method
+
+    sub DESTROY { undef }
+}
+
+
+{   package DBD::NullP::db; # ====== DATABASE ======
+    $imp_data_size = 0;
+    use strict;
+
+    sub prepare {
+	my($dbh, $statement)= @_;
+
+	my($outer, $sth) = DBI::_new_sth($dbh, {
+	    'Statement'     => $statement,
+	    }, [ qw'example implementors private data']);
+
+	$outer;
+    }
+
+    sub FETCH {
+	my ($dbh, $attrib) = @_;
+	# In reality this would interrogate the database engine to
+	# either return dynamic values that cannot be precomputed
+	# or fetch and cache attribute values too expensive to prefetch.
+	return 1 if $attrib eq 'AutoCommit';
+	# else pass up to DBI to handle
+	return $dbh->SUPER::FETCH($attrib);
+	}
+
+    sub STORE {
+	my ($dbh, $attrib, $value) = @_;
+	# would normally validate and only store known attributes
+	# else pass up to DBI to handle
+	if ($attrib eq 'AutoCommit') {
+	    return 1 if $value; # is already set
+	    croak("Can't disable AutoCommit");
+	}
+	return $dbh->SUPER::STORE($attrib, $value);
+    }
+
+    sub disconnect {
+	shift->STORE(Active => 0);
+    }
+
+}
+
+
+{   package DBD::NullP::st; # ====== STATEMENT ======
+    $imp_data_size = 0;
+    use strict;
+
+    sub execute {
+	my($sth, $data) = @_;
+	$sth->{dbd_nullp_data} = $data if $data;
+	$sth->{NAME} = [ "fieldname" ];
+	1;
+    }
+
+    sub fetch {
+	my($sth) = @_;
+	my $data = $sth->{dbd_nullp_data};
+        if ($data) {
+	    $sth->{dbd_nullp_data} = undef;
+	    return [ $data ];
+	}
+	$sth->finish;     # no more data so finish
+	return undef;
+    }
+
+    sub FETCH {
+	my ($sth, $attrib) = @_;
+	# would normally validate and only fetch known attributes
+	# else pass up to DBI to handle
+	return $sth->SUPER::FETCH($attrib);
+    }
+
+    sub STORE {
+	my ($sth, $attrib, $value) = @_;
+	# would normally validate and only store known attributes
+	# else pass up to DBI to handle
+	return $sth->SUPER::STORE($attrib, $value);
+    }
+
+}
+
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBD/ODBC.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBD/ODBC.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBD/ODBC.pm	(revision 14139)
@@ -0,0 +1,940 @@
+# $Id$
+#
+# Copyright (c) 1994,1995,1996,1998  Tim Bunce
+# portions Copyright (c) 1997-2004  Jeff Urlwin
+# portions Copyright (c) 1997  Thomas K. Wenrich
+#
+# You may distribute under the terms of either the GNU General Public
+# License or the Artistic License, as specified in the Perl README file.
+
+require 5.004;
+
+$DBD::ODBC::VERSION = '1.13';
+
+{
+    package DBD::ODBC;
+
+    use DBI ();
+    use DynaLoader ();
+    use Exporter ();
+    
+    @ISA = qw(Exporter DynaLoader);
+
+    # my $Revision = substr(q$Id$, 13,2);
+
+    require_version DBI 1.21;
+
+    bootstrap DBD::ODBC $VERSION;
+
+    $err = 0;		# holds error code   for DBI::err
+    $errstr = "";	# holds error string for DBI::errstr
+    $sqlstate = "00000";
+    $drh = undef;	# holds driver handle once initialised
+
+    sub driver{
+	return $drh if $drh;
+	my($class, $attr) = @_;
+
+	$class .= "::dr";
+
+	# not a 'my' since we use it above to prevent multiple drivers
+
+	$drh = DBI::_new_drh($class, {
+	    'Name' => 'ODBC',
+	    'Version' => $VERSION,
+	    'Err'    => \$DBD::ODBC::err,
+	    'Errstr' => \$DBD::ODBC::errstr,
+	    'State' => \$DBD::ODBC::sqlstate,
+	    'Attribution' => 'ODBC DBD by Jeff Urlwin',
+	    });
+
+	$drh;
+    }
+
+    sub CLONE { undef $drh }
+    1;
+}
+
+
+{   package DBD::ODBC::dr; # ====== DRIVER ======
+    use strict;
+
+    sub connect {
+	my $drh = shift;
+	my($dbname, $user, $auth, $attr)= @_;
+	$user = '' unless defined $user;
+	$auth = '' unless defined $auth;
+
+	# create a 'blank' dbh
+	my $this = DBI::_new_dbh($drh, {
+	    'Name' => $dbname,
+	    'USER' => $user, 
+	    'CURRENT_USER' => $user,
+	    });
+
+	# Call ODBC logon func in ODBC.xs file
+	# and populate internal handle data.
+
+	DBD::ODBC::db::_login($this, $dbname, $user, $auth, $attr) or return undef;
+
+	$this;
+    }
+
+}
+
+
+{   package DBD::ODBC::db; # ====== DATABASE ======
+    use strict;
+
+    sub prepare {
+	my($dbh, $statement, @attribs)= @_;
+
+	# create a 'blank' dbh
+	my $sth = DBI::_new_sth($dbh, {
+	    'Statement' => $statement,
+	    });
+
+	# Call ODBC func in ODBC.xs file.
+	# (This will actually also call SQLPrepare for you.)
+	# and populate internal handle data.
+
+	DBD::ODBC::st::_prepare($sth, $statement, @attribs)
+	    or return undef;
+
+	$sth;
+    }
+
+    sub column_info {
+	my ($dbh, $catalog, $schema, $table, $column) = @_;
+
+	$catalog = "" if (!$catalog);
+	$schema = "" if (!$schema);
+	$table = "" if (!$table);
+	$column = "" if (!$column);
+	# create a "blank" statement handle
+	my $sth = DBI::_new_sth($dbh, { 'Statement' => "SQLColumns" });
+
+	_columns($dbh,$sth, $catalog, $schema, $table, $column)
+	    or return undef;
+
+	$sth;
+    }
+    
+    sub columns {
+	my ($dbh, $catalog, $schema, $table, $column) = @_;
+
+	$catalog = "" if (!$catalog);
+	$schema = "" if (!$schema);
+	$table = "" if (!$table);
+	$column = "" if (!$column);
+	# create a "blank" statement handle
+	my $sth = DBI::_new_sth($dbh, { 'Statement' => "SQLColumns" });
+
+	_columns($dbh,$sth, $catalog, $schema, $table, $column)
+	    or return undef;
+
+	$sth;
+    }
+
+
+    sub table_info {
+ 	my($dbh, $catalog, $schema, $table, $type) = @_;
+
+	if ($#_ == 1) {
+	   my $attrs = $_[1];
+	   $catalog = $attrs->{TABLE_CAT};
+	   $schema = $attrs->{TABLE_SCHEM};
+	   $table = $attrs->{TABLE_NAME};
+	   $type = $attrs->{TABLE_TYPE};
+ 	}
+
+	$catalog = "" if (!$catalog);
+	$schema = "" if (!$schema);
+	$table = "" if (!$table);
+	$type = "" if (!$type);
+
+	# create a "blank" statement handle
+	my $sth = DBI::_new_sth($dbh, { 'Statement' => "SQLTables" });
+
+	DBD::ODBC::st::_tables($dbh,$sth, $catalog, $schema, $table, $type)
+	      or return undef;
+	$sth;
+    }
+
+    sub primary_key_info {
+       my ($dbh, $catalog, $schema, $table ) = @_;
+ 
+       # create a "blank" statement handle
+       my $sth = DBI::_new_sth($dbh, { 'Statement' => "SQLPrimaryKeys" });
+ 
+       $catalog = "" if (!$catalog);
+       $schema = "" if (!$schema);
+       $table = "" if (!$table);
+       DBD::ODBC::st::_primary_keys($dbh,$sth, $catalog, $schema, $table )
+	     or return undef;
+       $sth;
+    }
+
+    sub foreign_key_info {
+       my ($dbh, $pkcatalog, $pkschema, $pktable, $fkcatalog, $fkschema, $fktable ) = @_;
+ 
+       # create a "blank" statement handle
+       my $sth = DBI::_new_sth($dbh, { 'Statement' => "SQLForeignKeys" });
+ 
+       $pkcatalog = "" if (!$pkcatalog);
+       $pkschema = "" if (!$pkschema);
+       $pktable = "" if (!$pktable);
+       $fkcatalog = "" if (!$fkcatalog);
+       $fkschema = "" if (!$fkschema);
+       $fktable = "" if (!$fktable);
+       _GetForeignKeys($dbh, $sth, $pkcatalog, $pkschema, $pktable, $fkcatalog, $fkschema, $fktable) or return undef;
+       $sth;
+    }
+
+    sub ping {
+	my $dbh = shift;
+	my $state = undef;
+
+ 	my ($catalog, $schema, $table, $type);
+
+	$catalog = "";
+	$schema = "";
+	$table = "NOXXTABLE";
+	$type = "";
+
+	# create a "blank" statement handle
+	my $sth = DBI::_new_sth($dbh, { 'Statement' => "SQLTables_PING" });
+
+	DBD::ODBC::st::_tables($dbh,$sth, $catalog, $schema, $table, $type)
+	      or return 0;
+	$sth->finish;
+	return 1;
+
+    }
+
+    # saved, just for posterity.
+    sub oldping  {
+	my $dbh = shift;
+	my $state = undef;
+
+	# should never 'work' but if it does, that's okay!
+	# JLU incorporated patches from Jon Smirl 5/4/99
+	{
+	    local $dbh->{RaiseError} = 0 if $dbh->{RaiseError};
+	    # JLU added local PrintError handling for completeness.
+	    # it shouldn't print, I think.
+	    local $dbh->{PrintError} = 0 if $dbh->{PrintError};
+	    my $sql = "select sysdate from dual1__NOT_FOUND__CANNOT";
+	    my $sth = $dbh->prepare($sql);
+	    # fixed "my" $state = below.  Was causing problem with
+	    # ping!  Also, fetching fields as some drivers (Oracle 8)
+	    # may not actually check the database for activity until
+	    # the query is "described".
+	    # Right now, Oracle8 is the only known version which
+	    # does not actually check the server during prepare.
+	    my $ok = $sth && $sth->execute();
+
+	    $state = $dbh->state;
+	    $DBD::ODBC::err = 0;
+	    $DBD::ODBC::errstr = "";
+	    $DBD::ODBC::sqlstate = "00000";
+	    return 1 if $ok;
+	}
+	return 1 if $state eq 'S0002';	# Base table not found
+ 	return 1 if $state eq '42S02';  # Base table not found.Solid EE v3.51
+	return 1 if $state eq 'S0022';	# Column not found
+	return 1 if $state eq '37000';  # statement could not be prepared (19991011, JLU)
+	# return 1 if $state eq 'S1000';  # General Error? ? 5/30/02, JLU.  This is what Openlink is returning
+	# We assume that any other error means the database
+	# is no longer connected.
+	# Some special cases may need to be added to the code above.
+	return 0;
+    }
+
+    # New support for the next DBI which will have a get_info command.
+    # leaving support for ->func(xxx, GetInfo) (above) for a period of time
+    # to support older applications which used this.
+    sub get_info {
+	my ($dbh, $item) = @_;
+	# handle SQL_DRIVER_HSTMT, SQL_DRIVER_HLIB and
+	# SQL_DRIVER_HDESC specially
+	if ($item == 5 || $item == 135 || $item == 76) {
+	   return undef;
+	}
+	return _GetInfo($dbh, $item);
+    }
+
+    # new override of do method provided by Merijn Broeren
+    # this optimizes "do" to use SQLExecDirect for simple
+    # do statements without parameters.
+    sub do {
+        my($dbh, $statement, $attr, @params) = @_;
+        my $rows = 0;
+        if( -1 == $#params )
+        {
+          # No parameters, use execute immediate
+          $rows = ExecDirect( $dbh, $statement );
+          if( 0 == $rows )
+          {
+            $rows = "0E0";
+          }
+          elsif( $rows < -1 )
+          {
+            undef $rows;
+          }
+        }
+        else
+        {
+          $rows = $dbh->SUPER::do( $statement, $attr, @params );
+        }
+        return $rows
+    }
+
+    #
+    # can also be called as $dbh->func($sql, ExecDirect);
+    # if, for some reason, there are compatibility issues
+    # later with DBI's do.
+    #
+    sub ExecDirect {
+       my ($dbh, $sql) = @_;
+       _ExecDirect($dbh, $sql);
+    }
+
+    # Call the ODBC function SQLGetInfo
+    # Args are:
+    #	$dbh - the database handle
+    #	$item: the requested item.  For example, pass 6 for SQL_DRIVER_NAME
+    # See the ODBC documentation for more information about this call.
+    #
+    sub GetInfo {
+	my ($dbh, $item) = @_;
+	get_info($dbh, $item);
+    }
+
+    # Call the ODBC function SQLStatistics
+    # Args are:
+    # See the ODBC documentation for more information about this call.
+    #
+    sub GetStatistics {
+			my ($dbh, $Catalog, $Schema, $Table, $Unique) = @_;
+			# create a "blank" statement handle
+			my $sth = DBI::_new_sth($dbh, { 'Statement' => "SQLStatistics" });
+			_GetStatistics($dbh, $sth, $Catalog, $Schema, $Table, $Unique) or return undef;
+			$sth;
+    }
+
+    # Call the ODBC function SQLForeignKeys
+    # Args are:
+    # See the ODBC documentation for more information about this call.
+    #
+    sub GetForeignKeys {
+			my ($dbh, $PK_Catalog, $PK_Schema, $PK_Table, $FK_Catalog, $FK_Schema, $FK_Table) = @_;
+			# create a "blank" statement handle
+			my $sth = DBI::_new_sth($dbh, { 'Statement' => "SQLForeignKeys" });
+			_GetForeignKeys($dbh, $sth, $PK_Catalog, $PK_Schema, $PK_Table, $FK_Catalog, $FK_Schema, $FK_Table) or return undef;
+			$sth;
+    }
+
+    # Call the ODBC function SQLPrimaryKeys
+    # Args are:
+    # See the ODBC documentation for more information about this call.
+    #
+    sub GetPrimaryKeys {
+			my ($dbh, $Catalog, $Schema, $Table) = @_;
+			# create a "blank" statement handle
+			my $sth = DBI::_new_sth($dbh, { 'Statement' => "SQLPrimaryKeys" });
+			_GetPrimaryKeys($dbh, $sth, $Catalog, $Schema, $Table) or return undef;
+			$sth;
+    }
+
+    # Call the ODBC function SQLSpecialColumns
+    # Args are:
+    # See the ODBC documentation for more information about this call.
+    #
+    sub GetSpecialColumns {
+	my ($dbh, $Identifier, $Catalog, $Schema, $Table, $Scope, $Nullable) = @_;
+	# create a "blank" statement handle
+	my $sth = DBI::_new_sth($dbh, { 'Statement' => "SQLSpecialColumns" });
+	_GetSpecialColumns($dbh, $sth, $Identifier, $Catalog, $Schema, $Table, $Scope, $Nullable) or return undef;
+	$sth;
+    }
+	
+    sub GetTypeInfo {
+	my ($dbh, $sqltype) = @_;
+	# create a "blank" statement handle
+	my $sth = DBI::_new_sth($dbh, { 'Statement' => "SQLGetTypeInfo" });
+	# print "SQL Type is $sqltype\n";
+	_GetTypeInfo($dbh, $sth, $sqltype) or return undef;
+	$sth;
+    }
+
+    sub type_info_all {
+	my ($dbh, $sqltype) = @_;
+	$sqltype = DBI::SQL_ALL_TYPES unless defined $sqltype;
+	my $sth = DBI::_new_sth($dbh, { 'Statement' => "SQLGetTypeInfo" });
+	_GetTypeInfo($dbh, $sth, $sqltype) or return undef;
+	my $info = $sth->fetchall_arrayref;
+	unshift @$info, {
+	    map { ($sth->{NAME}->[$_] => $_) } 0..$sth->{NUM_OF_FIELDS}-1
+	};
+	return $info;
+    }
+
+}
+
+
+{   package DBD::ODBC::st; # ====== STATEMENT ======
+    use strict;
+
+    sub ColAttributes {		# maps to SQLColAttributes
+	my ($sth, $colno, $desctype) = @_;
+	# print "before ColAttributes $colno\n";
+	my $tmp = _ColAttributes($sth, $colno, $desctype);
+	# print "After ColAttributes\n";
+	$tmp;
+    }
+
+    sub cancel {
+	my $sth = shift;
+	my $tmp = _Cancel($sth);
+	$tmp;
+    }
+}
+
+1;
+__END__
+
+=head1 NAME
+
+DBD::ODBC - ODBC Driver for DBI
+
+=head1 SYNOPSIS
+
+  use DBI;
+
+  $dbh = DBI->connect('dbi:ODBC:DSN', 'user', 'password');
+
+See L<DBI> for more information.
+
+=head1 DESCRIPTION
+
+=head2 Notes:
+
+=over 4
+
+=item B<Change log/recent updates now in DBD::ODBC::Changes.pm>
+
+ Please note that the change log has been moved to DBD::ODBC::Changes.pm
+ To easily access this documentation, use perldoc DBD::ODBC::Changes
+
+ Also, while this document documents features, etc, I'm really trying to keep
+ the FAQ type questions answered in the DBI FAQ itself... see
+ http://dbi.perl.org for more information.
+   
+=item B<An Important note about the tests!>
+
+ Please note that some tests may fail or report they are
+ unsupported on this platform.  Notably Oracle's ODBC driver
+ will fail the "advanced" binding tests in t/08bind2.t.
+ These tests run perfectly under SQL Server 2000. This is
+ normal and expected.  Until Oracle fixes their drivers to
+ do the right thing from an ODBC perspective, it's going to
+ be tough to fix the issue.  The workaround for Oracle is to
+ bind date types with SQL_TIMESTAMP.
+   
+ Also note that some tests may be skipped, such as
+ t/09multi.t, if your driver doesn't seem to support
+ returning multiple result sets.  This is normal.
+
+=item B<Version Control>
+
+ I have recently placed all of the DBD::ODBC source code
+ under version control at svn.perl.org.  If you would like
+ to use the "bleeding" edge version, you can get the latest
+ from svn.perl.org via Subversion version control.  Note that I
+ don't guarantee that this version is any different than what
+ you get from the tarball from CPAN, but hey, it might be :)
+
+ You may read about Subversion from:
+   http://subversion.tigris.org
+
+ You can get a subversion client from there and check dbd-odbc out via:
+
+   svn checkout http://svn.perl.org/modules/dbd-odbc/trunk <your directory name here>
+
+ Which will, after a short bit a of work, grab all the files into your
+ local directory tree that you name.  For now, you can authenticate via the guest
+ user and guest password.  That will change to be unauthenticated in the future for
+ simple read-only checkout.
+				    
+=item B<Contributing>
+
+ I am usually very open to contributions, but I have tended
+ to get behind.  That's one strong reason why I've put everything
+ in a shared version control environment.
+
+ Please use Subversion (see above) to appropriately get the latest
+ versions.
+
+ Please, before submitting a patch:
+    svn update
+    <test your patch>
+    svn diff > describe_my_diffs.patch
+
+ and send the resuting file to me...
+
+ It's probably best to send to dbi-users@perl.org, as I monitor that group.
+ 
+=item B<Private DBD::ODBC Attributes>
+
+=item odbc_more_results (applies to statement handle only!)
+
+Use this attribute to determine if there are more result sets
+available.  SQL Server supports this feature.  Use this as follows:
+
+do {
+   my @row;
+   while (@row = $sth->fetchrow_array()) {
+      # do stuff here
+   }
+} while ($sth->{odbc_more_results});
+
+Note that with multiple result sets and output parameters (i.e. using
+bind_param_inout, don't expect output parameters to be bound until ALL
+result sets have been retrieved.
+
+=item odbc_ignore_named_placeholders
+
+Use this if you have special needs (such as Oracle triggers, etc) where
+:new or :name mean something special and are not just place holder names
+You I<must> then use ? for binding parameters.  Example:
+ $dbh->{odbc_ignore_named_placeholders} = 1;
+ $dbh->do("create trigger foo as if :new.x <> :old.x then ... etc");
+
+Without this, DBD::ODBC will think :new and :old are placeholders for binding
+and get confused.
+ 
+=item odbc_default_bind_type
+
+This value defaults to 0.  Older versions of DBD::ODBC assumed that the binding
+type was 12 (SQL_VARCHAR).  Newer versions default to 0, which means that
+DBD::ODBC will attempt to query the driver via SQLDescribeParam to determine
+the correct type.  If the driver doesn't support SQLDescribeParam, then DBD::ODBC
+falls back to using SQL_VARCHAR as the default, unless overridden by bind_param()
+
+=item odbc_force_rebind
+
+This is to handle special cases, especially when using multiple result sets.
+Set this before execute to "force" DBD::ODBC to re-obtain the result set's
+number of columns and column types for each execute.  Especially useful for
+calling stored procedures which may return different result sets each
+execute.  The only performance penalty is during execute(), but I didn't
+want to incur that penalty for all circumstances.  It is probably fairly
+rare that this occurs.  This attribute will be automatically set when
+multiple result sets are triggered.  Most people shouldn't have to worry
+about this.
+
+=item odbc_async_exec
+
+Allow asynchronous execution of queries.  Right now, this causes a spin-loop
+(with a small "sleep") until the sql is complete.  This is useful, however,
+if you want the error handling and asynchronous messages (see the err_handler)
+below.  See t/20SQLServer.t for an example of this.
+
+=item odbc_exec_direct
+
+Force DBD::ODBC to use SQLExecDirect instead of SQLPrepare() then SQLExecute.
+There are drivers that only support SQLExecDirect and the DBD::ODBC
+do() override doesn't allow returning result sets.  Therefore, the
+way to do this now is to set the attributed odbc_exec_direct.
+There are currently two ways to get this:
+	$dbh->prepare($sql, { odbc_exec_direct => 1}); 
+ and
+	$dbh->{odbc_exec_direct} = 1;
+ When $dbh->prepare() is called with the attribute "ExecDirect" set to a non-zero value 
+ dbd_st_prepare do NOT call SQLPrepare, but set the sth flag odbc_exec_direct to 1.
+ 
+=item odbc_err_handler
+
+Allow errors to be handled by the application.  A call-back function supplied
+by the application to handle or ignore messages.  If the error handler returns
+0, the error is ignored, otherwise the error is passed through the normal
+DBI error handling structure(s).
+
+This can also be used for procedures under MS SQL Server (Sybase too, probably)
+to obtain messages from system procedures such as DBCC.  Check t/20SQLServer.t
+and mytest/testerrhandler.pl
+
+The callback function takes three parameters: the SQLState, the ErrorMessage and
+the native server error.
+ 
+=item odbc_SQL_ROWSET_SIZE
+
+Here is the information from the original patch, however, I've learned
+since from other sources that this could/has caused SQL Server to "lock up".
+Please use at your own risk!
+   
+SQL_ROWSET_SIZE attribute patch from Andrew Brown 
+> There are only 2 additional lines allowing for the setting of
+> SQL_ROWSET_SIZE as db handle option.
+>
+> The purpose to my madness is simple. SqlServer (7 anyway) by default
+> supports only one select statement at once (using std ODBC cursors).
+> According to the SqlServer documentation you can alter the default setting
+> of
+> three values to force the use of server cursors - in which case multiple
+> selects are possible.
+>
+> The code change allows for:
+> $dbh->{SQL_ROWSET_SIZE} = 2;    # Any value > 1
+>
+> For this very purpose.
+>
+> The setting of SQL_ROWSET_SIZE only affects the extended fetch command as
+> far as I can work out and thus setting this option shouldn't affect
+> DBD::ODBC operations directly in any way.
+>
+> Andrew
+>
+
+=item SQL_DRIVER_ODBC_VER
+
+This, while available via get_info() is captured here.  I may get rid of this
+as I only used it for debugging purposes.  
+ 
+=item odbc_cursortype (applies to connect only!)
+
+This allows multiple concurrent statements on SQL*Server.  In your connect, add
+{ odbc_cursortype => 2 }.  If you are using DBI > 1.41, you should also be able
+to use { odbc_cursortype => DBI::SQL_CURSOR_DYNAMIC } instead.  For example:
+
+ my $dbh = DBI->connect("dbi:ODBC:$DSN", $user, $pass, { RaiseError => 1, odbc_cursortype => 2});
+ my $sth = $dbh->prepare("one statement");
+ my $sth2 = $dbh->prepare("two statement");
+ $sth->execute;
+ my @row;
+ while (@row = $sth->fetchrow_array) {
+    $sth2->execute($row[0]);
+ }
+
+See t/20SqlServer.t for an example.
+
+
+=item odbc_query_timeout 
+
+This allows the end user to set a timeout for queries on the ODBC side.  After your connect, add
+{ odbc_query_timeout => 30 } or set on the dbh before executing the statement.  The default is 0, no timeout.
+Note that some drivers may not support this attribute.
+
+See t/20SqlServer.t for an example.
+
+   
+=item odbc_version (applies to connect only!)
+
+This was added prior to the move to ODBC 3.x to allow the caller to "force" ODBC 3.0
+compatibility.  It's probably not as useful now, but it allowed get_info and get_type_info
+to return correct/updated information that ODBC 2.x didn't permit/provide.
+Since DBD::ODBC is now 3.x, this can be used to force 2.x behavior via something like:
+  my $dbh = DBI->connect("dbi:ODBC:$DSN", $user, $pass, { odbc_version => 2});
+       
+   
+=item B<Private DBD::ODBC Functions>
+
+=item GetInfo (superceded by get_info(), the DBI standard)
+
+This function maps to the ODBC SQLGetInfo call.  This is a Level 1 ODBC
+function.  An example of this is:
+
+  $value = $dbh->func(6, GetInfo);
+
+This function returns a scalar value, which can be a numeric or string value.  
+This depends upon the argument passed to GetInfo.
+
+
+=item SQLGetTypeInfo (superceded by get_type_info(), the DBI standard)
+
+This function maps to the ODBC SQLGetTypeInfo call.  This is a Level 1
+ODBC function.  An example of this is:
+
+  use DBI qw(:sql_types);
+
+  $sth = $dbh->func(SQL_ALL_TYPES, GetInfo);
+  while (@row = $sth->fetch_row) {
+    ...
+  }
+
+This function returns a DBI statement handle, which represents a result
+set containing type names which are compatible with the requested
+type.  SQL_ALL_TYPES can be used for obtaining all the types the ODBC
+driver supports.  NOTE: It is VERY important that the use DBI includes
+the qw(:sql_types) so that values like SQL_VARCHAR are correctly
+interpreted.  This "imports" the sql type names into the program's name
+space.  A very common mistake is to forget the qw(:sql_types) and
+obtain strange results.
+
+=item GetFunctions (now supports ODBC V3)
+
+This function maps to the ODBC API SQLGetFunctions.  This is a Level 1
+API call which returns supported driver funtions.  Depending upon how
+this is called, it will either return a 100 element array of true/false
+values or a single true false value.  If it's called with
+SQL_API_ALL_FUNCTIONS (0), it will return the 100 element array.
+Otherwise, pass the number referring to the function.  (See your ODBC
+docs for help with this).
+
+=item SQLColumns 
+
+Support for this function has been added in version 0.17.  It looks to be
+fixed in version 0.20.
+
+Use the DBI statement handle attributes NAME, NULLABLE, TYPE, PRECISION and
+SCALE, unless you have a specific reason.
+
+=item Connect without DSN
+The ability to connect without a full DSN is introduced in version 0.21.
+
+Example (using MS Access):
+	my $DSN = 'driver=Microsoft Access Driver (*.mdb);dbq=\\\\cheese\\g$\\perltest.mdb';
+	my $dbh = DBI->connect("dbi:ODBC:$DSN", '','') 
+		or die "$DBI::errstr\n";
+
+=item SQLStatistics
+
+=item SQLForeignKeys
+
+See DBI's get_foreign_keys.
+   
+=item SQLPrimaryKeys
+
+See DBI's get_primary_keys
+   
+=item SQLDataSources
+
+Handled, currently (as of 0.21), also see DBI's data_sources()
+
+=item SQLSpecialColumns
+
+Handled as of version 0.28
+ 
+=item Others/todo?
+
+Level 1
+
+    SQLTables (use tables()) call
+
+Level 2
+
+    SQLColumnPrivileges
+    SQLProcedureColumns
+    SQLProcedures
+    SQLTablePrivileges
+    SQLDrivers
+    SQLNativeSql
+
+=back
+
+=head2 Using DBD::ODBC with web servers under Win32. 
+
+=over 4
+
+=item General Commentary re web database access
+
+This should be a DBI faq, actually, but this has somewhat of an
+Win32/ODBC twist to it.
+
+Typically, the Web server is installed as an NT service or a Windows
+95/98 service.  This typically means that the web server itself does
+not have the same environment and permissions the web developer does.
+This situation, of course, can and does apply to Unix web servers.
+Under Win32, however, the problems are usually slightly different.
+
+=item Defining your DSN -- which type should I use?
+
+Under Win32 take care to define your DSN as a system DSN, not as a user
+DSN.  The system DSN is a "global" one, while the user is local to a
+user.  Typically, as stated above, the web server is "logged in" as a
+different user than the web developer.  This helps cause the situation
+where someone asks why a script succeeds from the command line, but
+fails when called from the web server.
+
+=item Defining your DSN -- careful selection of the file itself is important!
+
+For file based drivers, rather than client server drivers, the file
+path is VERY important.  There are a few things to keep in mind.  This
+applies to, for example, MS Access databases.
+
+1) If the file is on an NTFS partition, check to make sure that the Web
+B<service> user has permissions to access that file.
+
+2) If the file is on a remote computer, check to make sure the Web
+B<service> user has permissions to access the file.
+
+3) If the file is on a remote computer, try using a UNC path the file,
+rather than a X:\ notation.  This can be VERY important as services
+don't quite get the same access permissions to the mapped drive letters
+B<and>, more importantly, the drive letters themselves are GLOBAL to
+the machine.  That means that if the service tries to access Z:, the Z:
+it gets can depend upon the user who is logged into the machine at the
+time.  (I've tested this while I was developing a service -- it's ugly
+and worth avoiding at all costs).
+
+Unfortunately, the Access ODBC driver that I have does not allow one to
+specify the UNC path, only the X:\ notation.  There is at least one way
+around that.  The simplest is probably to use Regedit and go to
+(assuming it's a system DSN, of course)
+HKEY_LOCAL_USERS\SOFTWARE\ODBC\"YOUR DSN" You will see a few settings
+which are typically driver specific.  The important value to change for
+the Access driver, for example, is the DBQ value.  That's actually the
+file name of the Access database.
+
+=item Connect without DSN
+The ability to connect without a full DSN is introduced in version 0.21.
+
+Example (using MS Access):
+	my $DSN = 'driver=Microsoft Access Driver
+(*.mdb);dbq=\\\\cheese\\g$\\perltest.mdb';
+	my $dbh = DBI->connect("dbi:ODBC:$DSN", '','') 
+		or die "$DBI::errstr\n";
+
+The above sample uses Microsoft's UNC naming convention to point to the MSAccess
+file (\\\\cheese\\g$\\perltest.mdb).  The dbq parameter tells the access driver
+which file to use for the database.
+   
+Example (using MSSQL Server):
+      my $DSN = 'driver={SQL Server};Server=server_name;
+      database=database_name;uid=user;pwd=password;';
+      my $dbh  = DBI->connect("dbi:ODBC:$DSN") or die "$DBI::errstr\n";
+
+=back
+
+=head2 Random Links
+
+These are in need of sorting and annotating. Some are relevant only
+to ODBC developers (but I don't want to loose them).
+
+	http://www.ids.net/~bjepson/freeODBC/index.html
+
+	http://dataramp.com/
+
+	http://www.syware.com
+
+	http://www.microsoft.com/odbc
+
+   For Linux/Unix folks, compatible ODBC driver managers can be found at:
+   
+        http://www.easysoft.com		unixODBC driver manager source
+				        *and* ODBC-ODBC bridge for accessing Win32 ODBC sources from Linux
+
+        http://www.iodbc.org		iODBC driver manager source
+
+   For Linux/Unix folks, you can checkout the following for another ODBC-ODBC bridge and support for iODBC.
+
+	http://www.openlink.co.uk 
+		or
+	http://www.openlinksw.com 
+
+   And another:
+        OpenRDA
+   
+        http://www.atinet.com/support/openrda_samples.asp
+ 
+
+
+=head2 Frequently Asked Questions
+
+Answers to common DBI and DBD::ODBC questions:
+
+=over 4
+ 
+=item How do I read more than N characters from a Memo | BLOB | LONG field?
+
+See LongReadLen in the DBI docs.  
+
+Example:
+	$dbh->{LongReadLen} = 20000;
+	$sth = $dbh->prepare("select long_col from big_table");
+	$sth->execute;
+	etc
+
+=item What is DBD::ODBC?  Why can't I connect?  Do I need an ODBC driver?  What is the ODBC driver manager?
+
+These, general questions lead to needing definitions.
+
+1) ODBC Driver - the driver that the ODBC manager uses to connect
+and interact with the RDBMS.  You DEFINITELY need this to 
+connect to any database.  For Win32, they are plentiful and installed
+with many applications.  For Linux/Unix, some hunting is required, but
+you may find something useful at:
+
+	http://www.openlinksw.com
+        http://www.easysoft.com
+	http://www.intersolv.com
+	http://www.atinet.com/support/openrda_samples.asp
+	      
+
+2) ODBC Driver Manager - the piece of software which interacts with the drivers
+for the application.  It "hides" some of the differences between the
+drivers (i.e. if a function call is not supported by a driver, it 'hides'
+that and informs the application that the call is not supported.
+DBD::ODBC needs this to talk to drivers.  Under Win32, it is built in
+to the OS.  Under Unix/Linux, in most cases, you will want to use freeODBC,
+unixODBC or iODBC.  iODBC was bundled with DBD::ODBC, but you will need to find one
+which suits your needs.  Please see www.openlinksw.com, www.easysoft.com or www.iodbc.org
+
+3) DBD::ODBC.  DBD::ODBC uses the driver manager to talk to the ODBC driver(s) on
+your system.  You need both a driver manager and driver installed and tested
+before working with DBD::ODBC.  You need to have a DSN (see below) configured
+*and* TESTED before being able to test DBD::ODBC.
+
+4) DSN -- Data Source Name.  It's a way of referring to a particular database by any
+name you wish.  The name itself can be configured to hide the gory details of
+which type of driver you need and the connection information you need to provide.
+For example, for some databases, you need to provide a TCP address and port.
+You can configure the DSN to have use information when you refer to the DSN.
+
+=item Where do I get an ODBC driver manager for Unix/Linux?
+
+DBD::ODBC comes with one (iODBC).  In the DBD::ODBC source release is a directory named iodbcsrc.  
+There are others.  UnixODBC, FreeODBC and some of the drivers will come with one of these managers.
+For example Openlink's drivers (see below) come with the iODBC driver manager.  Easysoft
+supplies both ODBC-ODBC bridge software and unixODBC.
+
+=item How do I access a MS SQL Server database from Linux?
+
+Try using drivers from http://www.openlinksw.com or www.easysoft.com
+The multi-tier drivers have been tested with Linux and Redhat 5.1.
+
+=item How do I access an MS-Access database from Linux?
+
+I believe you can use the multi-tier drivers from http://www.openlinksw.com, however, I have
+not tested this.  Also, I believe there is a commercial solution from http://www.easysoft.com.  I
+have not tested this.
+
+If someone does have more information, please, please send it to me and I will put it in this
+FAQ.
+
+=item Almost all of my tests for DBD::ODBC fail.  They complain about not being able to connect
+or the DSN is not found.  
+
+Please, please test your configuration of ODBC and driver before trying to test DBD::ODBC.  Most
+of the time, this stems from the fact that the DSN (or ODBC) is not configured properly.  iODBC
+comes with a odbctest program.  Please use it to verify connectivity.
+
+=item For Unix -> Windows DB see Tom Lowery's write-up.
+
+http://tlowery.hypermart.net/perl_dbi_dbd_faq.html#HowDoIAccessMSWindowsDB
+
+=item I'm attempting to bind a Long Var char (or other specific type) and the binding is not working.
+The code I'm using is below:
+
+	$sth->bind_param(1, $str, $DBI::SQL_LONGVARCHAR);
+                                 ^^^
+The problem is that DBI::SQL_LONGVARCHAR is not the same as $DBI::SQL_LONGVARCHAR and that
+$DBI::SQL_LONGVARCHAR is an error!
+
+It should be:
+
+	$sth->bind_param(1, $str, DBI::SQL_LONGVARCHAR);
+
+
+=cut
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBD/ODBC/Changes.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBD/ODBC/Changes.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBD/ODBC/Changes.pm	(revision 14139)
@@ -0,0 +1,800 @@
+=head1 NAME
+
+DBD::ODBC::Changes - Log of significant changes to the DBD::ODBC
+
+=cut
+
+=head1 Todo
+
+ I'll be building this list shortly.
+ ++ done ++ Make ODBC version 3.0 default!
+ ++ done ++ Document more of the DBD::ODBC private attributes/functions.
+ Add array parameter binding (per new DBI Spec)
+ Add row caching/multiple row fetches to speed selects
+ Better/more tests on multiple statement handles which ensure the correct number of rows
+ Better/more tests on all queries which ensure the correct number of rows and data
+ Better tests on SQLExecDirect/do
+ ++ done ++ Change default behaviour to use SQLDescribeParam instead of SQL_VARCHAR.
+
+ Keep checking Oracle's ODBC drivers for Windows to fix the Date binding problem
+
+=head1 CHANGES
+
+=head2 Changes in DBD::ODBC 1.13 November 8, 2004
+
+Fix inconsistency/bug with odbc_exec_direct vs. odbc_execdirect settings.  Now made consistent with
+odbc_exec_direct.  For now, will still look for odbc_execdirect in prepare, but not as DBH attribute
+as a backup (which is what it was doing), but that support will be dropped at some time in the future. 
+Please use odbc_exec_direct from now on...
+
+Fix handling of print statements for SQL Server thanks to Martin Evans!  Thanks for all your work on this! 
+Due to bug in SQL Server, you must use odbc_exec_direct.  See t/20SqlServer.t for example.  You will need
+to call $sth->{odbc_more_results} to clear out any trailing messages.
+
+Change tests to use Test::More.  Whew, that's much nicer!
+
+Fix Oracle integral/numeric output params so that warning not printed about value not being numeric (even though it is!)
+
+=head2 Changes in DBD::ODBC 1.12 October 26, 2004
+
+Fix bug with odbc_execdirect attributed thanks to Martin Evans
+Fix bug(s) with odbc_query_timeout and tested with SQL*Server.  
+Oracle tests failed with setting timeout.  Probably not handled by Oracle's ODBC driver
+
+=head2 Changes in DBD::ODBC 1.11 October 11, 2004
+
+Added odbc_timeout, but untested
+
+=head2 Changes in DBD::ODBC 1.10 September 8, 2004
+
+Fixed bug in Makefile.PL.
+Added pod.t test, taken from DBI.
+Fixed various small POD issues, discovered during the pod test.
+Fixed bug in bind_param_inout
+
+=head2 Changes in DBD::ODBC 1.09 March 10, 2004
+
+Duh.  I forgot to add new dbivport.h to MANIFEST and SVN before submitting.  Fixed.
+
+=head2 Changes in DBD::ODBC 1.08 March 6, 2004
+
+Added check in Makefile.PL to detect if the environment variable LANG is 
+Set.  If so, prints a warning about potential makefile generation issues.
+Change to use dbivport.h per new DBI spec.
+Add ability to set the cursor type during the connect.  This may allow some servers
+which do not support multiple concurrent statements to permit them -- 
+tested with SQL Server.  Thanks to Martin Busik!
+See odbc_cursortype information in the ODBC POD.
+
+
+=head2 Changes in DBD::ODBC 1.07 February 19, 2004
+
+Added to Subversion version control hosted by perl.org.  Thanks Robert!  See ODBC.pm POD for more information.
+Added contributing section to ODBC.pm POD -- see more details there!
+Added parameter to odbc_errhandler for the NativeError -- thanks to Martin Busik.
+Fix for Makefile.PL not having tab in front of $(NOOP) (Finally).
+Fix for SQLForeignKeys thanks to Kevin Shepherd.
+
+=head2 Changes in DBD::ODBC 1.06 June 19, 2003
+
+Fixed test in t/02simple.t to skip if the DSN defined by the user has DSN= in it.
+Added tests for wrong DSN, ensuring the DBI::errstr is appropriately set.
+Fixed small issue in Makefile.PL for Unix systems thanks to H.Merijn Brand.
+Update to NOT copy user id and password to connect string if UID or PWD parameter in connect string.
+Updated Makefile.PL for dmake, per patch by Steffen Goldner.  Thanks Steffen!
+
+=head2 Changes in DBD::ODBC 1.05 March 14, 2003
+
+Cleaned up Makefile.PL and added Informix support thanks to Jonathan Leffler (see README.informix)
+Added nicer error message when attempting to do anything while the database is disconnected. 
+Fixed fetchrow_hashref('NAME_uc | NAME_lc') with odbc_more_results.
+Added exporter to allow perl -MDBD::ODBC=9999 command line to determine version
+Fixed for building with DBI 1.33 and greater
+Removed all C++ style comments
+Ensured files are in Unix format, with the exception of the README type information and Makefile.PL
+
+=head2 Changes in DBD::ODBC 1.04 January 24, 2003
+
+It seems that case insensitive string comparison with a limit causes problems for
+multiple platforms.  strncmpi, strncasecmp, _strcmpin are all functions hit and
+it seems to be a hit-or-miss.  Hence, I rewrote it to upper case the string
+then do strncmp, which should be safe...sheesh.  A simple thing turned into
+a headache...
+
+=head2 Changes in DBD::ODBC 1.03 January 17, 2003
+
+Add automatic detection of DRIVER= or DSN= to add user id and password to
+connect string.
+
+
+=head2 Changes in DBD::ODBC 1.02 January 6, 2003
+
+Fix to call finish() automatically if execute is re-called in a loop 
+(and test in t/02simple.t to ensure it's fixed)
+ 
+Augmented error message when longs are truncated to help users determine where
+to look for help.
+
+Fixes for build under Win32 with Perl5.8.  
+
+
+=head2 Changes in DBD::ODBC 1.01 December 9, 2002
+
+Forgot to fix require DBI 1.201 in ODBC.pm to work for perl 5.8.  Fixed
+
+=head2 Changes in DBD::ODBC 1.00 December 8, 2002
+
+(Please see all changes since version 0.43)
+
+Updated Makefile.PL to handle SQL_Wxxx types correctly with unixODBC and linking 
+directly with EasySoft OOB.  Note that I could not find where iODBC defines SQL_WLONG_VARCHAR,
+so I'm not sure it's fixed on all other platforms.  Should not have been a problem under
+Win32...
+
+Found that the fix in _18 was only enabled if debug enabled and it broke something else.
+removed the fix.
+
+Updated Makefile.PL to use DBI version 1.21 instead of 1.201 to facilitate builds under
+latest development versions of Perl.
+
+Updated code to use the *greater* of the column display size and the column length for
+allocating column buffers.  This *should* workaround a problem with DBD::ODBC and the 
+Universe database.
+
+Added code thanks to Michael Riber to handle SQLExecDirect instead of SQLPrepare.  There are 
+two ways to get this:
+
+	$dbh->prepare($sql, { odbc_execdirect => 1}); 
+ and
+	$dbh->{odbc_execdirect} = 1;
+
+When $dbh->prepare() is called with the attribute "ExecDirect" set to a non-zero value 
+dbd_st_prepare do NOT call SQLPrepare, but set the sth flag odbc_exec_direct to 1.
+ 
+Fixed numeric value binding when binding non-integral values.  Now lets the driver 
+or the database handle the conversion.
+
+Fixed makefile.pl generation of makefile to force the ODBC directory first in the 
+include list to help those installing ODBC driver managers on systems which 
+already have ODBC drivers in their standard include path.
+
+=head2 Changes in DBD::ODBC 0.45_18 September 26, 2002
+
+Updated MANIFEST to include more of the mytest/* files (examples, tests)
+Fixed problem when attempting to get NUM_OF_FIELDS after execute returns no rows/columns.
+
+=head2 Changes in DBD::ODBC 0.45_17 August 26, 2002
+
+More fixes for multiple result sets.  Needed to clear the DBIc_FIELDS_AV
+when re-executing the multiple-result set stored procedure/query.
+
+=head2 Changes in DBD::ODBC 0.45_16 August 26, 2002
+
+Updated to fix output parameters with multiple result sets.  The output
+parameters are not set until the last result set has been retrieved.
+
+=head2 Changes in DBD::ODBC 0.45_15 August 20, 2002
+
+Updated for new DBIc_STATE macros (all debug, as it turned out) to be thread safer in the long run
+
+Updated for the new DBIc_LOGFP macros
+
+Added CLONE method
+
+Fix for SQL Server where multiple result sets being returned from a stored proc,
+where one of the result sets was empty (insert/update).
+ 
+Added new attribute odbc_force_rebind, which forces DBD::ODBC to
+check recheck for new result sets every execute.  This is only
+really necessary if you have a stored procedure which returns different
+result sets with each execute, given the same "prepare".  Many times
+this will be automatically set by DBD::ODBC, however, if there is only
+one result set in the stored proc, but it can differ with each call,
+then DBD::ODBC will not know to set it. 
+
+Updated the DBD::ODBC POD documentation to document DBD::ODBC 
+private attributes and usage.
+ 
+=head2 Changes in DBD::ODBC 0.45_14 August 13, 2002
+
+Added support to handle (better) DBI begin_work().
+
+Fix for binding undef parameters on SQL Server.
+
+Fix bug when connecting twice in the same script.  Trying to set the environment ODBC version
+twice against the same henv caused an error.
+
+=head2 Changes in DBD::ODBC 0.45_13 August 9, 2002
+
+Workaround problem with iODBC where SQLAllocHandleStd is not present in iODBC.
+Made Changes file accessible via perldoc DBD::ODBC::Changes.  In the near future
+the change log will be removed from here and put in changes to tidy up a bit.
+
+=head2 Changes in DBD::ODBC 0.45_12 August 9, 2002
+
+Fixed global destruction access violation (which was seemingly random).
+
+=head2 Changes in DBD::ODBC 0.45_11 August 8, 2002
+
+Updated manifest to include more samples.
+Working on checking for leaks on Linux, where I might get more information about
+the process memory.
+
+Working on fixing problems with MS SQL Server binding parameters.  It seems that SQLServer
+gets "confused" if you bind a NULL first.  In "older" (SQLServer 2000 initial release) versions
+of the driver, it would truncate char fields.  In "newer" versions of the SQL Server
+driver, it seems to only truncate dates (actually, round them to the nearest minute).  If you have
+problems in the SQL Server tests, please upgrade your driver to the latest version on
+Microsoft's website (MDAC 2.7 or above) http://www.microsoft.com/data
+
+=head2 Changes in DBD::ODBC 0.45_10 July 30, 2002
+
+Added database specific tests to ensure things are working.  Some of the tests may
+not work for all people or may not be desirable.  I have tried to keep them as
+safe as possible, but if they don't work, please let me know.
+
+Added support for the internal function GetFunctions to handle ODBC 3's
+SQL_API_ODBC3_ALL_FUNCTIONS.  Would have caused a memory overwrite on the
+stack if it was called. 
+ 
+
+=head2 Changes in DBD::ODBC 0.45_9 July 30, 2002
+
+Fixed bug in procedure handling for SQLServer.  Was not re-describing the result sets
+if the SQLMoreResults in the execute needs to be called.
+  
+=head2 Changes in DBD::ODBC 0.45_8 July 25, 2002
+
+Fixed bug in tracing code when binding an undef parameter which did not
+happen to have a valid buffer with tracing level >= 2
+ 
+Fixed bug when binding undef after a valid data bind on a timestamp.  The
+Scale value was being calculated based upon the string that had been bound
+prior to the bind of the undef and if that had a sub-second value, then
+the scale would be set to the wrong value...I.e. 
+
+ bind_param(1, '2000-05-17 00:01:00.250', SQL_TYPE_TIMESTAMP) then
+ execute
+ bind_param(1, undef, SQL_TYPE_TIMESTAMP) then
+
+Fixed SQL Server issue when binding a null and the length was set to 0 instead of 1
+
+=head2 Changes in DBD::ODBC 0.45_7 July 25, 2002
+
+Adding support for array binding, but not finished.
+
+Fixed bug where SqlServer Stored procedures which perform INSERT would not correctly
+return a result set.  Thanks to Joe Tebelskis for finding it and Martin Evans for
+supplying a fix.
+
+Fixed bug where binding the empty string would cuase a problem.  Fixed and added
+test in t/07bind.t.
+ 
+=head2 Changes in DBD::ODBC 0.45_6 July 24, 2002
+
+Added support for new DBI ParamValues feature.
+ 
+=head2 Changes in DBD::ODBC 0.45_5 July 23, 2002
+
+Added odbc_err_handler and odbc_async_exec thanks to patches by David L. Good.
+See example in mytest/testerrhandler.pl
+
+Here's the notes about it:
+
+ I've implemented two separate functions.  The first is an "error
+ handler" similar to that in DBD::Sybase.  The error handler can be used
+ to intercept error and status messages from the server.  It is the only
+ way (at least currently) that you can retrieve non-error status messages
+ when execution is successful.
+
+ To use the error handler, set the "odbc_err_handler" attribute on
+ your database handle to a reference to a subroutine that will act
+ as the error handler.  This subroutine will be passed two args, the
+ SQLSTATE and the error message.  If the subroutine returns 0, the
+ error message will be otherwise ignored.  If it returns non-zero,
+ the error message will be processed normally.
+
+ The second function implemented is asynchronous execution.  It's only
+ useful for retrieving server messages with an error handler during an
+ execute() that takes a long time (such as a DBCC on a large database) ODBC
+ doesn't have the concept of a callback routine like Sybase's DBlib/CTlib
+ does, so asynchronous execution is needed to be able to get the server
+ messages before the SQL statement is done processing.
+
+ To use asynchronous execution, set the "odbc_async_exec" attribute on
+ your database handle to 1.  Not all ODBC drivers support asynchronous
+ execution.  To see if yours does, set odbc_async_exec to 1 and then check
+ it's value.  If the value is 1, your ODBC driver can do asynchronous
+ execution.  If the value is 0, your ODBC driver cannot.
+
+=head2 Changes in DBD::ODBC 0.45_4 July 22, 2002
+
+More fixes for DB2 tests and timestamp handling.
+ 
+=head2 Changes in DBD::ODBC 0.45_3 July 22, 2002
+
+Changes to internal timestamp type handling and test structure to ensure tests
+work for all platforms.  DB2 was giving me fits due to bad assumptions.  Thanks
+to Martin Evans (again) for help in identifying the problems and helping research
+solutions.  This includes the scale/precision values to correctly store full timestamps.
+
+=head2 Changes in DBD::ODBC 0.45_2 July 19, 2002
+
+Moving API usage to ODBC 3.0 specifications.  With lots of help from Martin Evans (again!).
+Thanks Martin!!!!!
+ 
+=head2 Changes in DBD::ODBC 0.44 July 18, 2002
+
+.44 was never officially released.
+Fix for do() and execute to handle DB2 correctly.  Patch/discovery thanks to Martin Evans.
+Partly moving towards defaulting to ODBC 3.x standards.
+
+=head2 Changes in DBD::ODBC 0.43 July 18, 2002
+
+Fix for FoxPro (and potentially other) Drivers!!!!!
+
+Add support for DBI column_info
+
+Fix for binding undef value which comes from dereferencing hash
+
+Fix to make all bound columns word (int) aligned in the buffer.
+
+=head2 Changes in DBD::ODBC 0.42 July 8, 2002
+
+Added patches to the tests to support ActiveState's automated build process.
+
+Fix ping() to try SQLTables for a test, instead of a strange query.  
+
+=head2 Changes in DBD::ODBC 0.41 April 15, 2002
+
+Fixed problem where SQLDescribeParam would fail (probably
+bug in ODBC driver).  Now reverts to SQL_VARCHAR if that
+happens, instead of failing the query.
+
+Fixed error report when using Oracle's driver.  There is
+a known problem.  Left the error on the test, but added
+warning indicating it's a known problem.
+
+=head2 Changes in DBD::ODBC 0.40 April 12, 2002
+
+Most significant change is the change in the default binding
+type which forces DBD::ODBC to attempt to determine the bind
+type if one is not passed.  I decided to make this the default
+behavior to make things as simple as possible.
+
+Fixed connection code put in 0.39 to work correctly.
+
+Two minor patches for building, one for Cygwin one
+if both iODBC and unixODBC libraries are installed.
+Probably need better command line on this, but if 
+someone has the problem, please let me know (and 
+hopefully send a patch with it).
+
+=head2 Changes in DBD::ODBC 0.39 March 12, 2002
+ 
+See mytest/longbin.pl for demonstration of inserting and retrieving
+long binary files to/from the db.  Uses MD5 algorithm to verify data.
+Please do some similar test(s) with your database before using it
+in production.  The various bind types are different for each database!
+
+Finally removed distribution of old iODBC.  See www.iodbc.org or
+www.unixodbc.org for newer/better versions of the ODBC driver
+manager for Unix (and others?). 
+
+Added ability to force ODBC environment version.
+ 
+Fix to SQLColAttributes.
+
+Changes to connect sequence to provide better error
+messages for those using DSN-less connections.
+
+=head2 Changes in DBD::ODBC 0.38 February 12, 2002
+
+Fixed do function (again) thanks to work by Martin Evans.
+
+=head2 Changes in DBD::ODBC 0.37 February 10, 2002
+
+Patches for get_info where return type is string.  Patches
+thanks to Steffen Goldner.  Thanks Steffen!
+
+Patched get_info to NOT attempt to get data for SQL_DRIVER_HSTMT
+and SQL_DRIVER_HDESC as they expect data in and have limited value
+(IMHO).
+
+Further fixed build for ODBC 2.x drivers.  The new SQLExecDirect
+code had SQLAllocHandle which is a 3.x function, not a 2.x function.
+Sigh.  I should have caught that the first time.  Signed, the Mad-and-
+not-thorough-enough-patcher.
+
+Additionally, a random core dump occurred in the tests, based upon the
+new SQLExecDirect code.  This has been fixed.
+ 
+ 
+=head2 Changes in DBD::ODBC 0.36 February 10, 2002
+
+Fixed build for ODBC 2.x drivers.  The new SQLExecDirect code
+had SQLFreeHandle which is a 3.x function, not a 2.x function.
+ 
+=head2 Changes in DBD::ODBC 0.35 February 9, 2002
+
+Fixed (finally) multiple result sets with differing
+numbers of columns.  The final fix was to call
+SQLFreeStmt(SQL_UNBIND) before repreparing
+the statement for the next query.
+
+Added more to the multi-statement tests to ensure
+the data retrieved was what was expected.
+
+Now, DBD::ODBC overrides DBI's do to call SQLExecDirect
+for simple statements (those without parameters).
+Please advise if you run into problems.  Hopefully,
+this will provide some small speed improvement for
+simple "do" statements.  You can also call
+$dbh->func($stmt, ExecDirect).  I'm not sure this has
+great value unless you need to ensure SQLExecDirect
+is being called.  Patches thanks to Merijn Broeren.
+Thanks Merijn!
+   
+=head2 Changes in DBD::ODBC 0.34 February 7, 2002
+ 
+Further revamped tests to attempt to determine if SQLDescribeParam
+will work to handle the binding types.  The t/08bind.t attempts
+to determine if SQLDescribeParam is supported.  note that Oracle's
+ODBC driver under NT doesn't work correctly when binding dates
+using the ODBC date formatting {d } or {ts }.  So, test #3 will
+fail in t/08bind.t
+
+New support for primary_key_info thanks to patches by Martin Evans.
+New support for catalog, schema, table and table_type in table_info
+thanks to Martin Evans.  Thanks Martin for your work and your
+continuing testing, suggestions and general support!
+
+Support for upcoming dbi get_info.
+ 
+=head2 Changes in DBD::ODBC 0.33_3 February 4, 2002
+
+Revamped tests to include tests for multiple result sets.
+The tests are ODBC driver platform specific and will be skipped
+for drivers which do not support multiple result sets.
+ 
+=head2 Changes in DBD::ODBC 0.33_2 February 4, 2002
+
+Finally tested new binding techniques with SQL Server 2000,
+but there is a nice little bug in their MDAC and ODBC
+drivers according to the knowledge base article # Q273813, titled
+
+   "FIX: "Incorrect Syntax near the Keyword 'by' "
+   Error Message with Column Names of "C", "CA" or "CAS" (Q273813)
+
+DBD::ODBC now does not name any of the columns A, B, C, or D
+they are now COL_A, COL_B, COL_C, COL_D.
+
+ *** NOTE: *** I AM STRONGLY CONSIDERING MAKING THE NEW
+ BINDING the default for future versions.  I do not believe
+ it will break much existing code (if any) as anyone binding
+ to non VARCHAR (without the ODBC driver doing a good conversion
+ from the VARCHAR) will have a problem.  It may be subtle, however,
+ since much code will work, but say, binding dates may not with
+ some drivers.
+   
+ Please comment soon...
+   
+=head2 Changes in DBD::ODBC 0.33_1 February 4, 2002
+
+*** WARNING: ***
+ 
+ Changes to the binding code to allow the use of SQLDescribeParam
+ to determine if the type of column being bound.  This is
+ experimental and activated by setting
+ 
+  $dbh->{odbc_default_bind_type} = 0; # before creating the query...
+
+Currently the default value of odbc_default_bind_type = SQL_VARCHAR
+which mimicks the current behavior.  If you set
+odbc_default_bind_type to 0, then SQLDescribeParam will be
+called to determine the columen type.  Not ALL databases
+handle this correctly.  For example, Oracle returns
+SQL_VARCHAR for all types and attempts to convert to the
+correct type for us.  However, if you use the ODBC escaped
+date/time format such as: {ts '1998-05-13 00:01:00'} then
+Oracle complains.  If you bind this with a SQL_TIMESTAMP type,
+however, Oracle's ODBC driver will parse the time/date correctly.
+Use at your own risk!
+
+Fix to dbdimp.c to allow quoted identifiers to begin/end
+with either " or '.
+The following will not be treated as if they have a bind placeholder:
+
+   "isEstimated?"
+   '01-JAN-1987 00:00:00'
+   'Does anyone insert a ?'
+
+				    
+=head2 Changes in DBD::ODBC 0.32 January 22, 2002
+
+More SAP patches to Makfile.PL to eliminate the call to Data Sources
+
+A patch to the test (for SAP and potentially others), to allow
+fallback to SQL_TYPE_DATE in the tests
+ 
+=head2 Changes in DBD::ODBC 0.31 January 18, 2002
+
+Added SAP patches to build directly against SAP driver instead of
+driver manager thanks to Flemming Frandsen (thanks!)
+
+Added support to fix ping for Oracle8.  May break other databases,
+so please report this as soon as possible.  The downside is that
+we need to actually execute the dummy query.
+ 
+
+=head2 Changes in DBD::ODBC 0.30 January 8, 2002
+
+Added ping patch for Solid courtesy of Marko Asplund
+
+Updated disconnect to rollback if autocommit is not on.
+This should silence some errors when disconnecting.
+
+Updated SQL_ROWSET_SIZE attribute.  Needed to force it to
+odbc_SQL_ROWSET_SIZE to obey the DBI rules.
+
+Added odbc_SQL_DRIVER_ODBC_VER, which obtains the version of
+the Driver upon connect.  This internal capture of the version is
+a read-only attributed and is used during array binding of parameters.
+ 
+Added odbc_ignore_named_placeholders attribute to facilicate
+creating triggers within SAPDB and Oracle, to name two. The
+syntax in these DBs is to allow use of :old and :new to
+access column values before and after updates.  Example:
+
+ $dbh->{odbc_ignore_named_placeholders} = 1; # set it for all future statements
+					  # ignores :foo, :new, etc, but not :1 or ?
+ $dbh->do("create or replace etc :new.D = sysdate etc");
+ 
+
+=head2 Changes in DBD::ODBC 0.29 August 22, 2001
+
+Cygwin patches from Neil Lunn (untested by me).  Thanks Neil!
+ 
+SQL_ROWSET_SIZE attribute patch from Andrew Brown 
+
+ There are only 2 additional lines allowing for the setting of
+ SQL_ROWSET_SIZE as db handle option.
+
+ The purpose to my madness is simple. SqlServer (7 anyway) by default
+ supports only one select statement at once (using std ODBC cursors).
+ According to the SqlServer documentation you can alter the default setting
+ of
+ three values to force the use of server cursors - in which case multiple
+ selects are possible.
+
+ The code change allows for:
+ $dbh->{SQL_ROWSET_SIZE} = 2;    # Any value > 1
+
+ For this very purpose.
+
+ The setting of SQL_ROWSET_SIZE only affects the extended fetch command as
+ far as I can work out and thus setting this option shouldn't affect
+ DBD::ODBC operations directly in any way.
+
+ Andrew
+
+
+VMS and other patches from Martin Evans (thanks!)
+
+[1] a fix for Makefile.PL to build DBD::ODBC on OpenVMS.
+
+[2] fix trace message coredumping after SQLDriverConnect
+
+[3] fix call to SQLCancel which fails to pass the statement handle properly.
+
+[4] consume diagnostics after SQLDriverConnect/SQLConnect call or they remain
+    until the next error occurs and it then looks confusing (this is due to
+    ODBC spec for SQLError). e.g. test 02simple returns a data truncated error
+    only now instead of all the informational diags that are left from the
+    connect call, like the "database changed", "language changed" messages you
+    get from MS SQL Server.
+
+Replaced C++ style comments with C style to support more platforms more easily.
+
+Fixed bug which use the single quote (') instead of a double quote (") for "literal" column names.  This
+   helped when having a colon (:) in the column name.
+
+Fixed bug which would cause DBD::ODBC to core-dump (crash) if DBI tracing level was greater than 3.
+
+Fixed problem where ODBC.pm would have "use of uninitialized variable" if calling DBI's type_info.
+
+Fixed problem where ODBC.xs *may* have an overrun when calling SQLDataSources. 
+
+Fixed problem with DBI 1.14, where fprintf was being called instead of PerlIO_printf for debug information
+
+Fixed problem building with unixODBC per patch from Nick Gorham   
+
+Added ability to bind_param_inout() via patches from Jeremy Cooper.  Haven't figured out a good, non-db specific
+   way to test.  My current test platform attempts to determine the connected database type via
+   ugly hacks and will test, if it thinks it can.  Feel free to patch and send me something...Also, my
+   current Oracle ODBC driver fails miserably and dies.
+
+Updated t/02simple.t to not print an error, when there is not one.
+   
+=head2 Changes in DBD::ODBC 0.28 March 23, 2000
+
+Added support for SQLSpecialColumns thanks to patch provided by Martin J. Evans [martin@easysoft.com]
+
+Fixed bug introduced in 0.26 which was introduced of SQLMoreResults was not supported by the driver.
+
+=head2 Changes in DBD::ODBC 0.27 March 8, 2000
+
+Examined patch for ping method to repair problem reported by Chris Bezil.  Thanks Chris!
+
+Added simple test for ping method working which should identify this in the future.
+
+=head2 Changes in DBD::ODBC 0.26 March 5, 2000
+
+Put in patch for returning only positive rowcounts from dbd_st_execute.  The original patch
+was submitted by Jon Smirl and put back in by David Good.  Reasoning seems sound, so I put it
+back in.  However, any databases that return negative rowcounts for specific reasons,
+will no longer do so.
+
+Put in David Good's patch for multiple result sets.  Thanks David!  See mytest\moreresults.pl for
+an example of usage.
+
+Added readme.txt in iodbcsrc explaining an issue there with iODBC 2.50.3 and C<data_sources>.
+
+Put in rudimentary cancel support via SQLCancel.  Call $sth->cencel to utilize.  However, it is largely
+untested by me, as I do not have a good sample for this yet.  It may come in handy with threaded
+perl, someday or it may work in a signal handler.
+   
+=head2 Changes in DBD::ODBC 0.25 March 4, 2000
+
+Added conditional compilation for SQL_WVARCHAR and SQL_WLONGVARCHAR.  If they
+are not defined by your driver manager, they will not be compiled in to the code.
+If you would like to support these types on some platforms, you may be able to
+#define SQL_WVARCHAR (-9)
+#define SQL_WLONGVARCHAR (-10)
+
+Added more long tests with binding in t\09bind.t.  Note use of bind_param!
+ 
+=head2 Changes in DBD::ODBC 0.24 February 24, 2000
+
+Fixed Test #13 in 02simple.t.  Would fail, improperly, if there was only one data source defined.
+
+Fixed (hopefully) SQL Server 7 and ntext type "Out of Memory!" errors via patch from Thomas Lowery.  Thanks Thomas!
+
+Added more support for Solid to handle the fact that it does not support data_sources nor SQLDriverConnect.
+Patch supplied by Samuli Karkkainen [skarkkai@woods.iki.fi].  Thanks!  It's untested by me, however.
+
+Added some information from Adam Curtin about a bug in iodbc 2.50.3's data_sources.  See
+iodbcsrc\readme.txt.
+
+Added information in this pod from Stephen Arehart regarding DSNLess connections.
+
+Added fix for sp_prepare/sp_execute bug reported by Paul G. Weiss.
+
+Added some code for handling a hint on disconnect where the user gets an error for not committing.
+ 
+=head2 Changes in DBD::ODBC 0.22 September 8, 1999
+
+Fixed for threaded perl builds.  Note that this was tested only on Win32, with no threads in use and using DBI 1.13.
+Note, for ActiveState/PERL_OBJECT builds, DBI 1.13_01 is required as of 9/8/99.  
+If you are using ActiveState's perl, this can be installed by using PPM.
+
+
+=head2 Changes in DBD::ODBC 0.21 
+
+Thanks to all who provided patches!
+
+Added ability to connect to an ODBC source without prior creation of DSN.  See mytest/contest.pl for example with MS Access.
+(Also note that you will need documentation for your ODBC driver -- which, sadly, can be difficult to find).
+
+Fixed case sensitivity in tests.
+
+Hopefully fixed test #4 in t/09bind.t.  Updated it to insert the date column and updated it to find the right
+type of the column.  However, it doesn't seem to work on my Linux test machine, using the OpenLink drivers 
+with MS-SQL Server (6.5).  It complains about binding the date time.  The same test works under Win32 with 
+SQL Server 6.5, Oracle 8.0.3 and MS Access 97 ODBC drivers.  Hmmph.
+
+Fixed some binary type issues (patches from Jon Smirl)
+
+Added SQLStatistics, SQLForeignKeys, SQLPrimaryKeys (patches from Jon Smirl)
+Thanks (again), Jon, for providing the build_results function to help reduce duplicate code!
+
+Worked on LongTruncOk for Openlink drivers.
+
+Note: those trying to bind variables need to remember that you should use the following syntax:
+
+	use DBI;
+	...
+	$sth->bind_param(1, $str, DBI::SQL_LONGVARCHAR);
+
+Added support for unixodbc (per Nick Gorham)
+Added support for OpenLinks udbc (per Patrick van Kleef)
+Added Support for esodbc (per Martin Evans)
+Added Support for Easysoft (per Bob Kline)
+
+Changed table_info to produce a list of views, too.
+Fixed bug in SQLColumns call.
+Fixed blob handling via patches from Jochen Wiedmann.
+Added data_sources capability via snarfing code from DBD::Adabas (Jochen Wiedmann)
+
+=head2 Changes in DBD::ODBC 0.20 August 14, 1998
+
+SQLColAttributes fixes for SQL Server and MySQL. Fixed tables method
+by renaming to new table_info method. Added new tyoe_info_all method.
+Improved Makefile.PL support for Adabase.
+
+=head2 Changes in DBD::ODBC 0.19
+
+Added iODBC source code to distribution.Fall-back to using iODBC header
+files in some cases.
+
+=head2 Changes in DBD::ODBC 0.18
+
+Enhancements to build process. Better handling of errors in
+error handling code.
+
+=head2 Changes in DBD::ODBC 0.17 
+
+This release is mostly due to the good work of Jeff Urlwin.
+My eternal thanks to you Jeff.
+
+Fixed "SQLNumResultCols err" on joins and 'order by' with some
+drivers (see Microsoft Knowledge Base article #Q124899).
+Thanks to Paul O'Fallon for that one.
+
+Added more (probably incomplete) support for unix ODBC in Makefile.PL
+
+Increased default SQL_COLUMN_DISPLAY_SIZE and SQL_COLUMN_LENGTH to 2000
+for drivers that don't provide a way to query them dynamically. Was 100!
+
+When fetch reaches the end-of-data it automatically frees the internal
+ODBC statement handle and marks the DBI statement handle as inactive
+(thus an explicit 'finish' is *not* required).
+
+Also:
+
+LongTruncOk for Oracle ODBC (where fbh->datalen < 0)
+
+Added tracing into SQLBindParameter (help diagnose oracle odbc bug)
+
+Fixed/worked around bug/result from Latest Oracle ODBC driver where in
+SQLColAttribute cbInfoValue was changed to 0 to indicate fDesc had a value
+
+Added work around for compiling w/ActiveState PRK (PERL_OBJECT)
+
+Updated tests to include date insert and type
+
+Added more "backup" SQL_xxx types for tests                                  
+
+Updated bind test to test binding select
+
+ NOTE: bind insert fails on Paradox driver (don't know why)
+
+Added support for: (see notes below)
+
+  SQLGetInfo       via $dbh->func(xxx, GetInfo)
+  SQLGetTypeInfo   via $dbh->func(xxx, GetTypeInfo)
+  SQLDescribeCol   via $sth->func(colno, DescribeCol)
+  SQLColAttributes via $sth->func(xxx, colno, ColAttributes)
+  SQLGetFunctions  via $dbh->func(xxx, GetFunctions)
+  SQLColumns       via $dbh->func(catalog, schema, table, column, 'columns')
+
+Fixed $DBI::err to reflect the real ODBC error code
+which is a 5 char code, not necessarily numeric.
+
+Fixed fetches when LongTruncOk == 1.
+
+Updated tests to pass more often (hopefully 100% <G>)
+
+Updated tests to test long reading, inserting and the LongTruncOk attribute.
+
+Updated tests to be less driver specific.  
+
+They now rely upon SQLGetTypeInfo I<heavily> in order to create the tables.
+The test use this function to "ask" the driver for the name of the SQL type
+to correctly create long, varchar, etc types.  For example, in Oracle the
+SQL_VARCHAR type is VARCHAR2, while MS Access uses TEXT for the SQL Name.  
+Again, in Oracle the SQL_LONGVARCHAR is LONG, while in Access it's MEMO.
+The tests currently handle this correctly (at least with Access and Oracle,
+MS SQL server will be tested also).
+
+=cut
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBD/Proxy.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBD/Proxy.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBD/Proxy.pm	(revision 14139)
@@ -0,0 +1,937 @@
+#   -*- perl -*-
+#
+#
+#   DBD::Proxy - DBI Proxy driver
+#
+#
+#   Copyright (c) 1997,1998  Jochen Wiedmann
+#
+#   The DBD::Proxy module is free software; you can redistribute it and/or
+#   modify it under the same terms as Perl itself. In particular permission
+#   is granted to Tim Bunce for distributing this as a part of the DBI.
+#
+#
+#   Author: Jochen Wiedmann
+#           Am Eisteich 9
+#           72555 Metzingen
+#           Germany
+#
+#           Email: joe@ispsoft.de
+#           Phone: +49 7123 14881
+#
+
+use strict;
+
+require DBI;
+DBI->require_version(1.0201);
+
+use RPC::PlClient 0.2000; # XXX change to 0.2017 once it's released
+
+
+
+package DBD::Proxy;
+
+use vars qw($VERSION $drh %ATTR);
+
+$VERSION = "0.2004";
+
+$drh = undef;		# holds driver handle once initialised
+
+%ATTR = (	# common to db & st, see also %ATTR in DBD::Proxy::db & ::st
+    'Warn'	=> 'local',
+    'Active'	=> 'local',
+    'Kids'	=> 'local',
+    'CachedKids' => 'local',
+    'PrintError' => 'local',
+    'RaiseError' => 'local',
+    'HandleError' => 'local',
+);
+
+sub driver ($$) {
+    if (!$drh) {
+	my($class, $attr) = @_;
+
+	$class .= "::dr";
+
+	$drh = DBI::_new_drh($class, {
+	    'Name' => 'Proxy',
+	    'Version' => $VERSION,
+	    'Attribution' => 'DBD::Proxy by Jochen Wiedmann',
+	    });
+    }
+    $drh;
+}
+
+sub CLONE {
+    undef $drh;
+}
+
+sub proxy_set_err {
+  my ($h,$errmsg) = @_;
+  my ($err, $state) = ($errmsg =~ s/ \[err=(.*?),state=(.*?)\]//)
+	? ($1, $2) : (1, ' ' x 5);
+  return $h->set_err($err, $errmsg, $state);
+}
+
+package DBD::Proxy::dr; # ====== DRIVER ======
+
+$DBD::Proxy::dr::imp_data_size = 0;
+
+sub connect ($$;$$) {
+    my($drh, $dsn, $user, $auth, $attr)= @_;
+    my($dsnOrig) = $dsn;
+
+    my %attr = %$attr;
+    my ($var, $val);
+    while (length($dsn)) {
+	if ($dsn =~ /^dsn=(.*)/) {
+	    $attr{'dsn'} = $1;
+	    last;
+	}
+	if ($dsn =~ /^(.*?);(.*)/) {
+	    $var = $1;
+	    $dsn = $2;
+	} else {
+	    $var = $dsn;
+	    $dsn = '';
+	}
+	if ($var =~ /^(.*?)=(.*)/) {
+	    $var = $1;
+	    $val = $2;
+	    $attr{$var} = $val;
+	}
+    }
+
+    my $err = '';
+    if (!defined($attr{'hostname'})) { $err .= " Missing hostname."; }
+    if (!defined($attr{'port'}))     { $err .= " Missing port."; }
+    if (!defined($attr{'dsn'}))      { $err .= " Missing remote dsn."; }
+
+    # Create a cipher object, if requested
+    my $cipherRef = undef;
+    if ($attr{'cipher'}) {
+	$cipherRef = eval { $attr{'cipher'}->new(pack('H*',
+							$attr{'key'})) };
+	if ($@) { $err .= " Cannot create cipher object: $@."; }
+    }
+    my $userCipherRef = undef;
+    if ($attr{'userkey'}) {
+	my $cipher = $attr{'usercipher'} || $attr{'cipher'};
+	$userCipherRef = eval { $cipher->new(pack('H*', $attr{'userkey'})) };
+	if ($@) { $err .= " Cannot create usercipher object: $@."; }
+    }
+
+    return DBD::Proxy::proxy_set_err($drh, $err) if $err; # Returns undef
+
+    my %client_opts = (
+		       'peeraddr'	=> $attr{'hostname'},
+		       'peerport'	=> $attr{'port'},
+		       'socket_proto'	=> 'tcp',
+		       'application'	=> $attr{dsn},
+		       'user'		=> $user || '',
+		       'password'	=> $auth || '',
+		       'version'	=> $DBD::Proxy::VERSION,
+		       'cipher'	        => $cipherRef,
+		       'debug'		=> $attr{debug}   || 0,
+		       'timeout'	=> $attr{timeout} || undef,
+		       'logfile'	=> $attr{logfile} || undef
+		      );
+    # Options starting with 'proxy_rpc_' are forwarded to the RPC layer after
+    # stripping the prefix.
+    while (my($var,$val) = each %attr) {
+	if ($var =~ s/^proxy_rpc_//) {
+	    $client_opts{$var} = $val;
+	}
+    }
+    # Create an RPC::PlClient object.
+    my($client, $msg) = eval { RPC::PlClient->new(%client_opts) };
+
+    return DBD::Proxy::proxy_set_err($drh, "Cannot log in to DBI::ProxyServer: $@")
+	if $@; # Returns undef
+    return DBD::Proxy::proxy_set_err($drh, "Constructor didn't return a handle: $msg")
+	unless ($msg =~ /^((?:\w+|\:\:)+)=(\w+)/); # Returns undef
+
+    $msg = RPC::PlClient::Object->new($1, $client, $msg);
+
+    my $max_proto_ver;
+    my ($server_ver_str) = eval { $client->Call('Version') };
+    if ( $@ ) {
+      # Server denies call, assume legacy protocol.
+      $max_proto_ver = 1;
+    } else {
+      # Parse proxy server version.
+      my ($server_ver_num) = $server_ver_str =~ /^DBI::ProxyServer\s+([\d\.]+)/;
+      $max_proto_ver = $server_ver_num >= 0.3 ? 2 : 1;
+    }
+    my $req_proto_ver;
+    if ( exists $attr{proxy_lazy_prepare} ) {
+      $req_proto_ver = ($attr{proxy_lazy_prepare} == 0) ? 2 : 1;
+      return DBD::Proxy::proxy_set_err($drh, 
+                 "DBI::ProxyServer does not support synchronous statement preparation.")
+	if $max_proto_ver < $req_proto_ver;
+    }
+
+    # Switch to user specific encryption mode, if desired
+    if ($userCipherRef) {
+	$client->{'cipher'} = $userCipherRef;
+    }
+
+    # create a 'blank' dbh
+    my $this = DBI::_new_dbh($drh, {
+	    'Name' => $dsnOrig,
+	    'proxy_dbh' => $msg,
+	    'proxy_client' => $client,
+	    'RowCacheSize' => $attr{'RowCacheSize'} || 20,
+	    'proxy_proto_ver' => $req_proto_ver || 1
+   });
+
+    foreach $var (keys %attr) {
+	if ($var =~ /proxy_/) {
+	    $this->{$var} = $attr{$var};
+	}
+    }
+    $this->SUPER::STORE('Active' => 1);
+
+    $this;
+}
+
+
+sub DESTROY { undef }
+
+
+package DBD::Proxy::db; # ====== DATABASE ======
+
+$DBD::Proxy::db::imp_data_size = 0;
+
+sub commit;
+sub rollback;
+
+use vars qw(%ATTR $AUTOLOAD);
+
+# inherited: STORE / FETCH against this class.
+# local:     STORE / FETCH against parent class.
+# cached:    STORE to remote and local objects, FETCH from local.
+# remote:    STORE / FETCH against remote object only (default).
+#
+# Note: Attribute names starting with 'proxy_' always treated as 'inherited'.
+#
+%ATTR = (	# see also %ATTR in DBD::Proxy::st
+    %DBD::Proxy::ATTR,
+    RowCacheSize => 'inherited',
+    AutoCommit => 'cached',
+    Statement => 'local',
+    Driver => 'local',
+    dbi_connect_closure => 'local',
+    Username => 'local',
+);
+
+sub AUTOLOAD {
+    my $method = $AUTOLOAD;
+    $method =~ s/(.*::(.*)):://;
+    # warn "AUTOLOAD of $method";
+    my $class = $1;
+    my $type = $2;
+    my %expand =
+	( 'method' => $method,
+	  'class' => $class,
+	  'type' => $type,
+	  'h' => "DBI::_::$type"
+	);
+    my $method_code = UNIVERSAL::can($expand{'h'}, $method) ?
+	q/package ~class~;
+          sub ~method~ {
+            my $h = shift;
+	    my @result = wantarray
+		? eval {        $h->{'proxy_~type~h'}->~method~(@_) }
+		: eval { scalar $h->{'proxy_~type~h'}->~method~(@_) };
+            return DBD::Proxy::proxy_set_err($h, $@) if $@;
+            wantarray ? @result : $result[0];
+          }
+	 / :
+        q/package ~class~;
+	  sub ~method~ {
+	    my $h = shift;
+	    my @result = wantarray
+		? eval {        $h->{'proxy_~type~h'}->func(@_, '~method~') }
+		: eval { scalar $h->{'proxy_~type~h'}->func(@_, '~method~') };
+	    return DBD::Proxy::proxy_set_err($h, $@) if $@;
+	    wantarray ? @result : $result[0];
+          }
+         /;
+    $method_code =~ s/\~(\w+)\~/$expand{$1}/eg;
+    local $SIG{__DIE__} = 'DEFAULT';
+    my $err = do { local $@; eval $method_code.2; $@ };
+    die $err if $err;
+    goto &$AUTOLOAD;
+}
+
+sub DESTROY {
+    my $dbh = shift;
+    local $@ if $@;	# protect $@
+    $dbh->disconnect if $dbh->SUPER::FETCH('Active');
+}
+
+sub disconnect ($) {
+    my ($dbh) = @_;
+
+    # Sadly the Proxy too-often disagrees with the backend database
+    # on the subject of 'Active'.  In the short term, I'd like the
+    # Proxy to ease up and let me decide when it's proper to go over
+    # the wire.  This ultimately applies to finish() as well.
+    #return unless $dbh->SUPER::FETCH('Active');
+
+    # Drop database connection at remote end
+    my $rdbh = $dbh->{'proxy_dbh'};
+    local $SIG{__DIE__} = 'DEFAULT';
+    eval { $rdbh->disconnect() };
+    DBD::Proxy::proxy_set_err($dbh, $@) if $@;
+    
+    # Close TCP connect to remote
+    # XXX possibly best left till DESTROY? Add a config attribute to choose?
+    #$dbh->{proxy_client}->Disconnect(); # Disconnect method requires newer PlRPC module
+    $dbh->{proxy_client}->{socket} = undef; # hack
+
+    $dbh->SUPER::STORE('Active' => 0);
+    1;
+}
+
+
+sub STORE ($$$) {
+    my($dbh, $attr, $val) = @_;
+    my $type = $ATTR{$attr} || 'remote';
+
+    if ($attr =~ /^proxy_/  ||  $type eq 'inherited') {
+	$dbh->{$attr} = $val;
+	return 1;
+    }
+
+    if ($type eq 'remote'  ||  $type eq 'cached') {
+        local $SIG{__DIE__} = 'DEFAULT';
+	local $@;
+	my $result = eval { $dbh->{'proxy_dbh'}->STORE($attr => $val) };
+	return DBD::Proxy::proxy_set_err($dbh, $@) if $@; # returns undef
+	$dbh->{$attr} = $val if $type eq 'cached';
+	return $result;
+    }
+    return $dbh->SUPER::STORE($attr => $val);
+}
+
+sub FETCH ($$) {
+    my($dbh, $attr) = @_;
+    my $type = $ATTR{$attr} || 'remote';
+
+    if ($attr =~ /^proxy_/  ||  $type eq 'inherited'  ||
+	$type eq 'cached') {
+	return $dbh->{$attr};
+    }
+
+    return $dbh->SUPER::FETCH($attr) unless $type eq 'remote';
+
+    local $SIG{__DIE__} = 'DEFAULT';
+    local $@;
+    my $result = eval { $dbh->{'proxy_dbh'}->FETCH($attr) };
+    return DBD::Proxy::proxy_set_err($dbh, $@) if $@;
+    return $result;
+}
+
+sub prepare ($$;$) {
+    my($dbh, $stmt, $attr) = @_;
+    my $sth = DBI::_new_sth($dbh, {
+				   'Statement' => $stmt,
+				   'proxy_attr' => $attr,
+				   'proxy_cache_only' => 0,
+				   'proxy_params' => [],
+				  }
+			   );
+    my $proto_ver = $dbh->{'proxy_proto_ver'};
+    if ( $proto_ver > 1 ) {
+      $sth->{'proxy_attr_cache'} = {cache_filled => 0};
+      my $rdbh = $dbh->{'proxy_dbh'};
+      local $SIG{__DIE__} = 'DEFAULT';
+      local $@;
+      my $rsth = eval { $rdbh->prepare($sth->{'Statement'}, $sth->{'proxy_attr'}, undef, $proto_ver) };
+      return DBD::Proxy::proxy_set_err($sth, $@) if $@;
+      return DBD::Proxy::proxy_set_err($sth, "Constructor didn't return a handle: $rsth")
+	unless ($rsth =~ /^((?:\w+|\:\:)+)=(\w+)/);
+    
+      my $client = $dbh->{'proxy_client'};
+      $rsth = RPC::PlClient::Object->new($1, $client, $rsth);
+      
+      $sth->{'proxy_sth'} = $rsth;
+      # If statement is a positioned update we do not want any readahead.
+      $sth->{'RowCacheSize'} = 1 if $stmt =~ /\bfor\s+update\b/i;
+    # Since resources are used by prepared remote handle, mark us active.
+    $sth->SUPER::STORE(Active => 1);
+    }
+    $sth;
+}
+
+sub quote {
+    my $dbh = shift;
+    my $proxy_quote = $dbh->{proxy_quote} || 'remote';
+
+    return $dbh->SUPER::quote(@_)
+	if $proxy_quote eq 'local' && @_ == 1;
+
+    # For the common case of only a single argument
+    # (no $data_type) we could learn and cache the behaviour.
+    # Or we could probe the driver with a few test cases.
+    # Or we could add a way to ask the DBI::ProxyServer
+    # if $dbh->can('quote') == \&DBI::_::db::quote.
+    # Tim
+    #
+    # Sounds all *very* smart to me. I'd rather suggest to
+    # implement some of the typical quote possibilities
+    # and let the user set
+    #    $dbh->{'proxy_quote'} = 'backslash_escaped';
+    # for example.
+    # Jochen
+    local $SIG{__DIE__} = 'DEFAULT';
+    local $@;
+    my $result = eval { $dbh->{'proxy_dbh'}->quote(@_) };
+    return DBD::Proxy::proxy_set_err($dbh, $@) if $@;
+    return $result;
+}
+
+sub table_info {
+    my $dbh = shift;
+    my $rdbh = $dbh->{'proxy_dbh'};
+    #warn "table_info(@_)";
+    local $SIG{__DIE__} = 'DEFAULT';
+    local $@;
+    my($numFields, $names, $types, @rows) = eval { $rdbh->table_info(@_) };
+    return DBD::Proxy::proxy_set_err($dbh, $@) if $@;
+    my ($sth, $inner) = DBI::_new_sth($dbh, {
+        'Statement' => "SHOW TABLES",
+	'proxy_params' => [],
+	'proxy_data' => \@rows,
+	'proxy_attr_cache' => { 
+		'NUM_OF_PARAMS' => 0, 
+		'NUM_OF_FIELDS' => $numFields, 
+		'NAME' => $names, 
+		'TYPE' => $types,
+		'cache_filled' => 1
+		},
+    	'proxy_cache_only' => 1,
+    });
+    $sth->SUPER::STORE('NUM_OF_FIELDS' => $numFields);
+    $inner->{NAME} = $names;
+    $inner->{TYPE} = $types;
+    $sth->SUPER::STORE('Active' => 1); # already execute()'d
+    $sth->{'proxy_rows'} = @rows;
+    return $sth;
+}
+
+sub tables {
+    my $dbh = shift;
+    #warn "tables(@_)";
+    return $dbh->SUPER::tables(@_);
+}
+
+
+sub type_info_all {
+    my $dbh = shift;
+    local $SIG{__DIE__} = 'DEFAULT';
+    local $@;
+    my $result = eval { $dbh->{'proxy_dbh'}->type_info_all(@_) };
+    return DBD::Proxy::proxy_set_err($dbh, $@) if $@;
+    return $result;
+}
+
+
+package DBD::Proxy::st; # ====== STATEMENT ======
+
+$DBD::Proxy::st::imp_data_size = 0;
+
+use vars qw(%ATTR);
+
+# inherited:  STORE to current object. FETCH from current if exists, else call up
+#              to the (proxy) database object.
+# local:      STORE / FETCH against parent class.
+# cache_only: STORE noop (read-only).  FETCH from private_* if exists, else call
+#              remote and cache the result.
+# remote:     STORE / FETCH against remote object only (default).
+#
+# Note: Attribute names starting with 'proxy_' always treated as 'inherited'.
+#
+%ATTR = (	# see also %ATTR in DBD::Proxy::db
+    %DBD::Proxy::ATTR,
+    'Database' => 'local',
+    'RowsInCache' => 'local',
+    'RowCacheSize' => 'inherited',
+    'NULLABLE' => 'cache_only',
+    'NAME' => 'cache_only',
+    'TYPE' => 'cache_only',
+    'PRECISION' => 'cache_only',
+    'SCALE' => 'cache_only',
+    'NUM_OF_FIELDS' => 'cache_only',
+    'NUM_OF_PARAMS' => 'cache_only'
+);
+
+*AUTOLOAD = \&DBD::Proxy::db::AUTOLOAD;
+
+sub execute ($@) {
+    my $sth = shift;
+    my $params = @_ ? \@_ : $sth->{'proxy_params'};
+
+    # new execute, so delete any cached rows from previous execute
+    undef $sth->{'proxy_data'};
+
+    my $rsth = $sth->{proxy_sth};
+    my $dbh = $sth->FETCH('Database');
+    my $proto_ver = $dbh->{proxy_proto_ver};
+
+    my ($numRows, @outData);
+
+    local $SIG{__DIE__} = 'DEFAULT';
+    local $@;
+    if ( $proto_ver > 1 ) {
+      ($numRows, @outData) = eval { $rsth->execute($params, $proto_ver) };
+      return DBD::Proxy::proxy_set_err($sth, $@) if $@;
+      
+      # Attributes passed back only on the first execute() of a statement.
+      unless ($sth->{proxy_attr_cache}->{cache_filled}) {
+	my ($numFields, $numParams, $names, $types) = splice(@outData, 0, 4); 
+	$sth->{'proxy_attr_cache'} = {
+				      'NUM_OF_FIELDS' => $numFields,
+				      'NUM_OF_PARAMS' => $numParams,
+				      'NAME'          => $names,
+				      'cache_filled'  => 1
+				     };
+	$sth->SUPER::STORE('NUM_OF_FIELDS' => $numFields);
+	$sth->SUPER::STORE('NUM_OF_PARAMS' => $numParams);
+      }
+
+    }
+    else {
+      if ($rsth) {
+	($numRows, @outData) = eval { $rsth->execute($params, $proto_ver) };
+	return DBD::Proxy::proxy_set_err($sth, $@) if $@;
+
+      }
+      else {
+	my $rdbh = $dbh->{'proxy_dbh'};
+	
+	# Legacy prepare is actually prepare + first execute on the server.
+        ($rsth, @outData) =
+	  eval { $rdbh->prepare($sth->{'Statement'},
+				$sth->{'proxy_attr'}, $params, $proto_ver) };
+	return DBD::Proxy::proxy_set_err($sth, $@) if $@;
+	return DBD::Proxy::proxy_set_err($sth, "Constructor didn't return a handle: $rsth")
+	  unless ($rsth =~ /^((?:\w+|\:\:)+)=(\w+)/);
+	
+	my $client = $dbh->{'proxy_client'};
+	$rsth = RPC::PlClient::Object->new($1, $client, $rsth);
+
+	my ($numFields, $numParams, $names, $types) = splice(@outData, 0, 4);
+	$sth->{'proxy_sth'} = $rsth;
+        $sth->{'proxy_attr_cache'} = {
+	    'NUM_OF_FIELDS' => $numFields,
+	    'NUM_OF_PARAMS' => $numParams,
+	    'NAME'          => $names
+        };
+	$sth->SUPER::STORE('NUM_OF_FIELDS' => $numFields);
+	$sth->SUPER::STORE('NUM_OF_PARAMS' => $numParams);
+	$numRows = shift @outData;
+      }
+    }
+    # Always condition active flag.
+    $sth->SUPER::STORE('Active' => 1) if $sth->FETCH('NUM_OF_FIELDS'); # is SELECT
+    $sth->{'proxy_rows'} = $numRows;
+    # Any remaining items are output params.
+    if (@outData) {
+	foreach my $p (@$params) {
+	    if (ref($p->[0])) {
+		my $ref = shift @outData;
+		${$p->[0]} = $$ref;
+	    }
+	}
+    }
+
+    $sth->{'proxy_rows'} || '0E0';
+}
+
+sub fetch ($) {
+    my $sth = shift;
+
+    my $data = $sth->{'proxy_data'};
+
+    if(!$data || !@$data) {
+	return undef unless $sth->SUPER::FETCH('Active');
+
+	my $rsth = $sth->{'proxy_sth'};
+	if (!$rsth) {
+	    die "Attempt to fetch row without execute";
+	}
+	my $num_rows = $sth->FETCH('RowCacheSize') || 20;
+	local $SIG{__DIE__} = 'DEFAULT';
+	local $@;
+	my @rows = eval { $rsth->fetch($num_rows) };
+	return DBD::Proxy::proxy_set_err($sth, $@) if $@;
+	unless (@rows == $num_rows) {
+	    undef $sth->{'proxy_data'};
+	    # server side has already called finish
+	    $sth->SUPER::STORE(Active => 0);
+	}
+	return undef unless @rows;
+	$sth->{'proxy_data'} = $data = [@rows];
+    }
+    my $row = shift @$data;
+
+    $sth->SUPER::STORE(Active => 0) if ( $sth->{proxy_cache_only} and !@$data );
+    return $sth->_set_fbav($row);
+}
+*fetchrow_arrayref = \&fetch;
+
+sub rows ($) {
+    my($sth) = @_;
+    $sth->{'proxy_rows'};
+}
+
+sub finish ($) {
+    my($sth) = @_;
+    return 1 unless $sth->SUPER::FETCH('Active');
+    my $rsth = $sth->{'proxy_sth'};
+    $sth->SUPER::STORE('Active' => 0);
+    return 0 unless $rsth; # Something's out of sync
+    my $no_finish = exists($sth->{'proxy_no_finish'})
+ 	? $sth->{'proxy_no_finish'}
+	: $sth->FETCH('Database')->{'proxy_no_finish'};
+    unless ($no_finish) {
+        local $SIG{__DIE__} = 'DEFAULT';
+	local $@;
+	my $result = eval { $rsth->finish() };
+	return DBD::Proxy::proxy_set_err($sth, $@) if $@;
+	return $result;
+    }
+    1;
+}
+
+sub STORE ($$$) {
+    my($sth, $attr, $val) = @_;
+    my $type = $ATTR{$attr} || 'remote';
+
+    if ($attr =~ /^proxy_/  ||  $type eq 'inherited') {
+	$sth->{$attr} = $val;
+	return 1;
+    }
+
+    if ($type eq 'cache_only') {
+	return 0;
+    }
+
+    if ($type eq 'remote') {
+	my $rsth = $sth->{'proxy_sth'}  or  return undef;
+        local $SIG{__DIE__} = 'DEFAULT';
+	local $@;
+	my $result = eval { $rsth->STORE($attr => $val) };
+	return DBD::Proxy::proxy_set_err($sth, $@) if ($@);
+	return $result;
+    }
+    return $sth->SUPER::STORE($attr => $val);
+}
+
+sub FETCH ($$) {
+    my($sth, $attr) = @_;
+
+    if ($attr =~ /^proxy_/) {
+	return $sth->{$attr};
+    }
+
+    my $type = $ATTR{$attr} || 'remote';
+    if ($type eq 'inherited') {
+	if (exists($sth->{$attr})) {
+	    return $sth->{$attr};
+	}
+	return $sth->FETCH('Database')->{$attr};
+    }
+
+    if ($type eq 'cache_only'  &&
+	    exists($sth->{'proxy_attr_cache'}->{$attr})) {
+	return $sth->{'proxy_attr_cache'}->{$attr};
+    }
+
+    if ($type ne 'local') {
+	my $rsth = $sth->{'proxy_sth'}  or  return undef;
+        local $SIG{__DIE__} = 'DEFAULT';
+	local $@;
+	my $result = eval { $rsth->FETCH($attr) };
+	return DBD::Proxy::proxy_set_err($sth, $@) if $@;
+	return $result;
+    }
+    elsif ($attr eq 'RowsInCache') {
+	my $data = $sth->{'proxy_data'};
+	$data ? @$data : 0;
+    }
+    else {
+	$sth->SUPER::FETCH($attr);
+    }
+}
+
+sub bind_param ($$$@) {
+    my $sth = shift; my $param = shift;
+    $sth->{'proxy_params'}->[$param-1] = [@_];
+}
+*bind_param_inout = \&bind_param;
+
+sub DESTROY {
+    my $sth = shift;
+    $sth->finish if $sth->SUPER::FETCH('Active');
+}
+
+
+1;
+
+
+__END__
+
+=head1 NAME
+
+DBD::Proxy - A proxy driver for the DBI
+
+=head1 SYNOPSIS
+
+  use DBI;
+
+  $dbh = DBI->connect("dbi:Proxy:hostname=$host;port=$port;dsn=$db",
+                      $user, $passwd);
+
+  # See the DBI module documentation for full details
+
+=head1 DESCRIPTION
+
+DBD::Proxy is a Perl module for connecting to a database via a remote
+DBI driver.
+
+This is of course not needed for DBI drivers which already
+support connecting to a remote database, but there are engines which
+don't offer network connectivity.
+
+Another application is offering database access through a firewall, as
+the driver offers query based restrictions. For example you can
+restrict queries to exactly those that are used in a given CGI
+application.
+
+Speaking of CGI, another application is (or rather, will be) to reduce
+the database connect/disconnect overhead from CGI scripts by using
+proxying the connect_cached method. The proxy server will hold the
+database connections open in a cache. The CGI script then trades the
+database connect/disconnect overhead for the DBD::Proxy
+connect/disconnect overhead which is typically much less.
+I<Note that the connect_cached method is new and still experimental.>
+
+
+=head1 CONNECTING TO THE DATABASE
+
+Before connecting to a remote database, you must ensure, that a Proxy
+server is running on the remote machine. There's no default port, so
+you have to ask your system administrator for the port number. See
+L<DBI::ProxyServer> for details.
+
+Say, your Proxy server is running on machine "alpha", port 3334, and
+you'd like to connect to an ODBC database called "mydb" as user "joe"
+with password "hello". When using DBD::ODBC directly, you'd do a
+
+  $dbh = DBI->connect("DBI:ODBC:mydb", "joe", "hello");
+
+With DBD::Proxy this becomes
+
+  $dsn = "DBI:Proxy:hostname=alpha;port=3334;dsn=DBI:ODBC:mydb";
+  $dbh = DBI->connect($dsn, "joe", "hello");
+
+You see, this is mainly the same. The DBD::Proxy module will create a
+connection to the Proxy server on "alpha" which in turn will connect
+to the ODBC database.
+
+Refer to the L<DBI> documentation on the C<connect> method for a way
+to automatically use DBD::Proxy without having to change your code.
+
+DBD::Proxy's DSN string has the format
+
+  $dsn = "DBI:Proxy:key1=val1; ... ;keyN=valN;dsn=valDSN";
+
+In other words, it is a collection of key/value pairs. The following
+keys are recognized:
+
+=over 4
+
+=item hostname
+
+=item port
+
+Hostname and port of the Proxy server; these keys must be present,
+no defaults. Example:
+
+    hostname=alpha;port=3334
+
+=item dsn
+
+The value of this attribute will be used as a dsn name by the Proxy
+server. Thus it must have the format C<DBI:driver:...>, in particular
+it will contain colons. The I<dsn> value may contain semicolons, hence
+this key *must* be the last and it's value will be the complete
+remaining part of the dsn. Example:
+
+    dsn=DBI:ODBC:mydb
+
+=item cipher
+
+=item key
+
+=item usercipher
+
+=item userkey
+
+By using these fields you can enable encryption. If you set,
+for example,
+
+    cipher=$class;key=$key
+
+(note the semicolon) then DBD::Proxy will create a new cipher object
+by executing
+
+    $cipherRef = $class->new(pack("H*", $key));
+
+and pass this object to the RPC::PlClient module when creating a
+client. See L<RPC::PlClient>. Example:
+
+    cipher=IDEA;key=97cd2375efa329aceef2098babdc9721
+
+The usercipher/userkey attributes allow you to use two phase encryption:
+The cipher/key encryption will be used in the login and authorisation
+phase. Once the client is authorised, he will change to usercipher/userkey
+encryption. Thus the cipher/key pair is a B<host> based secret, typically
+less secure than the usercipher/userkey secret and readable by anyone.
+The usercipher/userkey secret is B<your> private secret.
+
+Of course encryption requires an appropriately configured server. See
+<DBD::ProxyServer/CONFIGURATION FILE>.
+
+=item debug
+
+Turn on debugging mode
+
+=item stderr
+
+This attribute will set the corresponding attribute of the RPC::PlClient
+object, thus logging will not use syslog(), but redirected to stderr.
+This is the default under Windows.
+
+    stderr=1
+
+=item logfile
+
+Similar to the stderr attribute, but output will be redirected to the
+given file.
+
+    logfile=/dev/null
+
+=item RowCacheSize
+
+The DBD::Proxy driver supports this attribute (which is DBI standard,
+as of DBI 1.02). It's used to reduce network round-trips by fetching
+multiple rows in one go. The current default value is 20, but this may
+change.
+
+
+=item proxy_no_finish
+
+This attribute can be used to reduce network traffic: If the
+application is calling $sth->finish() then the proxy tells the server
+to finish the remote statement handle. Of course this slows down things
+quite a lot, but is prefectly good for reducing memory usage with
+persistent connections.
+
+However, if you set the I<proxy_no_finish> attribute to a TRUE value,
+either in the database handle or in the statement handle, then finish()
+calls will be supressed. This is what you want, for example, in small
+and fast CGI applications.
+
+=item proxy_quote
+
+This attribute can be used to reduce network traffic: By default calls
+to $dbh->quote() are passed to the remote driver.  Of course this slows
+down things quite a lot, but is the safest default behaviour.
+
+However, if you set the I<proxy_quote> attribute to the value 'C<local>'
+either in the database handle or in the statement handle, and the call
+to quote has only one parameter, then the local default DBI quote
+method will be used (which will be faster but may be wrong).
+
+=back
+
+=head1 KNOWN ISSUES
+
+=head2 Complex handle attributes
+
+Sometimes handles are having complex attributes like hash refs or
+array refs and not simple strings or integers. For example, with
+DBD::CSV, you would like to write something like
+
+  $dbh->{"csv_tables"}->{"passwd"} =
+        { "sep_char" => ":", "eol" => "\n";
+
+The above example would advice the CSV driver to assume the file
+"passwd" to be in the format of the /etc/passwd file: Colons as
+separators and a line feed without carriage return as line
+terminator.
+
+Surprisingly this example doesn't work with the proxy driver. To understand
+the reasons, you should consider the following: The Perl compiler is
+executing the above example in two steps:
+
+=over
+
+=item 1
+
+The first step is fetching the value of the key "csv_tables" in the
+handle $dbh. The value returned is complex, a hash ref.
+
+=item 2
+
+The second step is storing some value (the right hand side of the
+assignment) as the key "passwd" in the hash ref from step 1.
+
+=back
+
+This becomes a little bit clearer, if we rewrite the above code:
+
+  $tables = $dbh->{"csv_tables"};
+  $tables->{"passwd"} = { "sep_char" => ":", "eol" => "\n";
+
+While the examples work fine without the proxy, the fail due to a
+subtile difference in step 1: By DBI magic, the hash ref
+$dbh->{'csv_tables'} is returned from the server to the client.
+The client creates a local copy. This local copy is the result of
+step 1. In other words, step 2 modifies a local copy of the hash ref,
+but not the server's hash ref.
+
+The workaround is storing the modified local copy back to the server:
+
+  $tables = $dbh->{"csv_tables"};
+  $tables->{"passwd"} = { "sep_char" => ":", "eol" => "\n";
+  $dbh->{"csv_tables"} = $tables;
+
+
+=head1 AUTHOR AND COPYRIGHT
+
+This module is Copyright (c) 1997, 1998
+
+    Jochen Wiedmann
+    Am Eisteich 9
+    72555 Metzingen
+    Germany
+
+    Email: joe@ispsoft.de
+    Phone: +49 7123 14887
+
+The DBD::Proxy module is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself. In particular permission
+is granted to Tim Bunce for distributing this as a part of the DBI.
+
+
+=head1 SEE ALSO
+
+L<DBI>, L<RPC::PlClient>, L<Storable>
+
+=cut
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBD/Sponge.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBD/Sponge.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBD/Sponge.pm	(revision 14139)
@@ -0,0 +1,300 @@
+{
+    package DBD::Sponge;
+
+    require DBI;
+    require Carp;
+
+    @EXPORT = qw(); # Do NOT @EXPORT anything.
+    $VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/o);
+
+#   $Id$
+#
+#   Copyright (c) 1994-2003 Tim Bunce Ireland
+#
+#   You may distribute under the terms of either the GNU General Public
+#   License or the Artistic License, as specified in the Perl README file.
+
+    $drh = undef;	# holds driver handle once initialised
+    my $methods_already_installed;
+
+    sub driver{
+	return $drh if $drh;
+
+	DBD::Sponge::db->install_method("sponge_test_installed_method")
+		unless $methods_already_installed++;
+
+	my($class, $attr) = @_;
+	$class .= "::dr";
+	($drh) = DBI::_new_drh($class, {
+	    'Name' => 'Sponge',
+	    'Version' => $VERSION,
+	    'Attribution' => "DBD::Sponge $VERSION (fake cursor driver) by Tim Bunce",
+	    });
+	$drh;
+    }
+
+    sub CLONE {
+        undef $drh;
+    }
+}
+
+
+{   package DBD::Sponge::dr; # ====== DRIVER ======
+    $imp_data_size = 0;
+    # we use default (dummy) connect method
+}
+
+
+{   package DBD::Sponge::db; # ====== DATABASE ======
+    $imp_data_size = 0;
+    use strict;
+
+    sub prepare {
+	my($dbh, $statement, $attribs) = @_;
+	my $rows = delete $attribs->{'rows'}
+	    or return $dbh->set_err(1,"No rows attribute supplied to prepare");
+	my ($outer, $sth) = DBI::_new_sth($dbh, {
+	    'Statement'   => $statement,
+	    'rows'        => $rows,
+	    (map { exists $attribs->{$_} ? ($_=>$attribs->{$_}) : () }
+		qw(execute_hook)
+	    ),
+	});
+	if (my $behave_like = $attribs->{behave_like}) {
+	    $outer->{$_} = $behave_like->{$_}
+		foreach (qw(RaiseError PrintError HandleError ShowErrorStatement));
+	}
+
+	if ($statement =~ /^\s*insert\b/) {	# very basic, just for testing execute_array()
+	    $sth->{is_insert} = 1;
+	    my $NUM_OF_PARAMS = $attribs->{NUM_OF_PARAMS}
+		or return $dbh->set_err(1,"NUM_OF_PARAMS not specified for INSERT statement");
+	    $sth->STORE('NUM_OF_PARAMS' => $attribs->{NUM_OF_PARAMS} );
+	}
+	else {	#assume select
+
+	    # we need to set NUM_OF_FIELDS
+	    my $numFields;
+	    if ($attribs->{'NUM_OF_FIELDS'}) {
+		$numFields = $attribs->{'NUM_OF_FIELDS'};
+	    } elsif ($attribs->{'NAME'}) {
+		$numFields = @{$attribs->{NAME}};
+	    } elsif ($attribs->{'TYPE'}) {
+		$numFields = @{$attribs->{TYPE}};
+	    } elsif (my $firstrow = $rows->[0]) {
+		$numFields = scalar @$firstrow;
+	    } else {
+		return $dbh->set_err(1, 'Cannot determine NUM_OF_FIELDS');
+	    }
+	    $sth->STORE('NUM_OF_FIELDS' => $numFields);
+	    $sth->{NAME} = $attribs->{NAME}
+		    || [ map { "col$_" } 1..$numFields ];
+	    $sth->{TYPE} = $attribs->{TYPE}
+		    || [ (DBI::SQL_VARCHAR()) x $numFields ];
+	    $sth->{PRECISION} = $attribs->{PRECISION}
+		    || [ map { length($sth->{NAME}->[$_]) } 0..$numFields -1 ];
+	    $sth->{SCALE} = $attribs->{SCALE}
+		    || [ (0) x $numFields ];
+	    $sth->{NULLABLE} = $attribs->{NULLABLE}
+		    || [ (2) x $numFields ];
+	}
+
+	$outer;
+    }
+
+    sub type_info_all {
+	my ($dbh) = @_;
+	my $ti = [
+	    {	TYPE_NAME	=> 0,
+		DATA_TYPE	=> 1,
+		PRECISION	=> 2,
+		LITERAL_PREFIX	=> 3,
+		LITERAL_SUFFIX	=> 4,
+		CREATE_PARAMS	=> 5,
+		NULLABLE	=> 6,
+		CASE_SENSITIVE	=> 7,
+		SEARCHABLE	=> 8,
+		UNSIGNED_ATTRIBUTE=> 9,
+		MONEY		=> 10,
+		AUTO_INCREMENT	=> 11,
+		LOCAL_TYPE_NAME	=> 12,
+		MINIMUM_SCALE	=> 13,
+		MAXIMUM_SCALE	=> 14,
+	    },
+	    [ 'VARCHAR', DBI::SQL_VARCHAR(), undef, "'","'", undef, 0, 1, 1, 0, 0,0,undef,0,0 ],
+	];
+	return $ti;
+    }
+
+    sub FETCH {
+        my ($dbh, $attrib) = @_;
+        # In reality this would interrogate the database engine to
+        # either return dynamic values that cannot be precomputed
+        # or fetch and cache attribute values too expensive to prefetch.
+        return 1 if $attrib eq 'AutoCommit';
+        # else pass up to DBI to handle
+        return $dbh->SUPER::FETCH($attrib);
+    }
+
+    sub STORE {
+        my ($dbh, $attrib, $value) = @_;
+        # would normally validate and only store known attributes
+        # else pass up to DBI to handle
+        if ($attrib eq 'AutoCommit') {
+            return 1 if $value; # is already set
+            Carp::croak("Can't disable AutoCommit");
+        }
+        return $dbh->SUPER::STORE($attrib, $value);
+    }
+
+    sub sponge_test_installed_method {
+	my ($dbh, @args) = @_;
+	return $dbh->set_err(42, "not enough parameters") unless @args >= 2;
+	return \@args;
+    }
+}
+
+
+{   package DBD::Sponge::st; # ====== STATEMENT ======
+    $imp_data_size = 0;
+    use strict;
+
+    sub execute {
+	my $sth = shift;
+	if (my $hook = $sth->{execute_hook}) {
+	    &$hook($sth, @_) or return;
+	}
+
+	if ($sth->{is_insert}) {
+	    my $row;
+	    $row = (@_) ? [ @_ ] : die "bind_param not supported yet" ;
+	    my $NUM_OF_PARAMS = $sth->{NUM_OF_PARAMS};
+	    return $sth->set_err(1, @$row." values bound (@$row) but $NUM_OF_PARAMS expected")
+		if @$row != $NUM_OF_PARAMS;
+	    { local $^W; $sth->trace_msg("inserting (@$row)\n"); }
+	    push @{ $sth->{rows} }, $row;
+	}
+	else {	# mark select sth as Active
+	    $sth->STORE(Active => 1);
+	}
+	# else do nothing for select as data is already in $sth->{rows}
+	return 1;
+    }
+
+    sub fetch {
+	my ($sth) = @_;
+	my $row = shift @{$sth->{'rows'}};
+	unless ($row) {
+	    $sth->STORE(Active => 0);
+	    return undef;
+	}
+	return $sth->_set_fbav($row);
+    }
+    *fetchrow_arrayref = \&fetch;
+
+    sub FETCH {
+	my ($sth, $attrib) = @_;
+	# would normally validate and only fetch known attributes
+	# else pass up to DBI to handle
+	return $sth->SUPER::FETCH($attrib);
+    }
+
+    sub STORE {
+	my ($sth, $attrib, $value) = @_;
+	# would normally validate and only store known attributes
+	# else pass up to DBI to handle
+	return $sth->SUPER::STORE($attrib, $value);
+    }
+}
+
+1;
+
+__END__ 
+
+=pod
+
+=head1 NAME
+
+DBD::Sponge - Create a DBI statement handle from Perl data
+
+=head1 SYNOPSIS
+
+  my $sponge = DBI->connect("dbi:Sponge:","","",{ RaiseError => 1 });
+  my $sth = $sponge->prepare($statement, {
+          rows => $data,
+          NAME => $names,
+          %attr
+      }
+  );
+
+=head1 DESCRIPTION
+
+DBD::Sponge is useful for making a Perl data structure accessible through a
+standard DBI statement handle. This may be useful to DBD module authors who
+need to transform data in this way.
+
+=head1 METHODS
+
+=head2 connect()
+
+  my $sponge = DBI->connect("dbi:Sponge:","","",{ RaiseError => 1 });
+
+Here's a sample syntax for creating a database handle for the Sponge driver.
+No username and password are needed.
+
+=head2 prepare()
+
+  my $sth = $sponge->prepare($statement, {
+          rows => $data,
+          NAME => $names,
+          %attr
+      }
+  );
+
+=over 4
+
+=item *
+
+The C<$statement> here is an arbitrary statement or name you want
+to provide as identity of your data. If you're using DBI::Profile
+it will appear in the profile data.
+
+Generally it's expected that you are preparing a statement handle
+as if a C<select> statement happened.
+
+=item *
+
+C<$data> is a reference to the data you are providing, given as an array of arrays.
+
+=item *
+
+C<$names> is a reference an array of column names for the C<$data> you are providing.
+The number and order should match the number and ordering of the C<$data> columns. 
+
+=item *
+
+C<%attr> is a hash of other standard DBI attributes that you might pass to a prepare statement.
+
+Currently only NAME, TYPE, and PRECISION are supported.
+
+=back
+
+=head1 BUGS
+
+Using this module to prepare INSERT-like statements is not currently documented.
+
+=head1 AUTHOR AND COPYRIGHT
+
+This module is Copyright (c) 2003 Tim Bunce
+
+Documentation initially written by Mark Stosberg
+
+The DBD::Sponge module is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself. In particular permission
+is granted to Tim Bunce for distributing this as a part of the DBI.
+
+=head1 SEE ALSO
+
+L<DBI>
+
+=cut
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/Changes.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/Changes.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/Changes.pm	(revision 14139)
@@ -0,0 +1,1571 @@
+=head1 NAME
+
+DBI::Changes - List of significant changes to the DBI
+
+=cut
+
+=head2 Changes in DBI 1.48 (svn rev 928),    14th March 2005
+
+  Fixed DBI::DBD::Metadata generation of type_info_all thanks to Steffen Goeldner
+    (driver authors who have used it should rerun it).
+
+  Updated docs for NULL Value placeholders thanks to Brian Campbell.
+  
+  Added multi-keyfield nested hash fetching to fetchall_hashref()
+    thanks to Zhuang (John) Li for polishing up my draft.
+  Added registered driver prefixes: amzn_ for DBD::Amazon and yaswi_ for DBD::Yaswi.
+
+
+=head2 Changes in DBI 1.47 (svn rev 854),    2nd February 2005
+
+  Fixed DBI::ProxyServer to not create pid files by default.
+    References: Ubuntu Security Notice USN-70-1, CAN-2005-0077
+    Thanks to Javier Fernández-Sanguino Peña from the
+    Debian Security Audit Project, and Jonathan Leffler.
+  Fixed some tests to work with older Test::More versions.
+  Fixed setting $DBI::err/errstr in DBI::PurePerl.
+  Fixed potential undef warning from connect_cached().
+  Fixed $DBI::lasth handling for DESTROY so lasth points to
+    parent even if DESTROY called other methods.
+  Fixed DBD::Proxy method calls to not alter $@.
+  Fixed DBD::File problem with encoding pragma thanks to Erik Rijkers.
+
+  Changed error handling so undef errstr doesn't cause warning.
+  Changed DBI::DBD docs to use =head3/=head4 pod thanks to
+    Jonathan Leffler. This may generate warnings for perl 5.6.
+  Changed DBI::PurePerl to set autoflush on trace filehandle.
+  Changed DBD::Proxy to treat Username as a local attribute
+    so recent DBI version can be used with old DBI::ProxyServer.
+  Changed driver handle caching in DBD::File.
+  Added $GetInfoType{SQL_DATABASE_NAME} thanks to Steffen Goeldner.
+
+  Updated docs to recommend some common DSN string attributes.
+  Updated connect_cached() docs with issues and suggestions.
+  Updated docs for NULL Value placeholders thanks to Brian Campbell.
+  Updated docs for primary_key_info and primary_keys.
+  Updated docs to clarify that the default fetchrow_hashref behaviour,
+    of returning a ref to a new hash for each row, will not change.
+  Updated err/errstr/state docs for DBD authors thanks to Steffen Goeldner.
+  Updated handle/attribute docs for DBD authors thanks to Steffen Goeldner.
+  Corrected and updated LongReadLen docs thanks to Bart Lateur.
+  Added DBD::JDBC as a registered driver.
+
+=head2 Changes in DBI 1.46 (svn rev 584),    16th November 2004
+
+  Fixed parsing bugs in DBI::SQL::Nano thanks to Jeff Zucker.
+  Fixed a couple of bad links in docs thanks to Graham Barr.
+  Fixed test.pl Win32 undef warning thanks to H.Merijn Brand & David Repko.
+  Fixed minor issues in DBI::DBD::Metadata thanks to Steffen Goeldner.
+  Fixed DBI::PurePerl neat() to use double quotes for utf8.
+
+  Changed execute_array() definition, and default implementation,
+    to not consider scalar values for execute tuple count. See docs.
+  Changed DBD::File to enable ShowErrorStatement by default,
+    which affects DBD::File subclasses such as DBD::CSV and DBD::DBM.
+  Changed use DBI qw(:utils) tag to include $neat_maxlen.
+  Updated Roadmap and ToDo.
+
+  Added data_string_diff() data_string_desc() and data_diff()
+    utility functions to help diagnose Unicode issues.
+    All can be imported via the use DBI qw(:utils) tag.
+
+=head2 Changes in DBI 1.45 (svn rev 480),    6th October 2004
+
+  Fixed DBI::DBD code for drivers broken in 1.44.
+  Fixed "Free to wrong pool"/"Attempt to free unreferenced scalar" in FETCH.
+
+=head2 Changes in DBI 1.44 (svn rev 478),    5th October 2004
+
+  Fixed build issues on VMS thanks to Jakob Snoer.
+  Fixed DBD::File finish() method to return 1 thanks to Jan Dubois.
+  Fixed rare core dump during global destruction thanks to Mark Jason Dominus.
+  Fixed risk of utf8 flag persisting from one row to the next.
+
+  Changed bind_param_array() so it doesn't require all bind arrays
+    to have the same number of elements.
+  Changed bind_param_array() to error if placeholder number <= 0.
+  Changed execute_array() definition, and default implementation,
+    to effectively NULL-pad shorter bind arrays.
+  Changed execute_array() to return "0E0" for 0 as per the docs.
+  Changed execute_for_fetch() definition, and default implementation,
+    to return "0E0" for 0 like execute() and execute_array().
+  Changed Test::More prerequisite to Test::Simple (which is also the name
+    of the distribution both are packaged in) to work around ppm behaviour.
+
+  Corrected docs to say that get/set of unknown attribute generates
+    a warning and is no longer fatal. Thanks to Vadim.
+  Corrected fetchall_arrayref() docs example thanks to Drew Broadley.
+
+  Added $h1->swap_inner_handle($h2) sponsored by BizRate.com
+
+
+=head2 Changes in DBI 1.43 (svn rev 377),    2nd July 2004
+
+  Fixed connect() and connect_cached() RaiseError/PrintError
+    which would sometimes show "(no error string)" as the error.
+  Fixed compiler warning thanks to Paul Marquess.
+  Fixed "trace level set to" trace message thanks to H.Merijn Brand.
+  Fixed DBD::DBM $dbh->{dbm_tables}->{...} to be keyed by the
+    table name not the file name thanks to Jeff Zucker.
+  Fixed last_insert_id(...) thanks to Rudy Lippan.
+  Fixed propagation of scalar/list context into proxied methods.
+  Fixed DBI::Profile::DESTROY to not alter $@.
+  Fixed DBI::ProfileDumper new() docs thanks to Michael Schwern.
+  Fixed _load_class to propagate $@ thanks to Drew Taylor.
+  Fixed compile warnings on Win32 thanks to Robert Baron.
+  Fixed problem building with recent versions of MakeMaker.
+  Fixed DBD::Sponge not to generate warning with threads.
+  Fixed DBI_AUTOPROXY to work more than once thanks to Steven Hirsch.
+
+  Changed TraceLevel 1 to not show recursive/nested calls.
+  Changed getting or setting an invalid attribute to no longer be
+    a fatal error but generate a warning instead.
+  Changed selectall_arrayref() to call finish() if
+    $attr->{MaxRows} is defined.
+  Changed all tests to use Test::More and enhanced the tests thanks
+    to Stevan Little and Andy Lester. See http://qa.perl.org/phalanx/
+  Changed Test::More minimum prerequisite version to 0.40 (2001).
+  Changed DBI::Profile header to include the date and time.
+
+  Added DBI->parse_dsn($dsn) method.
+  Added warning if build directory path contains whitespace.
+  Added docs for parse_trace_flags() and parse_trace_flag().
+  Removed "may change" warnings from the docs for table_info(),
+    primary_key_info(), and foreign_key_info() methods.
+
+=head2 Changes in DBI 1.42 (svn rev 222),    12th March 2004
+
+  Fixed $sth->{NUM_OF_FIELDS} of non-executed statement handle
+    to be undef as per the docs (it was 0).
+  Fixed t/41prof_dump.t to work with perl5.9.1.
+  Fixed DBD_ATTRIB_DELETE macro thanks to Marco Paskamp.
+  Fixed DBI::PurePerl looks_like_number() and $DBI::rows.
+  Fixed ref($h)->can("foo") to not croak.
+
+  Changed attributes (NAME, TYPE etc) of non-executed statement
+    handle to be undef instead of triggering an error.
+  Changed ShowErrorStatement to apply to more $dbh methods.
+  Changed DBI_TRACE env var so just does this at load time:
+    DBI->trace(split '=', $ENV{DBI_TRACE}, 2);
+  Improved "invalid number of parameters" error message.
+  Added DBI::common as base class for DBI::db, DBD::st etc.
+  Moved methods common to all handles into DBI::common.
+
+  Major tracing enhancement:
+
+  Added $h->parse_trace_flags("foo|SQL|7") to map a group of
+    trace flags into the corresponding trace flag bits.
+  Added automatic calling of parse_trace_flags() if
+    setting the trace level to a non-numeric value:
+    $h->{TraceLevel}="foo|SQL|7"; $h->trace("foo|SQL|7");
+    DBI->connect("dbi:Driver(TraceLevel=SQL|foo):...", ...);
+    Currently no trace flags have been defined.
+  Added to, and reworked, the trace documentation.
+  Added dbivport.h for driver authors to use.
+
+  Major driver additions that Jeff Zucker and I have been working on:
+
+  Added DBI::SQL::Nano a 'smaller than micro' SQL parser
+    with an SQL::Statement compatible API. If SQL::Statement
+    is installed then DBI::SQL::Nano becomes an empty subclass
+    of SQL::Statement, unless the DBI_SQL_NANO env var is true.
+  Added DBD::File, modified to use DBI::SQL::Nano.
+  Added DBD::DBM, an SQL interface to DBM files using DBD::File.
+
+  Documentation changes:
+
+  Corrected typos in docs thanks to Steffen Goeldner.
+  Corrected execute_for_fetch example thanks to Dean Arnold.
+
+=head2 Changes in DBI 1.41 (svn rev 130),    22nd February 2004
+
+  Fixed execute_for_array() so tuple_status parameter is optional
+    as per docs, thanks to Ed Avis.
+  Fixed execute_for_array() docs to say that it returns undef if
+    any of the execute() calls fail.
+  Fixed take_imp_data() test on m68k reported by Christian Hammers.
+  Fixed write_typeinfo_pm inconsistencies in DBI::DBD::Metadata
+    thanks to Andy Hassall.
+  Fixed $h->{TraceLevel} to not return DBI->trace trace level
+    which it used to if DBI->trace trace level was higher.
+
+  Changed set_err() to append to errstr, with a leading "\n" if it's
+    not empty, so that multiple error/warning messages are recorded.
+  Changed trace to limit elements dumped when an array reference is
+    returned from a method to the max(40, $DBI::neat_maxlen/10)
+    so that fetchall_arrayref(), for example, doesn't flood the trace.
+  Changed trace level to be a four bit integer (levels 0 thru 15)
+    and a set of topic flags (no topics have been assigned yet).
+  Changed column_info() to check argument count.
+  Extended bind_param() TYPE attribute specification to imply
+    standard formating of value, eg SQL_DATE implies 'YYYY-MM-DD'.
+
+  Added way for drivers to indicate 'success with info' or 'warning'
+    by setting err to "0" for warning and "" for information.
+    Both values are false and so don't trigger RaiseError etc.
+    Thanks to Steffen Goeldner for the original idea.
+  Added $h->{HandleSetErr} = sub { ... } to be called at the
+    point that an error, warn, or info state is recorded.
+    The code can alter the err, errstr, and state values
+    (e.g., to promote an error to a warning, or the reverse).
+  Added $h->{PrintWarn} attribute to enable printing of warnings
+    recorded by the driver. Defaults to same value as $^W (perl -w).
+  Added $h->{ErrCount} attribute, incremented whenever an error is
+    recorded by the driver via set_err().
+  Added $h->{Executed} attribute, set if do()/execute() called.
+  Added \%attr parameter to foreign_key_info() method.
+  Added ref count of inner handle to "DESTROY ignored for outer" msg.
+  Added Win32 build config checks to DBI::DBD thanks to Andy Hassall.
+  Added bind_col to Driver.xst so drivers can define their own.
+  Added TYPE attribute to bind_col and specified the expected
+    driver behaviour.
+
+  Major update to signal handling docs thanks to Lincoln Baxter.
+  Corrected dbiproxy usage doc thanks to Christian Hammers.
+  Corrected type_info_all index hash docs thanks to Steffen Goeldner.
+  Corrected type_info COLUMN_SIZE to chars not bytes thanks to Dean Arnold.
+  Corrected get_info() docs to include details of DBI::Const::GetInfoType.
+  Clarified that $sth->{PRECISION} is OCTET_LENGTH for char types.
+
+=head2 Changes in DBI 1.40,    7th January 2004
+
+  Fixed handling of CachedKids when DESTROYing threaded handles.
+  Fixed sql_user_name() in DBI::DBD::Metadata (used by write_getinfo_pm)
+    to use $dbh->{Username}. Driver authors please update your code.
+
+  Changed connect_cached() when running under Apache::DBI
+    to route calls to Apache::DBI::connect().
+
+  Added CLONE() to DBD::Sponge and DBD::ExampleP.
+  Added warning when starting a new thread about any loaded driver
+    which does not have a CLONE() function.
+  Added new prepare_cache($sql, \%attr, 3) option to manage Active handles.
+  Added SCALE and NULLABLE support to DBD::Sponge.
+  Added missing execute() in fetchall_hashref docs thanks to Iain Truskett.
+  Added a CONTRIBUTING section to the docs with notes on creating patches.
+
+=head2 Changes in DBI 1.39,    27th November 2003
+
+  Fixed STORE to not clear error during nested DBI call, again/better,
+    thanks to Tony Bowden for the report and helpful test case.
+  Fixed DBI dispatch to not try to use AUTOLOAD for driver methods unless
+    the method has been declared (as methods should be when using AUTOLOAD).
+    This fixes a problem when the Attribute::Handlers module is loaded.
+  Fixed cwd check code to use $Config{path_sep} thanks to Steve Hay.
+  Fixed unqualified croak() calls thanks to Steffen Goeldner.
+  Fixed DBD::ExampleP TYPE and PRECISION attributes thanks to Tom Lowery.
+  Fixed tracing of methods that only get traced at high trace levels.
+
+  The level 1 trace no longer includes nested method calls so it generally
+    just shows the methods the application explicitly calls.
+  Added line to trace log (level>=4) when err/errstr is cleared.
+  Updated docs for InactiveDestroy and point out where and when the
+    trace includes the process id.
+  Update DBI::DBD docs thanks to Steffen Goeldner.
+  Removed docs saying that the DBI->data_sources method could be
+    passed a $dbh. The $dbh->data_sources method should be used instead.
+  Added link to 'DBI recipes' thanks to Giuseppe Maxia:
+    http://gmax.oltrelinux.com/dbirecipes.html (note that this
+    is not an endorsement that the recipies are 'optimal')
+
+  Note: There is a bug in perl 5.8.2 when configured with threads
+  and debugging enabled (bug #24463) which causes a DBI test to fail.
+
+=head2 Changes in DBI 1.38,    21th August 2003
+
+  NOTE: The DBI now requires perl version 5.6.0 or later.
+  (As per notice in DBI 1.33 released 27th February 2003)
+
+  Fixed spurious t/03handles failure on 64bit perls reported by H.Merijn Brand.
+  Fixed spurious t/15array failure on some perl versions thanks to Ed Avis.
+  Fixed build using dmake on windows thanks to Steffen Goeldner.
+  Fixed build on using some shells thanks to Gurusamy Sarathy.
+  Fixed ParamValues to only be appended to ShowErrorStatement if not empty.
+  Fixed $dbh->{Statement} not being writable by drivers in some cases.
+  Fixed occasional undef warnings on connect failures thanks to Ed Avis.
+  Fixed small memory leak when using $sth->{NAME..._hash}.
+  Fixed 64bit warnings thanks to Marian Jancar.
+  Fixed DBD::Proxy::db::DESTROY to not alter $@ thanks to Keith Chapman.
+  Fixed Makefile.PL status from WriteMakefile() thanks to Leon Brocard.
+
+  Changed "Can't set ...->{Foo}: unrecognised attribute" from an error to a
+    warning when running with DBI::ProxyServer to simplify upgrades.
+  Changed execute_array() to no longer require ArrayTupleStatus attribute.
+  Changed DBI->available_drivers to not hide DBD::Sponge.
+  Updated/moved placeholder docs to a better place thanks to Johan Vromans.
+  Changed dbd_db_do4 api in Driver.xst to match dbd_st_execute (return int,
+    not bool), relevant only to driver authors.
+  Changed neat(), and thus trace(), so strings marked as utf8 are presented
+    in double quotes instead of single quotes and are not sanitized.
+
+  Added $dbh->data_sources method.
+  Added $dbh->last_insert_id method.
+  Added $sth->execute_for_fetch($fetch_tuple_sub, \@tuple_status) method.
+  Added DBI->installed_versions thanks to Jeff Zucker.
+  Added $DBI::Profile::ON_DESTROY_DUMP variable.
+  Added docs for DBD::Sponge thanks to Mark Stosberg.
+
+=head2 Changes in DBI 1.37,    15th May 2003
+
+  Fixed "Can't get dbh->{Statement}: unrecognised attribute" error in test
+    caused by change to perl internals in 5.8.0
+  Fixed to build with latest development perl (5.8.1@19525).
+  Fixed C code to use all ANSI declarations thanks to Steven Lembark.
+
+=head2 Changes in DBI 1.36,    11th May 2003
+
+  Fixed DBI->connect to carp instead of croak on 'old-style' usage.
+  Fixed connect(,,, { RootClass => $foo }) to not croak if module not found.
+  Fixed code generated by DBI::DBD::Metadata thanks to DARREN@cpan.org (#2270)
+  Fixed DBI::PurePerl to not reset $@ during method dispatch.
+  Fixed VMS build thanks to Michael Schwern.
+  Fixed Proxy disconnect thanks to Steven Hirsch.
+  Fixed error in DBI::DBD docs thanks to Andy Hassall.
+
+  Changed t/40profile.t to not require Time::HiRes.
+  Changed DBI::ProxyServer to load DBI only on first request, which
+    helps threaded server mode, thanks to Bob Showalter.
+  Changed execute_array() return value from row count to executed
+    tuple count, and now the ArrayTupleStatus attribute is mandatory.
+    NOTE: That is an API definition change that may affect your code.
+  Changed CompatMode attribute to also disable attribute 'quick FETCH'.
+  Changed attribute FETCH to be slightly faster thanks to Stas Bekman.
+
+  Added workaround for perl bug #17575 tied hash nested FETCH
+    thanks to Silvio Wanka.
+  Added Username and Password attributes to connect(..., \%attr) and so
+    also embedded in DSN like "dbi:Driver(Username=user,Password=pass):..."
+    Username and Password can't contain ")", ",", or "=" characters.
+    The predence is DSN first, then \%attr, then $user & $pass parameters,
+    and finally the DBI_USER & DBI_PASS environment variables.
+    The Username attribute is stored in the $dbh but the Password is not.
+  Added ProxyServer HOWTO configure restrictions docs thanks to Jochen Wiedmann.
+  Added MaxRows attribute to selectcol_arrayref prompted by Wojciech Pietron.
+  Added dump_handle as a method not just a DBI:: utility function.
+  Added on-demand by-row data feed into execute_array() using code ref,
+    or statement handle. For example, to insert from a select:
+    $insert_sth->execute_array( { ArrayTupleFetch => $select_sth, ... } )
+  Added warning to trace log when $h->{foo}=... is ignored due to
+    invalid prefix (e.g., not 'private_').
+
+=head2 Changes in DBI 1.35,    7th March 2003
+
+  Fixed memory leak in fetchrow_hashref introduced in DBI 1.33.
+  Fixed various DBD::Proxy errors introduced in DBI 1.33.
+  Fixed to ANSI C in dbd_dr_data_sources thanks to Jonathan Leffler.
+  Fixed $h->can($method_name) to return correct code ref.
+  Removed DBI::Format from distribution as it's now part of the
+    separate DBI::Shell distribution by Tom Lowery.
+  Updated DBI::DBD docs with a note about the CLONE method.
+  Updated DBI::DBD docs thanks to Jonathan Leffler.
+  Updated DBI::DBD::Metadata for perl 5.5.3 thanks to Jonathan Leffler.
+  Added note to install_method docs about setup_driver() method.
+
+=head2 Changes in DBI 1.34,    28th February 2003
+
+  Fixed DBI::DBD docs to refer to DBI::DBD::Metadata thanks to Jonathan Leffler.
+  Fixed dbi_time() compile using BorlandC on Windows thanks to Steffen Goeldner.
+  Fixed profile tests to do enough work to measure on Windows.
+  Fixed disconnect_all() to not be required by drivers.
+
+  Added $okay = $h->can($method_name) to check if a method exists.
+  Added DBD::*::*->install_method($method_name, \%attr) so driver private
+    methods can be 'installed' into the DBI dispatcher and no longer
+    need to be called using $h->func(..., $method_name).
+
+  Enhanced $dbh->clone() and documentation.
+  Enhanced docs to note that dbi_time(), and thus profiling, is limited
+    to only millisecond (seconds/1000) resolution on Windows.
+  Removed old DBI::Shell from distribution and added Tom Lowery's improved
+    version to the Bundle::DBI file.
+  Updated minimum version numbers for modules in Bundle::DBI.
+
+=head2 Changes in DBI 1.33,    27th February 2003
+
+  NOTE: Future versions of the DBI *will not* support perl 5.6.0 or earlier.
+  : Perl 5.6.1 will be the minimum supported version.
+
+  NOTE: The "old-style" connect: DBI->connect($database, $user, $pass, $driver);
+  : has been deprecated for several years and will now generate a warning.
+  : It will be removed in a later release. Please change any old connect() calls.
+
+  Added $dbh2 = $dbh1->clone to make a new connection to the database
+    that is identical to the original one. clone() can be called even after
+    the original handle has been disconnected. See the docs for more details.
+
+  Fixed merging of profile data to not sum DBIprof_FIRST_TIME values.
+  Fixed unescaping of newlines in DBI::ProfileData thanks to Sam Tregar.
+  Fixed Taint bug with fetchrow_hashref with help from Bradley Baetz.
+  Fixed $dbh->{Active} for DBD::Proxy, reported by Bob Showalter.
+  Fixed STORE to not clear error during nested DBI call,
+    thanks to Tony Bowden for the report and helpful test case.
+  Fixed DBI::PurePerl error clearing behaviour.
+  Fixed dbi_time() and thus DBI::Profile on Windows thanks to Smejkal Petr.
+  Fixed problem that meant ShowErrorStatement could show wrong statement,
+   thanks to Ron Savage for the report and test case.
+  Changed Apache::DBI hook to check for $ENV{MOD_PERL} instead of
+    $ENV{GATEWAY_INTERFACE} thanks to Ask Bjoern Hansen.
+  No longer tries to dup trace logfp when an interpreter is being cloned.
+  Database handles no longer inherit shared $h->err/errstr/state storage
+    from their drivers, so each $dbh has it's own $h->err etc. values
+    and is no longer affected by calls made on other dbh's.
+    Now when a dbh is destroyed it's err/errstr/state values are copied
+    up to the driver so checking $DBI::errstr still works as expected.
+
+  Build / portability fixes:
+    Fixed t/40profile.t to not use Time::HiRes.
+    Fixed t/06attrs.t to not be locale sensitive, reported by Christian Hammers.
+    Fixed sgi compiler warnings, reported by Paul Blake.
+    Fixed build using make -j4, reported by Jonathan Leffler.
+    Fixed build and tests under VMS thanks to Craig A. Berry.
+
+  Documentation changes:
+    Documented $high_resolution_time = dbi_time() function.
+    Documented that bind_col() can take an atribute hash.
+    Clarified documentation for ParamValues attribute hash keys.
+    Many good DBI documentation tweaks from Jonathan Leffler,
+      including a major update to the DBI::DBD driver author guide.
+    Clarified that execute() should itself call finish() if it's
+      called on a statement handle that's still active.
+    Clarified $sth->{ParamValues}. Driver authors please note.
+    Removed "NEW" markers on some methods and attributes and
+      added text to each giving the DBI version it was added in,
+      if it was added after DBI 1.21 (Feb 2002).
+
+  Changes of note for authors of all drivers:
+    Added SQL_DATA_TYPE, SQL_DATETIME_SUB, NUM_PREC_RADIX, and
+      INTERVAL_PRECISION fields to docs for type_info_all. There were
+      already in type_info(), but type_info_all() didn't specify the
+      index values.  Please check and update your type_info_all() code.
+    Added DBI::DBD::Metadata module that auto-generates your drivers
+      get_info and type_info_all data and code, thanks mainly to
+      Jonathan Leffler and Steffen Goeldner. If you've not implemented
+      get_info and type_info_all methods and your database has an ODBC
+      driver available then this will do all the hard work for you!
+    Drivers should no longer pass Err, Errstr, or State to _new_drh
+      or _new_dbh functions.
+    Please check that you support the slightly modified behaviour of
+      $sth->{ParamValues}, e.g., always return hash with keys if possible.
+
+  Changes of note for authors of compiled drivers:
+    Added dbd_db_login6 & dbd_st_finish3 prototypes thanks to Jonathan Leffler.
+    All dbd_*_*() functions implemented by drivers must have a
+      corresponding #define dbd_*_* <driver_prefix>_*_* otherwise
+      the driver may not work with a future release of the DBI.
+
+  Changes of note for authors of drivers which use Driver.xst:
+    Some new method hooks have been added are are enabled by
+      defining corresponding macros:
+          $drh->data_sources()      - dbd_dr_data_sources
+          $dbh->do()                - dbd_db_do4
+    The following methods won't be compiled into the driver unless
+      the corresponding macro has been #defined:
+          $drh->disconnect_all()    - dbd_discon_all
+
+
+=head2 Changes in DBI 1.32,    1st December 2002
+
+  Fixed to work with 5.005_03 thanks to Tatsuhiko Miyagawa (I've not tested it).
+  Reenabled taint tests (accidentally left disabled) spotted by Bradley Baetz.
+  Improved docs for FetchHashKeyName attribute thanks to Ian Barwick.
+  Fixed core dump if fetchrow_hashref given bad argument (name of attribute
+    with a value that wasn't an array reference), spotted by Ian Barwick.
+  Fixed some compiler warnings thanks to David Wheeler.
+  Updated Steven Hirsch's enhanced proxy work (seems I left out a bit).
+  Made t/40profile.t tests more reliable, reported by Randy, who is part of
+    the excellent CPAN testers team: http://testers.cpan.org/
+    (Please visit, see the valuable work they do and, ideally, join in!)
+
+=head2 Changes in DBI 1.31,    29th November 2002
+
+  The fetchall_arrayref method, when called with a $maxrows parameter,
+    no longer gives an error if called again after all rows have been
+    fetched. This simplifies application logic when fetching in batches.
+    Also added batch-fetch while() loop example to the docs.
+  The proxy now supports non-lazy (synchronous) prepare, positioned
+    updates (for selects containing 'for update'), PlRPC config set
+    via attributes, and accurate propagation of errors, all thanks
+    to Steven Hirsch (plus a minor fix from Sean McMurray and doc
+    tweaks from Michael A Chase).
+  The DBI_AUTOPROXY env var can now hold the full dsn of the proxy driver
+    plus attributes, like "dbi:Proxy(proxy_foo=>1):host=...".
+  Added TaintIn & TaintOut attributes to give finer control over
+    tainting thanks to Bradley Baetz.
+  The RootClass attribute no longer ignores failure to load a module,
+    but also doesn't try to load a module if the class already exists,
+    with thanks to James FitzGibbon.
+  HandleError attribute works for connect failures thanks to David Wheeler.
+  The connect() RaiseError/PrintError message now includes the username.
+  Changed "last handle unknown or destroyed" warning to be a trace message.
+  Removed undocumented $h->event() method.
+  Further enhancements to DBD::PurePerl accuracy.
+  The CursorName attribute now defaults to undef and not an error.
+
+  DBI::Profile changes:
+    New DBI::ProfileDumper, DBI::ProfileDumper::Apache, and
+    DBI::ProfileData modules (to manage the storage and processing
+    of profile data), plus dbiprof program for analyzing profile
+    data - with many thanks to Sam Tregar.
+    Added $DBI::err (etc) tied variable lookup time to profile.
+    Added time for DESTROY method into parent handles profile (used to be ignored).
+
+  Documentation changes:
+    Documented $dbh = $sth->{Database} attribute.
+    Documented $dbh->connected(...) post-connection call when subclassing.
+    Updated some minor doc issues thanks to H.Merijn Brand.
+    Updated Makefile.PL example in DBI::DBD thanks to KAWAI,Takanori.
+    Fixed execute_array() example thanks to Peter van Hardenberg.
+
+  Changes for driver authors, not required but strongly recommended:
+    Change DBIS to DBIc_DBISTATE(imp_xxh)   [or imp_dbh, imp_sth etc]
+    Change DBILOGFP to DBIc_LOGPIO(imp_xxh) [or imp_dbh, imp_sth etc]
+    Any function from which all instances of DBIS and DBILOGFP are
+    removed can also have dPERLINTERP removed (a good thing).
+    All use of the DBIh_EVENT* macros should be removed.
+    Major update to DBI::DBD docs thanks largely to Jonathan Leffler.
+    Add these key values: 'Err' => \my $err, 'Errstr' => \my $errstr,
+    to the hash passed to DBI::_new_dbh() in your driver source code.
+    That will make each $dbh have it's own $h->err and $h->errstr
+    values separate from other $dbh belonging to the same driver.
+    If you have a ::db or ::st DESTROY methods that do nothing
+    you can now remove them - which speeds up handle destruction.
+
+
+=head2 Changes in DBI 1.30,    18th July 2002
+
+  Fixed problems with selectrow_array, selectrow_arrayref, and
+    selectall_arrayref introduced in DBI 1.29.
+  Fixed FETCHing a handle attribute to not clear $DBI::err etc (broken in 1.29).
+  Fixed core dump at trace level 9 or above.
+  Fixed compilation with perl 5.6.1 + ithreads (i.e. Windows).
+  Changed definition of behaviour of selectrow_array when called in a scalar
+    context to match fetchrow_array.
+  Corrected selectrow_arrayref docs which showed selectrow_array thanks to Paul DuBois.
+
+=head2 Changes in DBI 1.29,    15th July 2002
+
+  NOTE: This release changes the specified behaviour for the
+  : fetchrow_array method when called in a scalar context:
+  : The DBI spec used to say that it would return the FIRST field.
+  : Which field it returns (i.e., the first or the last) is now undefined.
+  : This does not affect statements that only select one column, which is
+  : usually the case when fetchrow_array is called in a scalar context.
+  : FYI, this change was triggered by discovering that the fetchrow_array
+  : implementation in Driver.xst (used by most compiled drivers) 
+  : didn't match the DBI specification. Rather than change the code
+  : to match, and risk breaking existing applications, I've changed the
+  : specification (that part was always of dubious value anyway).
+
+  NOTE: Future versions of the DBI may not support for perl 5.5 much longer.
+  : If you are still using perl 5.005_03 you should be making plans to
+  : upgrade to at least perl 5.6.1, or 5.8.0. Perl 5.8.0 is due to be
+  : released in the next week or so.  (Although it's a "point 0" release,
+  : it is the most throughly tested release ever.)
+
+  Added XS/C implementations of selectrow_array, selectrow_arrayref, and
+    selectall_arrayref to Driver.xst. See DBI 1.26 Changes for more info.
+  Removed support for the old (fatally flawed) "5005" threading model.
+  Added support for new perl 5.8 iThreads thanks to Gerald Richter.
+    (Threading support and safety should still be regarded as beta
+    quality until further notice. But it's much better than it was.)
+  Updated the "Threads and Thread Safety" section of the docs.
+  The trace output can be sent to STDOUT instead of STDERR by using
+    "STDOUT" as the name of the file, i.e., $h->trace(..., "STDOUT")
+  Added pointer to perlreftut, perldsc, perllol, and perlboot manuals
+    into the intro section of the docs, suggested by Brian McCain.
+  Fixed DBI::Const::GetInfo::* pod docs thanks to Zack Weinberg.
+  Some changes to how $dbh method calls are treated by DBI::Profile:
+    Meta-data methods now clear $dbh->{Statement} on entry.
+    Some $dbh methods are now profiled as if $dbh->{Statement} was empty
+    (because thet're unlikely to actually relate to its contents).
+  Updated dbiport.h to ppport.h from perl 5.8.0.
+  Tested with perl 5.5.3 (vanilla, Solaris), 5.6.1 (vanilla, Solaris), and
+    perl 5.8.0 (RC3@17527 with iThreads & Multiplicity on Solaris and FreeBSD).
+
+=head2 Changes in DBI 1.28,    14th June 2002
+
+  Added $sth->{ParamValues} to return a hash of the most recent
+    values bound to placeholders via bind_param() or execute().
+    Individual drivers need to be updated to support it.
+  Enhanced ShowErrorStatement to include ParamValues if available:
+    "DBD::foo::st execute failed: errstr [for statement ``...'' with params: 1='foo']"
+  Further enhancements to DBD::PurePerl accuracy.
+
+=head2 Changes in DBI 1.27,    13th June 2002
+
+  Fixed missing column in C implementation of fetchall_arrayref()
+    thanks to Philip Molter for the prompt reporting of the problem.
+
+=head2 Changes in DBI 1.26,    13th June 2002
+
+  Fixed t/40profile.t to work on Windows thanks to Smejkal Petr.
+  Fixed $h->{Profile} to return undef, not error, if not set.
+  Fixed DBI->available_drivers in scalar context thanks to Michael Schwern.
+
+  Added C implementations of selectrow_arrayref() and fetchall_arrayref()
+    in Driver.xst.  All compiled drivers using Driver.xst will now be
+    faster making those calls. Most noticable with fetchall_arrayref for
+    many rows or selectrow_arrayref with a fast query. For example, using
+    DBD::mysql a selectrow_arrayref for a single row using a primary key
+    is ~20% faster, and fetchall_arrayref for 20000 rows is twice as fast!
+    Drivers just need to be recompiled and reinstalled to enable it.
+    The fetchall_arrayref speed up only applies if $slice parameter is not used.
+  Added $max_rows parameter to fetchall_arrayref() to optionally limit
+    the number of rows returned. Can now fetch batches of rows.
+  Added MaxRows attribute to selectall_arrayref()
+    which then passes it to fetchall_arrayref().
+  Changed selectrow_array to make use of selectrow_arrayref.
+  Trace level 1 now shows first two parameters of all methods
+    (used to only for that for some, like prepare,execute,do etc)
+  Trace indicator for recursive calls (first char on trace lines)
+    now starts at 1 not 2.
+
+  Documented that $h->func() does not trigger RaiseError etc
+    so applications must explicitly check for errors.
+  DBI::Profile with DBI_PROFILE now shows percentage time inside DBI.
+  HandleError docs updated to show that handler can edit error message.
+  HandleError subroutine interface is now regarded as stable.
+
+=head2 Changes in DBI 1.25,    5th June 2002
+
+  Fixed build problem on Windows and some compiler warnings.
+  Fixed $dbh->{Driver} and $sth->{Statement} for driver internals
+    These are 'inner' handles as per behaviour prior to DBI 1.16.
+  Further minor improvements to DBI::PurePerl accuracy.
+
+=head2 Changes in DBI 1.24,    4th June 2002
+
+  Fixed reference loop causing a handle/memory leak
+    that was introduced in DBI 1.16.
+  Fixed DBI::Format to work with 'filehandles' from IO::Scalar
+    and similar modules thanks to report by Jeff Boes.
+  Fixed $h->func for DBI::PurePerl thanks to Jeff Zucker.
+  Fixed $dbh->{Name} for DBI::PurePerl thanks to Dean Arnold.
+
+  Added DBI method call profiling and benchmarking.
+    This is a major new addition to the DBI.
+    See $h->{Profile} attribute and DBI::Profile module.
+    For a quick trial, set the DBI_PROFILE environment variable and
+    run your favourite DBI script. Try it with DBI_PROFILE set to 1,
+    then try 2, 4, 8, 10, and -10. Have fun!
+
+  Added execute_array() and bind_param_array() documentation
+    with thanks to Dean Arnold.
+  Added notes about the DBI having not yet been tested with iThreads
+    (testing and patches for SvLOCK etc welcome).
+  Removed undocumented Handlers attribute (replaced by HandleError).
+  Tested with 5.5.3 and 5.8.0 RC1.
+
+=head2 Changes in DBI 1.23,    25th May 2002
+
+  Greatly improved DBI::PurePerl in performance and accuracy.
+  Added more detail to DBI::PurePerl docs about what's not supported.
+  Fixed undef warnings from t/15array.t and DBD::Sponge.
+
+=head2 Changes in DBI 1.22,    22nd May 2002
+
+  Added execute_array() and bind_param_array() with special thanks
+    to Dean Arnold. Not yet documented. See t/15array.t for examples.
+    All drivers now automatically support these methods.
+  Added DBI::PurePerl, a transparent DBI emulation for pure-perl drivers
+    with special thanks to Jeff Zucker. Perldoc DBI::PurePerl for details.
+  Added DBI::Const::GetInfo* modules thanks to Steffen Goeldner.
+  Added write_getinfo_pm utility to DBI::DBD thanks to Steffen Goeldner.
+  Added $allow_active==2 mode for prepare_cached() thanks to Stephen Clouse.
+
+  Updated DBI::Format to Revision 11.4 thanks to Tom Lowery.
+  Use File::Spec in Makefile.PL (helps VMS etc) thanks to Craig Berry.
+  Extend $h->{Warn} to commit/rollback ineffective warning thanks to Jeff Baker.
+  Extended t/preparse.t and removed "use Devel::Peek" thanks to Scott Hildreth.
+  Only copy Changes to blib/lib/Changes.pm once thanks to Jonathan Leffler.
+  Updated internals for modern perls thanks to Jonathan Leffler and Jeff Urlwin.
+  Tested with perl 5.7.3 (just using default perl config).
+
+  Documentation changes:
+
+  Added 'Catalog Methods' section to docs thanks to Steffen Goeldner.
+  Updated README thanks to Michael Schwern.
+  Clarified that driver may choose not to start new transaction until
+    next use of $dbh after commit/rollback.
+  Clarified docs for finish method.
+  Clarified potentials problems with prepare_cached() thanks to Stephen Clouse.
+
+
+=head2 Changes in DBI 1.21,    7th February 2002
+
+  The minimum supported perl version is now 5.005_03.
+
+  Fixed DBD::Proxy support for AutoCommit thanks to Jochen Wiedmann.
+  Fixed DBI::ProxyServer bind_param(_inout) handing thanks to Oleg Mechtcheriakov.
+  Fixed DBI::ProxyServer fetch loop thanks to nobull@mail.com.
+  Fixed install_driver do-the-right-thing with $@ on error. It, and connect(),
+    will leave $@ empty on success and holding the error message on error.
+    Thanks to Jay Lawrence, Gavin Sherlock and others for the bug report.
+  Fixed fetchrow_hashref to assign columns to the hash left-to-right
+    so later fields with the same name overwrite earlier ones
+    as per DBI < 1.15, thanks to Kay Roepke.
+
+  Changed tables() to use quote_indentifier() if the driver returns a
+    true value for $dbh->get_info(29) # SQL_IDENTIFIER_QUOTE_CHAR
+  Changed ping() so it no longer triggers RaiseError/PrintError.
+  Changed connect() to not call $class->install_driver unless needed.
+  Changed DESTROY to catch fatal exceptions and append to $@.
+
+  Added ISO SQL/CLI & ODBCv3 data type definitions thanks to Steffen Goeldner.
+  Removed the definition of SQL_BIGINT data type constant as the value is
+    inconsistent between standards (ODBC=-5, SQL/CLI=25).
+  Added $dbh->column_info(...) thanks to Steffen Goeldner.
+  Added $dbh->foreign_key_info(...) thanks to Steffen Goeldner.
+  Added $dbh->quote_identifier(...) insipred by Simon Oliver.
+  Added $dbh->set_err(...) for DBD authors and DBI subclasses
+    (actually been there for a while, now expanded and documented).
+  Added $h->{HandleError} = sub { ... } addition and/or alternative
+    to RaiseError/PrintError. See the docs for more info.
+  Added $h->{TraceLevel} = N attribute to set/get trace level of handle
+    thus can set trace level via an (eg externally specified) DSN
+    using the embedded attribute syntax:
+      $dsn = 'dbi:DB2(PrintError=1,TraceLevel=2):dbname';
+    Plus, you can also now do: local($h->{TraceLevel}) = N;
+    (but that leaks a little memory in some versions of perl).
+  Added some call tree information to trace output if trace level >= 3
+    With thanks to Graham Barr for the stack walking code.
+  Added experimental undocumented $dbh->preparse(), see t/preparse.t
+    With thanks to Scott T. Hildreth for much of the work.
+  Added Fowler/Noll/Vo hash type as an option to DBI::hash().
+
+  Documentation changes:
+
+  Added DBI::Changes so now you can "perldoc DBI::Changes", yeah!
+  Added selectrow_arrayref & selectrow_hashref docs thanks to Doug Wilson.
+  Added 'Standards Reference Information' section to docs to gather
+    together all references to relevant on-line standards.
+  Added link to poop.sourceforge.net into the docs thanks to Dave Rolsky.
+  Added link to hyperlinked BNF for SQL92 thanks to Jeff Zucker.
+  Added 'Subclassing the DBI' docs thanks to Stephen Clouse, and
+    then changed some of them to reflect the new approach to subclassing.
+  Added stronger wording to description of $h->{private_*} attributes.
+  Added docs for DBI::hash.
+
+  Driver API changes:
+
+  Now a COPY of the DBI->connect() attributes is passed to the driver
+    connect() method, so it can process and delete any elements it wants.
+    Deleting elements reduces/avoids the explicit
+      $dbh->{$_} = $attr->{$_} foreach keys %$attr;
+    that DBI->connect does after the driver connect() method returns.
+
+
+=head2 Changes in DBI 1.20,    24th August 2001
+
+  WARNING: This release contains two changes that may affect your code.
+  : Any code using selectall_hashref(), which was added in March 2001, WILL
+  : need to be changed. Any code using fetchall_arrayref() with a non-empty
+  : hash slice parameter may, in a few rare cases, need to be changed.
+  : See the change list below for more information about the changes.
+  : See the DBI documentation for a description of current behaviour.
+
+  Fixed memory leak thanks to Toni Andjelkovic.
+  Changed fetchall_arrayref({ foo=>1, ...}) specification again (sorry):
+    The key names of the returned hashes is identical to the letter case of
+    the names in the parameter hash, regardless of the L</FetchHashKeyName>
+    attribute. The letter case is ignored for matching.
+  Changed fetchall_arrayref([...]) array slice syntax specification to
+    clarify that the numbers in the array slice are perl index numbers
+    (which start at 0) and not column numbers (which start at 1).
+  Added { Columns=>... } and { Slice =>... } attributes to selectall_arrayref()
+    which is passed to fetchall_arrayref() so it can fetch hashes now.
+  Added a { Columns => [...] } attribute to selectcol_arrayref() so that
+    the list it returns can be built from more than one column per row.
+    Why? Consider my %hash = @{$dbh->selectcol_arrayref($sql,{ Columns=>[1,2]})}
+    to return id-value pairs which can be used directly to build a hash.
+  Added $hash_ref = $sth->fetchall_hashref( $key_field )
+    which returns a ref to a hash with, typically, one element per row.
+    $key_field is the name of the field to get the key for each row from.
+    The value of the hash for each row is a hash returned by fetchrow_hashref.
+  Changed selectall_hashref to return a hash ref (from fetchall_hashref)
+    and not an array of hashes as it has since DBI 1.15 (end March 2001).
+    WARNING: THIS CHANGE WILL BREAK ANY CODE USING selectall_hashref()!
+    Sorry, but I think this is an important regularization of the API.
+    To get previous selectall_hashref() behaviour (an array of hash refs)
+    change $ary_ref = $dbh->selectall_hashref( $statement, undef, @bind);
+	to $ary_ref = $dbh->selectall_arrayref($statement, { Columns=>{} }, @bind);
+  Added NAME_lc_hash, NAME_uc_hash, NAME_hash statement handle attributes.
+    which return a ref to a hash of field_name => field_index (0..n-1) pairs.
+  Fixed select_hash() example thanks to Doug Wilson.
+  Removed (unbundled) DBD::ADO and DBD::Multiplex from the DBI distribution.
+    The latest versions of those modules are available from CPAN sites.
+  Added $dbh->begin_work. This method causes AutoCommit to be turned
+    off just until the next commit() or rollback().
+    Driver authors: if the DBIcf_BegunWork flag is set when your commit or
+    rollback method is called then please turn AutoCommit on and clear the
+    DBIcf_BegunWork flag. If you don't then the DBI will but it'll be much
+    less efficient and won't handle error conditions very cleanly.
+  Retested on perl 5.4.4, but the DBI won't support 5.4.x much longer.
+  Added text to SUPPORT section of the docs:
+    For direct DBI and DBD::Oracle support, enhancement, and related work
+    I am available for consultancy on standard commercial terms.
+  Added text to ACKNOWLEDGEMENTS section of the docs:
+    Much of the DBI and DBD::Oracle was developed while I was Technical
+    Director (CTO) of the Paul Ingram Group (www.ig.co.uk).  So I'd
+    especially like to thank Paul for his generosity and vision in
+    supporting this work for many years.
+
+=head2 Changes in DBI 1.19,    20th July 2001
+
+  Made fetchall_arrayref({ foo=>1, ...}) be more strict to the specification
+    in relation to wanting hash slice keys to be lowercase names.
+    WARNING: If you've used fetchall_arrayref({...}) with a hash slice
+    that contains keys with uppercase letters then your code will break.
+    (As far as I recall the spec has always said don't do that.)
+  Fixed $sth->execute() to update $dbh->{Statement} to $sth->{Statement}.
+  Added row number to trace output for fetch method calls.
+  Trace level 1 no longer shows fetches with row>1 (to reduce output volume).
+  Added $h->{FetchHashKeyName} = 'NAME_lc' or 'NAME_uc' to alter
+    behaviour of fetchrow_hashref() method. See docs.
+  Added type_info quote caching to quote() method thanks to Dean Kopesky.
+    Makes using quote() with second data type param much much faster.
+  Added type_into_all() caching to type_info(), spotted by Dean Kopesky.
+  Added new API definition for table_info() and tables(),
+    driver authors please note!
+  Added primary_key_info() to DBI API thanks to Steffen Goeldner.
+  Added primary_key() to DBI API as simpler interface to primary_key_info().
+  Indent and other fixes for DBI::DBD doc thanks to H.Merijn Brand.
+  Added prepare_cached() insert_hash() example thanks to Doug Wilson.
+  Removed false docs for fetchall_hashref(), use fetchall_arrayref({}).
+
+=head2 Changes in DBI 1.18,    4th June 2001
+
+  Fixed that altering ShowErrorStatement also altered AutoCommit!
+    Thanks to Jeff Boes for spotting that clanger.
+  Fixed DBD::Proxy to handle commit() and rollback(). Long overdue, sorry.
+  Fixed incompatibility with perl 5.004 (but no one's using that right? :)
+  Fixed connect_cached and prepare_cached to not be affected by the order
+    of elements in the attribute hash. Spotted by Mitch Helle-Morrissey.
+  Fixed version number of DBI::Shell
+    reported by Stuhlpfarrer Gerhard and others.
+  Defined and documented table_info() attribute semantics (ODBC compatible)
+    thanks to Olga Voronova, who also implemented then in DBD::Oracle.
+  Updated Win32::DBIODBC (Win32::ODBC emulation) thanks to Roy Lee.
+
+=head2 Changes in DBI 1.16,    30th May 2001
+
+  Reimplemented fetchrow_hashref in C, now fetches about 25% faster!
+  Changed behaviour if both PrintError and RaiseError are enabled
+    to simply do both (in that order, obviously :)
+  Slight reduction in DBI handle creation overhead.
+  Fixed $dbh->{Driver} & $sth->{Database} to return 'outer' handles.
+  Fixed execute param count check to honour RaiseError spotted by Belinda Giardie.
+  Fixed build for perl5.6.1 with PERLIO thanks to H.Merijn Brand.
+  Fixed client sql restrictions in ProxyServer.pm thanks to Jochen Wiedmann.
+  Fixed batch mode command parsing in Shell thanks to Christian Lemburg.
+  Fixed typo in selectcol_arrayref docs thanks to Jonathan Leffler.
+  Fixed selectrow_hashref to be available to callers thanks to T.J.Mather.
+  Fixed core dump if statement handle didn't define Statement attribute.
+  Added bind_param_inout docs to DBI::DBD thanks to Jonathan Leffler.
+  Added note to data_sources() method docs that some drivers may
+    require a connected database handle to be supplied as an attribute.
+  Trace of install_driver method now shows path of driver file loaded.
+  Changed many '||' to 'or' in the docs thanks to H.Merijn Brand.
+  Updated DBD::ADO again (improvements in error handling) from Tom Lowery.
+  Updated Win32::DBIODBC (Win32::ODBC emulation) thanks to Roy Lee.
+  Updated email and web addresses in DBI::FAQ thanks to Michael A Chase.
+
+=head2 Changes in DBI 1.15,    28th March 2001
+
+  Added selectrow_arrayref
+  Added selectrow_hashref
+  Added selectall_hashref thanks to Leon Brocard.
+  Added DBI->connect(..., { dbi_connect_method => 'method' })
+  Added $dbh->{Statement} aliased to most recent child $sth->{Statement}.
+  Added $h->{ShowErrorStatement}=1 to cause the appending of the
+    relevant Statement text to the RaiseError/PrintError text.
+  Modified type_info to always return hash keys in uppercase and
+    to not require uppercase 'DATA_TYPE' key from type_info_all.
+    Thanks to Jennifer Tong and Rob Douglas.
+  Added \%attr param to tables() and table_info() methods.
+  Trace method uses warn() if it can't open the new file.
+  Trace shows source line and filename during global destruction.
+  Updated packages:
+    Updated Win32::DBIODBC (Win32::ODBC emulation) thanks to Roy Lee.
+    Updated DBD::ADO to much improved version 0.4 from Tom Lowery.
+    Updated DBD::Sponge to include $sth->{PRECISION} thanks to Tom Lowery.
+    Changed DBD::ExampleP to use lstat() instead of stat().
+  Documentation:
+    Documented $DBI::lasth (which has been there since day 1).
+    Documented SQL_* names.
+    Clarified and extended docs for $h->state thanks to Masaaki Hirose.
+    Clarified fetchall_arrayref({}) docs (thanks to, er, someone!).
+    Clarified type_info_all re lettercase and index values.
+    Updated DBI::FAQ to 0.38 thanks to Alligator Descartes.
+    Added cute bind_columns example thanks to H.Merijn Brand.
+    Extended docs on \%attr arg to data_sources method.
+  Makefile.PL
+    Removed obscure potential 'rm -rf /' (thanks to Ulrich Pfeifer).
+    Removed use of glob and find (thanks to Michael A. Chase).
+  Proxy:
+    Removed debug messages from DBD::Proxy AUTOLOAD thanks to Brian McCauley.
+    Added fix for problem using table_info thanks to Tom Lowery.
+    Added better determination of where to put the pid file, and...
+    Added KNOWN ISSUES section to DBD::Proxy docs thanks to Jochen Wiedmann.
+  Shell:
+    Updated DBI::Format to include DBI::Format::String thanks to Tom Lowery.
+    Added describe command thanks to Tom Lowery.
+    Added columnseparator option thanks to Tom Lowery (I think).
+    Added 'raw' format thanks to, er, someone, maybe Tom again.
+  Known issues:
+    Perl 5.005 and 5.006 both leak memory doing local($handle->{Foo}).
+    Perl 5.004 doesn't. The leak is not a DBI or driver bug.
+
+=head2 Changes in DBI 1.14,	14th June 2000
+
+  NOTE: This version is the one the DBI book is based on.
+  NOTE: This version requires at least Perl 5.004.
+  Perl 5.6 ithreads changes with thanks to Doug MacEachern.
+  Changed trace output to use PerlIO thanks to Paul Moore.
+  Fixed bug in RaiseError/PrintError handling.
+    (% chars in the error string could cause a core dump.)
+  Fixed Win32 PerlEx IIS concurrency bugs thanks to Murray Nesbitt.
+  Major documentation polishing thanks to Linda Mui at O'Reilly.
+  Password parameter now shown as **** in trace output.
+  Added two fields to type_info and type_info_all.
+  Added $dsn to PrintError/RaiseError message from DBI->connect().
+  Changed prepare_cached() croak to carp if sth still Active.
+  Added prepare_cached() example to the docs.
+  Added further DBD::ADO enhancements from Thomas Lowery.
+
+=head2 Changes in DBI 1.13,	11th July 1999
+
+  Fixed Win32 PerlEx IIS concurrency bugs thanks to Murray Nesbitt.
+  Fixed problems with DBD::ExampleP long_list test mode.
+  Added SQL_WCHAR SQL_WVARCHAR SQL_WLONGVARCHAR and SQL_BIT
+    to list of known and exportable SQL types.
+  Improved data fetch performance of DBD::ADO.
+  Added GetTypeInfo to DBD::ADO thanks to Thomas Lowery.
+  Actually documented connect_cached thanks to Michael Schwern.
+  Fixed user/key/cipher bug in ProxyServer thanks to Joshua Pincus.
+
+=head2 Changes in DBI 1.12,	29th June 1999
+
+  Fixed significant DBD::ADO bug (fetch skipped first row).
+  Fixed ProxyServer bug handling non-select statements.
+  Fixed VMS problem with t/examp.t thanks to Craig Berry.
+  Trace only shows calls to trace_msg and _set_fbav at high levels.
+  Modified t/examp.t to workaround Cygwin buffering bug.
+
+=head2 Changes in DBI 1.11,	17th June 1999
+
+  Fixed bind_columns argument checking to allow a single arg.
+  Fixed problems with internal default_user method.
+  Fixed broken DBD::ADO.
+  Made default $DBI::rows more robust for some obscure cases.
+
+=head2 Changes in DBI 1.10,	14th June 1999
+
+  Fixed trace_msg.al error when using Apache.
+  Fixed dbd_st_finish enhancement in Driver.xst (internals).
+  Enable drivers to define default username and password
+    and temporarily disabled warning added in 1.09.
+  Thread safety optimised for single thread case.
+
+=head2 Changes in DBI 1.09,	9th June 1999
+
+  Added optional minimum trace level parameter to trace_msg().
+  Added warning in Makefile.PL that DBI will require 5.004 soon.
+  Added $dbh->selectcol_arrayref($statement) method.
+  Fixed fetchall_arrayref hash-slice mode undef NAME problem.
+  Fixed problem with tainted parameter checking and t/examp.t.
+  Fixed problem with thread safety code, including 64 bit machines.
+  Thread safety now enabled by default for threaded perls.
+  Enhanced code for MULTIPLICITY/PERL_OBJECT from ActiveState.
+  Enhanced prepare_cached() method.
+  Minor changes to trace levels (less internal info at level 2).
+  Trace log now shows "!! ERROR..." before the "<- method" line.
+  DBI->connect() now warn's if user / password is undefined and
+    DBI_USER / DBI_PASS environment variables are not defined.
+  The t/proxy.t test now ignores any /etc/dbiproxy.conf file.
+  Added portability fixes for MacOS from Chris Nandor.
+  Updated mailing list address from fugue.com to isc.org.
+
+=head2 Changes in DBI 1.08,	12th May 1999
+
+  Much improved DBD::ADO driver thanks to Phlip Plumlee and others.
+  Connect now allows you to specify attribute settings within the DSN
+    E.g., "dbi:Driver(RaiseError=>1,Taint=>1,AutoCommit=>0):dbname"
+  The $h->{Taint} attribute now also enables taint checking of
+    arguments to almost all DBI methods.
+  Improved trace output in various ways.
+  Fixed bug where $sth->{NAME_xx} was undef in some situations.
+  Fixed code for MULTIPLICITY/PERL_OBJECT thanks to Alex Smishlajev.
+  Fixed and documented DBI->connect_cached.
+  Workaround for Cygwin32 build problem with help from Jong-Pork Park.
+  bind_columns no longer needs undef or hash ref as first parameter.
+
+=head2 Changes in DBI 1.07,	6th May 1999
+
+  Trace output now shows contents of array refs returned by DBI.
+  Changed names of some result columns from type_info, type_info_all,
+    tables and table_info to match ODBC 3.5 / ISO/IEC standards.
+  Many fixes for DBD::Proxy and ProxyServer.
+  Fixed error reporting in install_driver.
+  Major enhancement to DBI::W32ODBC from Patrick Hollins.
+  Added $h->{Taint} to taint fetched data if tainting (perl -T).
+  Added code for MULTIPLICITY/PERL_OBJECT contributed by ActiveState.
+  Added $sth->more_results (undocumented for now).
+
+=head2 Changes in DBI 1.06,	6th January 1999
+
+  Fixed Win32 Makefile.PL problem in 1.04 and 1.05.
+  Significant DBD::Proxy enhancements and fixes
+    including support for bind_param_inout (Jochen and I)
+  Added experimental DBI->connect_cached method.
+  Added $sth->{NAME_uc} and $sth->{NAME_lc} attributes.
+  Enhanced fetchrow_hashref to take an attribute name arg.
+
+=head2 Changes in DBI 1.05,	4th January 1999
+
+  Improved DBD::ADO connect (thanks to Phlip Plumlee).
+  Improved thread safety (thanks to Jochen Wiedmann).
+  [Quick release prompted by truncation of copies on CPAN]
+
+=head2 Changes in DBI 1.04,	3rd January 1999
+
+  Fixed error in Driver.xst. DBI build now tests Driver.xst.
+  Removed unused variable compiler warnings in Driver.xst.
+  DBI::DBD module now tested during DBI build.
+  Further clarification in the DBI::DBD driver writers manual.
+  Added optional name parameter to $sth->fetchrow_hashref.
+
+=head2 Changes in DBI 1.03,	1st January 1999
+
+  Now builds with Perl>=5.005_54 (PERL_POLLUTE in DBIXS.h)
+  DBI trace trims path from "at yourfile.pl line nnn".
+  Trace level 1 now shows statement passed to prepare.
+  Assorted improvements to the DBI manual.
+  Assorted improvements to the DBI::DBD driver writers manual.
+  Fixed $dbh->quote prototype to include optional $data_type.
+  Fixed $dbh->prepare_cached problems.
+  $dbh->selectrow_array behaves better in scalar context.
+  Added a (very) experimental DBD::ADO driver for Win32 ADO.
+  Added experimental thread support (perl Makefile.PL -thread).
+  Updated the DBI::FAQ - thanks to Alligator Descartes.
+  The following changes were implemented and/or packaged
+    by Jochen Wiedmann - thanks Jochen:
+  Added a Bundle for CPAN installation of DBI, the DBI proxy
+    server and prerequisites (lib/Bundle/DBI.pm).
+  DBI->available_drivers uses File::Spec, if available.
+    This makes it work on MacOS. (DBI.pm)
+  Modified type_info to work with read-only values returned
+    by type_info_all. (DBI.pm)
+  Added handling of magic values in $sth->execute,
+    $sth->bind_param and other methods (Driver.xst)
+  Added Perl's CORE directory to the linkers path on Win32,
+    required by recent versions of ActiveState Perl.
+  Fixed DBD::Sponge to work with empty result sets.
+  Complete rewrite of DBI::ProxyServer and DBD::Proxy.
+
+=head2 Changes in DBI 1.02,	2nd September 1998
+
+  Fixed DBI::Shell including @ARGV and /current.
+  Added basic DBI::Shell test.
+  Renamed DBI::Shell /display to /format.
+
+=head2 Changes in DBI 1.01,	2nd September 1998
+
+  Many enhancements to Shell (with many contributions from
+  Jochen Wiedmann, Tom Lowery and Adam Marks).
+  Assorted fixes to DBD::Proxy and DBI::ProxyServer.
+  Tidied up trace messages - trace(2) much cleaner now.
+  Added $dbh->{RowCacheSize} and $sth->{RowsInCache}.
+  Added experimental DBI::Format (mainly for DBI::Shell).
+  Fixed fetchall_arrayref($slice_hash).
+  DBI->connect now honours PrintError=1 if connect fails.
+  Assorted clarifications to the docs.
+
+=head2 Changes in DBI 1.00,	14th August 1998
+
+  The DBI is no longer 'alpha' software!
+  Added $dbh->tables and $dbh->table_info.
+  Documented \%attr arg to data_sources method.
+  Added $sth->{TYPE}, $sth->{PRECISION} and $sth->{SCALE}.
+  Added $sth->{Statement}.
+  DBI::Shell now uses neat_list to print results
+  It also escapes "'" chars and converts newlines to spaces.
+
+=head2 Changes in DBI 0.95,	10th August 1998
+
+  WARNING: THIS IS AN EXPERIMENTAL RELEASE!
+
+  Fixed 0.94 slip so it will build on pre-5.005 again.
+  Added DBI_AUTOPROXY environment variable.
+  Array ref returned from fetch/fetchrow_arrayref now readonly.
+  Improved connect error reporting by DBD::Proxy.
+  All trace/debug messages from DBI now go to trace file.
+
+=head2 Changes in DBI 0.94,	9th August 1998
+
+  WARNING: THIS IS AN EXPERIMENTAL RELEASE!
+
+  Added DBD::Shell and dbish interactive DBI shell. Try it!
+  Any database attribs can be set via DBI->connect(,,, \%attr).
+  Added _get_fbav and _set_fbav methods for Perl driver developers
+    (see ExampleP driver for perl usage). Drivers which don't use
+    one of these methods (either via XS or Perl) are not compliant.
+  DBI trace now shows adds " at yourfile.pl line nnn"!
+  PrintError and RaiseError now prepend driver and method name.
+  The available_drivers method no longer returns NullP or Sponge.
+  Added $dbh->{Name}.
+  Added $dbh->quote($value, $data_type).
+  Added more hints to install_driver failure message.
+  Added DBD::Proxy and DBI::ProxyServer (from Jochen Wiedmann).
+  Added $DBI::neat_maxlen to control truncation of trace output.
+  Added $dbh->selectall_arrayref and $dbh->selectrow_array methods.
+  Added $dbh->tables.
+  Added $dbh->type_info and $dbh->type_info_all.
+  Added $h->trace_msg($msg) to write to trace log.
+  Added @bool = DBI::looks_like_number(@ary).
+  Many assorted improvements to the DBI docs.
+
+=head2 Changes in DBI 0.93,	13th February 1998
+
+  Fixed DBI::DBD::dbd_postamble bug causing 'Driver.xsi not found' errors.
+  Changes to handling of 'magic' values in neatsvpv (used by trace).
+  execute (in Driver.xst) stops binding after first bind error.
+  This release requires drivers to be rebuilt.
+
+=head2 Changes in DBI 0.92,	3rd February 1998
+
+  Fixed per-handle memory leak (with many thanks to Irving Reid).
+  Added $dbh->prepare_cached() caching variant of $dbh->prepare.
+  Added some attributes:
+    $h->{Active}       is the handle 'Active' (vague concept) (boolean)
+    $h->{Kids}         e.g. number of sth's associated with a dbh
+    $h->{ActiveKids}   number of the above which are 'Active'
+    $dbh->{CachedKids} ref to prepare_cached sth cache
+  Added support for general-purpose 'private_' attributes.
+  Added experimental support for subclassing the DBI: see t/subclass.t
+  Added SQL_ALL_TYPES to exported :sql_types.
+  Added dbd_dbi_dir() and dbd_dbi_arch_dir() to DBI::DBD module so that
+  DBD Makefile.PLs can work with the DBI installed in non-standard locations.
+  Fixed 'Undefined value' warning and &sv_no output from neatsvpv/trace.
+  Fixed small 'once per interpreter' leak.
+  Assorted minor documentation fixes.
+
+=head2 Changes in DBI 0.91,	10th December 1997
+
+  NOTE: This fix may break some existing scripts:
+  DBI->connect("dbi:...",$user,$pass) was not setting AutoCommit and PrintError!
+  DBI->connect(..., { ... }) no longer sets AutoCommit or PrintError twice.
+  DBI->connect(..., { RaiseError=>1 }) now croaks if connect fails.
+  Fixed $fh parameter of $sth->dump_results;
+  Added default statement DESTROY method which carps.
+  Added default driver DESTROY method to silence AUTOLOAD/__DIE__/CGI::Carp
+  Added more SQL_* types to %EXPORT_TAGS and @EXPORT_OK.
+  Assorted documentation updates (mainly clarifications).
+  Added workaround for perl's 'sticky lvalue' bug.
+  Added better warning for bind_col(umns) where fields==0.
+  Fixed to build okay with 5.004_54 with or without USE_THREADS.
+  Note that the DBI has not been tested for thread safety yet.
+
+=head2 Changes in DBI 0.90,	6th September 1997
+
+  Can once again be built with Perl 5.003.
+  The DBI class can be subclassed more easily now.
+  InactiveDestroy fixed for drivers using the *.xst template.
+  Slightly faster handle creation.
+  Changed prototype for dbd_*_*_attrib() to add extra param.
+  Note: 0.90, 0.89 and possibly some other recent versions have
+  a small memory leak. This will be fixed in the next release.
+
+=head2 Changes in DBI 0.89,	25th July 1997
+
+  Minor fix to neatsvpv (mainly used for debug trace) to workaround
+  bug in perl where SvPV removes IOK flag from an SV.
+  Minor updates to the docs.
+
+=head2 Changes in DBI 0.88,	22nd July 1997
+
+  Fixed build for perl5.003 and Win32 with Borland.
+  Fixed documentation formatting.
+  Fixed DBI_DSN ignored for old-style connect (with explicit driver).
+  Fixed AutoCommit in DBD::ExampleP
+  Fixed $h->trace.
+  The DBI can now export SQL type values: use DBI ':sql_types';
+  Modified Driver.xst and renamed DBDI.h to dbd_xsh.h
+
+=head2 Changes in DBI 0.87,	18th July 1997
+
+  Fixed minor type clashes.
+  Added more docs about placeholders and bind values.
+
+=head2 Changes in DBI 0.86,	16th July 1997
+
+  Fixed failed connect causing 'unblessed ref' and other errors.
+  Drivers must handle AutoCommit FETCH and STORE else DBI croaks.
+  Added $h->{LongReadLen} and $h->{LongTruncOk} attributes for BLOBS.
+  Added DBI_USER and DBI_PASS env vars. See connect docs for usage.
+  Added DBI->trace() to set global trace level (like per-handle $h->trace).
+  PERL_DBI_DEBUG env var renamed DBI_DEBUG (old name still works for now).
+  Updated docs, including commit, rollback, AutoCommit and Transactions sections.
+  Added bind_param method and execute(@bind_values) to docs.
+  Fixed fetchall_arrayref.
+
+  Since the DBIS structure has change the internal version numbers have also
+  changed (DBIXS_VERSION == 9 and DBISTATE_VERSION == 9) so drivers will have
+  to be recompiled. The test is also now more sensitive and the version
+  mismatch error message now more clear about what to do. Old drivers are
+  likely to core dump (this time) until recompiled for this DBI. In future
+  DBI/DBD version mismatch will always produce a clear error message.
+
+  Note that this DBI release contains and documents many new features
+  that won't appear in drivers for some time. Driver writers might like
+  to read perldoc DBI::DBD and comment on or apply the information given.
+
+=head2 Changes in DBI 0.85,	25th June 1997
+
+  NOTE: New-style connect now defaults to AutoCommit mode unless
+  { AutoCommit => 0 } specified in connect attributes. See the docs.
+  AutoCommit attribute now defined and tracked by DBI core.
+  Drivers should use/honour this and not implement their own.
+  Added pod doc changes from Andreas and Jonathan.
+  New DBI_DSN env var default for connect method. See docs.
+  Documented the func method.
+  Fixed "Usage: DBD::_::common::DESTROY" error.
+  Fixed bug which set some attributes true when there value was fetched.
+  Added new internal DBIc_set() macro for drivers to use.
+
+=head2 Changes in DBI 0.84,	20th June 1997
+
+  Added $h->{PrintError} attribute which, if set true, causes all errors to
+  trigger a warn().
+  New-style DBI->connect call now automatically sets PrintError=1 unless
+  { PrintError => 0 } specified in the connect attributes. See the docs.
+  The old-style connect with a separate driver parameter is deprecated.
+  Fixed fetchrow_hashref.
+  Renamed $h->debug to $h->trace() and added a trace filename arg.
+  Assorted other minor tidy-ups.
+
+=head2 Changes in DBI 0.83,	11th June 1997
+
+  Added driver specification syntax to DBI->connect data_source
+  parameter: DBI->connect('dbi:driver:...', $user, $passwd);
+  The DBI->data_sources method should return data_source
+  names with the appropriate 'dbi:driver:' prefix.
+  DBI->connect will warn if \%attr is true but not a hash ref.
+  Added the new fetchrow methods:
+    @row_ary  = $sth->fetchrow_array;
+    $ary_ref  = $sth->fetchrow_arrayref;
+    $hash_ref = $sth->fetchrow_hashref;
+  The old fetch and fetchrow methods still work.
+  Driver implementors should implement the new names for
+  fetchrow_array and fetchrow_arrayref ASAP (use the xs ALIAS:
+  directive to define aliases for fetch and fetchrow).
+  Fixed occasional problems with t/examp.t test.
+  Added automatic errstr reporting to the debug trace output.
+  Added the DBI FAQ from Alligator Descartes in module form for
+  easy reading via "perldoc DBI::FAQ". Needs reformatting.
+  Unknown driver specific attribute names no longer croak.
+  Fixed problem with internal neatsvpv macro.
+
+=head2 Changes in DBI 0.82,	23rd May 1997
+
+  Added $h->{RaiseError} attribute which, if set true, causes all errors to
+  trigger a die(). This makes it much easier to implement robust applications
+  in terms of higher level eval { ... } blocks and rollbacks.
+  Added DBI->data_sources($driver) method for implementation by drivers.
+  The quote method now returns the string NULL (without quotes) for undef.
+  Added VMS support thanks to Dan Sugalski.
+  Added a 'quick start guide' to the README.
+  Added neatsvpv function pointer to DBIS structure to make it available for
+  use by drivers. A macro defines neatsvpv(sv,len) as (DBIS->neatsvpv(sv,len)).
+  Old XS macro SV_YES_NO changes to standard boolSV.
+  Since the DBIS structure has change the internal version numbers have also
+  changed (DBIXS_VERSION == 8 and DBISTATE_VERSION == 8) so drivers will have
+  to be recompiled.
+
+=head2 Changes in DBI 0.81,	7th May 1997
+
+  Minor fix to let DBI build using less modern perls.
+  Fixed a suprious typo warning.
+
+=head2 Changes in DBI 0.80,	6th May 1997
+
+  Builds with no changes on NT using perl5.003_99 (with thanks to Jeffrey Urlwin).
+  Automatically supports Apache::DBI (with thanks to Edmund Mergl).
+    DBI scripts no longer need to be modified to make use of Apache::DBI.
+  Added a ping method and an experimental connect_test_perf method.
+  Added a fetchhash and fetch_all methods.
+  The func method no longer pre-clears err and errstr. 
+  Added ChopBlanks attribute (currently defaults to off, that may change).
+    Support for the attribute needs to be implemented by individual drivers.
+  Reworked tests into standard t/*.t form.
+  Added more pod text.  Fixed assorted bugs.
+  
+
+=head2 Changes in DBI 0.79,	7th Apr 1997
+
+  Minor release. Tidied up pod text and added some more descriptions
+  (especially disconnect). Minor changes to DBI.xs to remove compiler
+  warnings.
+
+=head2 Changes in DBI 0.78,	28th Mar 1997
+
+  Greatly extended the pod documentation in DBI.pm, including the under
+  used bind_columns method. Use 'perldoc DBI' to read after installing.
+  Fixed $h->err. Fetching an attribute value no longer resets err.
+  Added $h->{InactiveDestroy}, see documentation for details.
+  Improved debugging of cached ('quick') attribute fetches.
+  errstr will return err code value if there is no string value.
+  Added DBI/W32ODBC to the distribution. This is a pure-perl experimental
+  DBI emulation layer for Win32::ODBC. Note that it's unsupported, your
+  mileage will vary, and bug reports without fixes will probably be ignored.
+
+=head2 Changes in DBI 0.77,	21st Feb 1997
+
+  Removed erroneous $h->errstate and $h->errmsg methods from DBI.pm.
+  Added $h->err, $h->errstr and $h->state default methods in DBI.xs.
+  Updated informal DBI API notes in DBI.pm. Updated README slightly.
+  DBIXS.h now correctly installed into INST_ARCHAUTODIR.
+  (DBD authors will need to edit their Makefile.PL's to use
+  -I$(INSTALLSITEARCH)/auto/DBI -I$(INSTALLSITEARCH)/DBI)
+
+
+=head2 Changes in DBI 0.76,	3rd Feb 1997
+
+  Fixed a compiler type warnings (pedantic IRIX again).
+
+=head2 Changes in DBI 0.75,	27th Jan 1997
+
+  Fix problem introduced by a change in Perl5.003_XX.
+  Updated README and DBI.pm docs.
+
+=head2 Changes in DBI 0.74,	14th Jan 1997
+
+  Dispatch now sets dbi_debug to the level of the current handle
+  (this makes tracing/debugging individual handles much easier).
+  The '>> DISPATCH' log line now only logged at debug >= 3 (was 2).
+  The $csr->NUM_OF_FIELDS attribute can be set if not >0 already.
+  You can log to a file using the env var PERL_DBI_DEBUG=/tmp/dbi.log.
+  Added a type cast needed by IRIX.
+  No longer sets perl_destruct_level unless debug set >= 4.
+  Make compatible with PerlIO and sfio.
+
+=head2 Changes in DBI 0.73,	10th Oct 1996
+
+  Fixed some compiler type warnings (IRIX).
+  Fixed DBI->internal->{DebugLog} = $filename.
+  Made debug log file unbuffered.
+  Added experimental bind_param_inout method to interface.
+  Usage: $dbh->bind_param_inout($param, \$value, $maxlen [, \%attribs ])
+  (only currently used by DBD::Oracle at this time.)
+
+=head2 Changes in DBI 0.72,	23 Sep 1996
+
+  Using an undefined value as a handle now gives a better
+  error message (mainly useful for emulators like Oraperl).
+  $dbh->do($sql, @params) now works for binding placeholders.
+
+=head2 Changes in DBI 0.71,	10 July 1996
+
+  Removed spurious abort() from invalid handle check.
+  Added quote method to DBI interface and added test.
+
+=head2 Changes in DBI 0.70,	16 June 1996
+
+  Added extra invalid handle check (dbih_getcom)
+  Fixed broken $dbh->quote method.
+  Added check for old GCC in Makefile.PL
+
+=head2 Changes in DBI 0.69
+
+  Fixed small memory leak.
+  Clarified the behaviour of DBI->connect.
+  $dbh->do now returns '0E0' instead of 'OK'.
+  Fixed "Can't read $DBI::errstr, lost last handle" problem.
+
+
+=head2 Changes in DBI 0.68,	2 Mar 1996
+
+  Changes to suit perl5.002 and site_lib directories.
+  Detects old versions ahead of new in @INC.
+
+
+=head2 Changes in DBI 0.67,	15 Feb 1996
+
+  Trivial change to test suite to fix a problem shown up by the
+  Perl5.002gamma release Test::Harness.
+
+
+=head2 Changes in DBI 0.66,	29 Jan 1996
+
+  Minor changes to bring the DBI into line with 5.002 mechanisms,
+  specifically the xs/pm VERSION checking mechanism.
+  No functionality changes. One no-last-handle bug fix (rare problem).
+  Requires 5.002 (beta2 or later).
+
+
+=head2 Changes in DBI 0.65,	23 Oct 1995
+
+  Added $DBI::state to hold SQL CLI / ODBC SQLSTATE value.
+  SQLSTATE "00000" (success) is returned as "" (false), all else is true.
+  If a driver does not explicitly initialise it (via $h->{State} or
+  DBIc_STATE(imp_xxh) then $DBI::state will automatically return "" if
+  $DBI::err is false otherwise "S1000" (general error).
+  As always, this is a new feature and liable to change.
+
+  The is *no longer* a default error handler!
+  You can add your own using push(@{$h->{Handlers}}, sub { ... })
+  but be aware that this interface may change (or go away).
+
+  The DBI now automatically clears $DBI::err, errstr and state before
+  calling most DBI methods. Previously error conditions would persist.
+  Added DBIh_CLEAR_ERROR(imp_xxh) macro.
+
+  DBI now EXPORT_OK's some utility functions, neat($value),
+  neat_list(@values) and dump_results($sth).
+
+  Slightly enhanced t/min.t minimal test script in an effort to help
+  narrow down the few stray core dumps that some porters still report.
+
+  Renamed readblob to blob_read (old name still works but warns).
+  Added default blob_copy_to_file method.
+
+  Added $sth = $dbh->tables method. This returns an $sth for a query
+  which has these columns: TABLE_CATALOGUE, TABLE_OWNER, TABLE_NAME,
+  TABLE_TYPE, REMARKS in that order. The TABLE_CATALOGUE column
+  should be ignored for now.
+
+
+=head2 Changes in DBI 0.64,	23 Oct 1995
+
+  Fixed 'disconnect invalidates 1 associated cursor(s)' problem.
+  Drivers using DBIc_ACTIVE_on/off() macros should not need any changes
+  other than to test for DBIc_ACTIVE_KIDS() instead of DBIc_KIDS().
+  Fixed possible core dump in dbih_clearcom during global destruction.
+
+
+=head2 Changes in DBI 0.63,	1 Sep 1995
+
+  Minor update. Fixed uninitialised memory bug in method
+  attribute handling and streamlined processing and debugging.
+  Revised usage definitions for bind_* methods and readblob.
+
+
+=head2 Changes in DBI 0.62,	26 Aug 1995
+
+  Added method redirection method $h->func(..., $method_name).
+  This is now the official way to call private driver methods
+  that are not part of the DBI standard.  E.g.:
+      @ary = $sth->func('ora_types');
+  It can also be used to call existing methods. Has very low cost.
+
+  $sth->bind_col columns now start from 1 (not 0) to match SQL.
+  $sth->bind_columns now takes a leading attribute parameter (or undef),
+  e.g., $sth->bind_columns($attribs, \$col1 [, \$col2 , ...]);
+
+  Added handy DBD_ATTRIBS_CHECK macro to vet attribs in XS.
+  Added handy DBD_ATTRIB_GET_SVP, DBD_ATTRIB_GET_BOOL and
+  DBD_ATTRIB_GET_IV macros for handling attributes.
+
+  Fixed STORE for NUM_OF_FIELDS and NUM_OF_PARAMS.
+  Added FETCH for NUM_OF_FIELDS and NUM_OF_PARAMS.
+
+  Dispatch no longer bothers to call _untie().
+  Faster startup via install_method/_add_dispatch changes.
+
+
+=head2 Changes in DBI 0.61,	22 Aug 1995
+
+  Added $sth->bind_col($column, \$var [, \%attribs ]);
+
+  This method enables perl variable to be directly and automatically
+  updated when a row is fetched. It requires no driver support
+  (if the driver has been written to use DBIS->get_fbav).
+  Currently \%attribs is unused.
+
+  Added $sth->bind_columns(\$var [, \$var , ...]);
+
+  This method is a short-cut for bind_col which binds all the
+  columns of a query in one go (with no attributes). It also
+  requires no driver support.
+
+  Added $sth->bind_param($parameter, $var [, \%attribs ]);
+
+  This method enables attributes to be specified when values are
+  bound to placeholders. It also enables binding to occur away
+  from the execute method to improve execute efficiency.
+  The DBI does not provide a default implementation of this.
+  See the DBD::Oracle module for a detailed example.
+
+  The DBI now provides default implementations of both fetch and
+  fetchrow.  Each is written in terms of the other. A driver is
+  expected to implement at least one of them.
+
+  More macro and assorted structure changes in DBDXS.h. Sorry!
+  The old dbihcom definitions have gone. All fields have macros.
+  The imp_xxh_t type is now used within the DBI as well as drivers.
+  Drivers must set DBIc_NUM_FIELDS(imp_sth) and DBIc_NUM_PARAMS(imp_sth).
+
+  test.pl includes a trivial test of bind_param and bind_columns.
+
+
+=head2 Changes in DBI 0.60,	17 Aug 1995
+
+  This release has significant code changes but much less
+  dramatic than the previous release. The new implementors data
+  handling mechanism has matured significantly (don't be put off
+  by all the struct typedefs in DBIXS.h, there's just to make it
+  easier for drivers while keeping things type-safe).
+
+  The DBI now includes two new methods:
+
+  do		$dbh->do($statement)
+
+  This method prepares, executes and finishes a statement. It is
+  designed to be used for executing one-off non-select statements
+  where there is no benefit in reusing a prepared statement handle.
+
+  fetch		$array_ref = $sth->fetch;
+
+  This method is the new 'lowest-level' row fetching method. The
+  previous @row = $sth->fetchrow method now defaults to calling
+  the fetch method and expanding the returned array reference.
+
+  The DBI now provides fallback attribute FETCH and STORE functions
+  which drivers should call if they don't recognise an attribute.
+
+  THIS RELEASE IS A GOOD STARTING POINT FOR DRIVER DEVELOPERS!
+  Study DBIXS.h from the DBI and Oracle.xs etc from DBD::Oracle.
+  There will be further changes in the interface but nothing
+  as dramatic as these last two releases! (I hope :-)
+
+
+=head2 Changes in DBI 0.59	15 Aug 1995
+
+  NOTE: THIS IS AN UNSTABLE RELEASE!
+
+  Major reworking of internal data management!
+  Performance improvements and memory leaks fixed.
+  Added a new NullP (empty) driver and a -m flag
+  to test.pl to help check for memory leaks.
+  Study DBD::Oracle version 0.21 for more details.
+  (Comparing parts of v0.21 with v0.20 may be useful.)
+
+
+=head2 Changes in DBI 0.58	21 June 1995
+
+  Added DBI->internal->{DebugLog} = $filename;
+  Reworked internal logging.
+  Added $VERSION.
+  Made disconnect_all a compulsary method for drivers.
+
+
+=head1 ANCIENT HISTORY
+
+12th Oct 1994: First public release of the DBI module.
+               (for Perl 5.000-beta-3h)
+
+19th Sep 1994: DBperl project renamed to DBI.
+
+29th Sep 1992: DBperl project started.
+
+=cut
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/Const/GetInfo/ANSI.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/Const/GetInfo/ANSI.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/Const/GetInfo/ANSI.pm	(revision 14139)
@@ -0,0 +1,235 @@
+# $Id$
+#
+# Copyright (c) 2002  Tim Bunce  Ireland
+#
+# Constant data describing ANSI CLI info types and return values for the
+# SQLGetInfo() method of ODBC.
+#
+# You may distribute under the terms of either the GNU General Public
+# License or the Artistic License, as specified in the Perl README file.
+
+package DBI::Const::GetInfo::ANSI;
+
+=head1 NAME
+
+DBI::Const::GetInfo::ANSI - ISO/IEC SQL/CLI Constants for GetInfo
+
+=head1 SYNOPSIS
+
+  The API for this module is private and subject to change.
+
+=head1 DESCRIPTION
+
+Information requested by GetInfo().
+
+See: A.1 C header file SQLCLI.H, Page 316, 317.
+
+The API for this module is private and subject to change.
+
+=head1 REFERENCES
+
+  ISO/IEC FCD 9075-3:200x Information technology - Database Languages -
+  SQL - Part 3: Call-Level Interface (SQL/CLI)
+
+  SC32 N00744 = WG3:VIE-005 = H2-2002-007
+
+  Date: 2002-01-15
+
+=cut
+
+my
+$VERSION = sprintf "%d.%02d", '$Revision$ ' =~ /(\d+)\.(\d+)/;
+
+%InfoTypes =
+(
+  SQL_ALTER_TABLE                     =>      86
+, SQL_CATALOG_NAME                    =>   10003
+, SQL_COLLATING_SEQUENCE              =>   10004
+, SQL_CURSOR_COMMIT_BEHAVIOR          =>      23
+, SQL_CURSOR_SENSITIVITY              =>   10001
+, SQL_DATA_SOURCE_NAME                =>       2
+, SQL_DATA_SOURCE_READ_ONLY           =>      25
+, SQL_DBMS_NAME                       =>      17
+, SQL_DBMS_VERSION                    =>      18
+, SQL_DEFAULT_TRANSACTION_ISOLATION   =>      26
+, SQL_DESCRIBE_PARAMETER              =>   10002
+, SQL_FETCH_DIRECTION                 =>       8
+, SQL_GETDATA_EXTENSIONS              =>      81
+, SQL_IDENTIFIER_CASE                 =>      28
+, SQL_INTEGRITY                       =>      73
+, SQL_MAXIMUM_CATALOG_NAME_LENGTH     =>      34
+, SQL_MAXIMUM_COLUMNS_IN_GROUP_BY     =>      97
+, SQL_MAXIMUM_COLUMNS_IN_ORDER_BY     =>      99
+, SQL_MAXIMUM_COLUMNS_IN_SELECT       =>     100
+, SQL_MAXIMUM_COLUMNS_IN_TABLE        =>     101
+, SQL_MAXIMUM_COLUMN_NAME_LENGTH      =>      30
+, SQL_MAXIMUM_CONCURRENT_ACTIVITIES   =>       1
+, SQL_MAXIMUM_CURSOR_NAME_LENGTH      =>      31
+, SQL_MAXIMUM_DRIVER_CONNECTIONS      =>       0
+, SQL_MAXIMUM_IDENTIFIER_LENGTH       =>   10005
+, SQL_MAXIMUM_SCHEMA_NAME_LENGTH      =>      32
+, SQL_MAXIMUM_STMT_OCTETS             =>   20000
+, SQL_MAXIMUM_STMT_OCTETS_DATA        =>   20001
+, SQL_MAXIMUM_STMT_OCTETS_SCHEMA      =>   20002
+, SQL_MAXIMUM_TABLES_IN_SELECT        =>     106
+, SQL_MAXIMUM_TABLE_NAME_LENGTH       =>      35
+, SQL_MAXIMUM_USER_NAME_LENGTH        =>     107
+, SQL_NULL_COLLATION                  =>      85
+, SQL_ORDER_BY_COLUMNS_IN_SELECT      =>      90
+, SQL_OUTER_JOIN_CAPABILITIES         =>     115
+, SQL_SCROLL_CONCURRENCY              =>      43
+, SQL_SEARCH_PATTERN_ESCAPE           =>      14
+, SQL_SERVER_NAME                     =>      13
+, SQL_SPECIAL_CHARACTERS              =>      94
+, SQL_TRANSACTION_CAPABLE             =>      46
+, SQL_TRANSACTION_ISOLATION_OPTION    =>      72
+, SQL_USER_NAME                       =>      47
+);
+
+=head2 %ReturnTypes
+
+See: Codes and data types for implementation information (Table 28), Page 85, 86.
+
+Mapped to ODBC datatype names.
+
+=cut
+
+%ReturnTypes =                                                 #          maxlen
+(
+  SQL_ALTER_TABLE                     => 'SQLUINTEGER bitmask' # INTEGER
+, SQL_CATALOG_NAME                    => 'SQLCHAR'             # CHARACTER   (1)
+, SQL_COLLATING_SEQUENCE              => 'SQLCHAR'             # CHARACTER (254)
+, SQL_CURSOR_COMMIT_BEHAVIOR          => 'SQLUSMALLINT'        # SMALLINT
+, SQL_CURSOR_SENSITIVITY              => 'SQLUINTEGER'         # INTEGER
+, SQL_DATA_SOURCE_NAME                => 'SQLCHAR'             # CHARACTER (128)
+, SQL_DATA_SOURCE_READ_ONLY           => 'SQLCHAR'             # CHARACTER   (1)
+, SQL_DBMS_NAME                       => 'SQLCHAR'             # CHARACTER (254)
+, SQL_DBMS_VERSION                    => 'SQLCHAR'             # CHARACTER (254)
+, SQL_DEFAULT_TRANSACTION_ISOLATION   => 'SQLUINTEGER'         # INTEGER
+, SQL_DESCRIBE_PARAMETER              => 'SQLCHAR'             # CHARACTER   (1)
+, SQL_FETCH_DIRECTION                 => 'SQLUINTEGER bitmask' # INTEGER
+, SQL_GETDATA_EXTENSIONS              => 'SQLUINTEGER bitmask' # INTEGER
+, SQL_IDENTIFIER_CASE                 => 'SQLUSMALLINT'        # SMALLINT
+, SQL_INTEGRITY                       => 'SQLCHAR'             # CHARACTER   (1)
+, SQL_MAXIMUM_CATALOG_NAME_LENGTH     => 'SQLUSMALLINT'        # SMALLINT
+, SQL_MAXIMUM_COLUMNS_IN_GROUP_BY     => 'SQLUSMALLINT'        # SMALLINT
+, SQL_MAXIMUM_COLUMNS_IN_ORDER_BY     => 'SQLUSMALLINT'        # SMALLINT
+, SQL_MAXIMUM_COLUMNS_IN_SELECT       => 'SQLUSMALLINT'        # SMALLINT
+, SQL_MAXIMUM_COLUMNS_IN_TABLE        => 'SQLUSMALLINT'        # SMALLINT
+, SQL_MAXIMUM_COLUMN_NAME_LENGTH      => 'SQLUSMALLINT'        # SMALLINT
+, SQL_MAXIMUM_CONCURRENT_ACTIVITIES   => 'SQLUSMALLINT'        # SMALLINT
+, SQL_MAXIMUM_CURSOR_NAME_LENGTH      => 'SQLUSMALLINT'        # SMALLINT
+, SQL_MAXIMUM_DRIVER_CONNECTIONS      => 'SQLUSMALLINT'        # SMALLINT
+, SQL_MAXIMUM_IDENTIFIER_LENGTH       => 'SQLUSMALLINT'        # SMALLINT
+, SQL_MAXIMUM_SCHEMA_NAME_LENGTH      => 'SQLUSMALLINT'        # SMALLINT
+, SQL_MAXIMUM_STMT_OCTETS             => 'SQLUSMALLINT'        # SMALLINT
+, SQL_MAXIMUM_STMT_OCTETS_DATA        => 'SQLUSMALLINT'        # SMALLINT
+, SQL_MAXIMUM_STMT_OCTETS_SCHEMA      => 'SQLUSMALLINT'        # SMALLINT
+, SQL_MAXIMUM_TABLES_IN_SELECT        => 'SQLUSMALLINT'        # SMALLINT
+, SQL_MAXIMUM_TABLE_NAME_LENGTH       => 'SQLUSMALLINT'        # SMALLINT
+, SQL_MAXIMUM_USER_NAME_LENGTH        => 'SQLUSMALLINT'        # SMALLINT
+, SQL_NULL_COLLATION                  => 'SQLUSMALLINT'        # SMALLINT
+, SQL_ORDER_BY_COLUMNS_IN_SELECT      => 'SQLCHAR'             # CHARACTER   (1)
+, SQL_OUTER_JOIN_CAPABILITIES         => 'SQLUINTEGER bitmask' # INTEGER
+, SQL_SCROLL_CONCURRENCY              => 'SQLUINTEGER bitmask' # INTEGER
+, SQL_SEARCH_PATTERN_ESCAPE           => 'SQLCHAR'             # CHARACTER   (1)
+, SQL_SERVER_NAME                     => 'SQLCHAR'             # CHARACTER (128)
+, SQL_SPECIAL_CHARACTERS              => 'SQLCHAR'             # CHARACTER (254)
+, SQL_TRANSACTION_CAPABLE             => 'SQLUSMALLINT'        # SMALLINT
+, SQL_TRANSACTION_ISOLATION_OPTION    => 'SQLUINTEGER bitmask' # INTEGER
+, SQL_USER_NAME                       => 'SQLCHAR'             # CHARACTER (128)
+);
+
+=head2 %ReturnValues
+
+See: A.1 C header file SQLCLI.H, Page 317, 318.
+
+=cut
+
+$ReturnValues{SQL_ALTER_TABLE} =
+{
+  SQL_AT_ADD_COLUMN                         => 0x00000001
+, SQL_AT_DROP_COLUMN                        => 0x00000002
+, SQL_AT_ALTER_COLUMN                       => 0x00000004
+, SQL_AT_ADD_CONSTRAINT                     => 0x00000008
+, SQL_AT_DROP_CONSTRAINT                    => 0x00000010
+};
+$ReturnValues{SQL_CURSOR_COMMIT_BEHAVIOR} =
+{
+  SQL_CB_DELETE                             => 0
+, SQL_CB_CLOSE                              => 1
+, SQL_CB_PRESERVE                           => 2
+};
+$ReturnValues{SQL_FETCH_DIRECTION} =
+{
+  SQL_FD_FETCH_NEXT                         => 0x00000001
+, SQL_FD_FETCH_FIRST                        => 0x00000002
+, SQL_FD_FETCH_LAST                         => 0x00000004
+, SQL_FD_FETCH_PRIOR                        => 0x00000008
+, SQL_FD_FETCH_ABSOLUTE                     => 0x00000010
+, SQL_FD_FETCH_RELATIVE                     => 0x00000020
+};
+$ReturnValues{SQL_GETDATA_EXTENSIONS} =
+{
+  SQL_GD_ANY_COLUMN                         => 0x00000001
+, SQL_GD_ANY_ORDER                          => 0x00000002
+};
+$ReturnValues{SQL_IDENTIFIER_CASE} =
+{
+  SQL_IC_UPPER                              => 1
+, SQL_IC_LOWER                              => 2
+, SQL_IC_SENSITIVE                          => 3
+, SQL_IC_MIXED                              => 4
+};
+$ReturnValues{SQL_NULL_COLLATION} =
+{
+  SQL_NC_HIGH                               => 1
+, SQL_NC_LOW                                => 2
+};
+$ReturnValues{SQL_OUTER_JOIN_CAPABILITIES} =
+{
+  SQL_OUTER_JOIN_LEFT                       => 0x00000001
+, SQL_OUTER_JOIN_RIGHT                      => 0x00000002
+, SQL_OUTER_JOIN_FULL                       => 0x00000004
+, SQL_OUTER_JOIN_NESTED                     => 0x00000008
+, SQL_OUTER_JOIN_NOT_ORDERED                => 0x00000010
+, SQL_OUTER_JOIN_INNER                      => 0x00000020
+, SQL_OUTER_JOIN_ALL_COMPARISON_OPS         => 0x00000040
+};
+$ReturnValues{SQL_SCROLL_CONCURRENCY} =
+{
+  SQL_SCCO_READ_ONLY                        => 0x00000001
+, SQL_SCCO_LOCK                             => 0x00000002
+, SQL_SCCO_OPT_ROWVER                       => 0x00000004
+, SQL_SCCO_OPT_VALUES                       => 0x00000008
+};
+$ReturnValues{SQL_TRANSACTION_ACCESS_MODE} =
+{
+  SQL_TRANSACTION_READ_ONLY                 => 0x00000001
+, SQL_TRANSACTION_READ_WRITE                => 0x00000002
+};
+$ReturnValues{SQL_TRANSACTION_CAPABLE} =
+{
+  SQL_TC_NONE                               => 0
+, SQL_TC_DML                                => 1
+, SQL_TC_ALL                                => 2
+, SQL_TC_DDL_COMMIT                         => 3
+, SQL_TC_DDL_IGNORE                         => 4
+};
+$ReturnValues{SQL_TRANSACTION_ISOLATION} =
+{
+  SQL_TRANSACTION_READ_UNCOMMITTED          => 0x00000001
+, SQL_TRANSACTION_READ_COMMITTED            => 0x00000002
+, SQL_TRANSACTION_REPEATABLE_READ           => 0x00000004
+, SQL_TRANSACTION_SERIALIZABLE              => 0x00000008
+};
+
+1;
+
+=head1 TODO
+
+Corrections, e.g.:
+
+  SQL_TRANSACTION_ISOLATION_OPTION vs. SQL_TRANSACTION_ISOLATION
+
+=cut
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/Const/GetInfo/ODBC.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/Const/GetInfo/ODBC.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/Const/GetInfo/ODBC.pm	(revision 14139)
@@ -0,0 +1,1365 @@
+# $Id$
+#
+# Copyright (c) 2002  Tim Bunce  Ireland
+#
+# Constant data describing Microsoft ODBC info types and return values
+# for the SQLGetInfo() method of ODBC.
+#
+# You may distribute under the terms of either the GNU General Public
+# License or the Artistic License, as specified in the Perl README file.
+
+package DBI::Const::GetInfo::ODBC;
+
+=head1 NAME
+
+DBI::Const::GetInfo::ODBC - ODBC Constants for GetInfo
+
+=head1 SYNOPSIS
+
+ The API for this module is private and subject to change.
+
+=head1 DESCRIPTION
+
+Information requested by GetInfo().
+
+The API for this module is private and subject to change.   
+
+=head1 REFERENCES
+
+  MDAC SDK 2.6
+  ODBC version number (0x0351)
+
+  sql.h
+  sqlext.h
+
+=cut
+
+my
+$VERSION = sprintf "%d.%02d", '$Revision$ ' =~ /(\d+)\.(\d+)/;
+
+%InfoTypes =
+(
+  SQL_ACCESSIBLE_PROCEDURES           =>    20
+, SQL_ACCESSIBLE_TABLES               =>    19
+, SQL_ACTIVE_CONNECTIONS              =>     0
+, SQL_ACTIVE_ENVIRONMENTS             =>   116
+, SQL_ACTIVE_STATEMENTS               =>     1
+, SQL_AGGREGATE_FUNCTIONS             =>   169
+, SQL_ALTER_DOMAIN                    =>   117
+, SQL_ALTER_TABLE                     =>    86
+, SQL_ASYNC_MODE                      => 10021
+, SQL_BATCH_ROW_COUNT                 =>   120
+, SQL_BATCH_SUPPORT                   =>   121
+, SQL_BOOKMARK_PERSISTENCE            =>    82
+, SQL_CATALOG_LOCATION                =>   114  # SQL_QUALIFIER_LOCATION
+, SQL_CATALOG_NAME                    => 10003
+, SQL_CATALOG_NAME_SEPARATOR          =>    41  # SQL_QUALIFIER_NAME_SEPARATOR
+, SQL_CATALOG_TERM                    =>    42  # SQL_QUALIFIER_TERM
+, SQL_CATALOG_USAGE                   =>    92  # SQL_QUALIFIER_USAGE
+, SQL_COLLATION_SEQ                   => 10004
+, SQL_COLUMN_ALIAS                    =>    87
+, SQL_CONCAT_NULL_BEHAVIOR            =>    22
+, SQL_CONVERT_BIGINT                  =>    53
+, SQL_CONVERT_BINARY                  =>    54
+, SQL_CONVERT_BIT                     =>    55
+, SQL_CONVERT_CHAR                    =>    56
+, SQL_CONVERT_DATE                    =>    57
+, SQL_CONVERT_DECIMAL                 =>    58
+, SQL_CONVERT_DOUBLE                  =>    59
+, SQL_CONVERT_FLOAT                   =>    60
+, SQL_CONVERT_FUNCTIONS               =>    48
+, SQL_CONVERT_GUID                    =>   173
+, SQL_CONVERT_INTEGER                 =>    61
+, SQL_CONVERT_INTERVAL_DAY_TIME       =>   123
+, SQL_CONVERT_INTERVAL_YEAR_MONTH     =>   124
+, SQL_CONVERT_LONGVARBINARY           =>    71
+, SQL_CONVERT_LONGVARCHAR             =>    62
+, SQL_CONVERT_NUMERIC                 =>    63
+, SQL_CONVERT_REAL                    =>    64
+, SQL_CONVERT_SMALLINT                =>    65
+, SQL_CONVERT_TIME                    =>    66
+, SQL_CONVERT_TIMESTAMP               =>    67
+, SQL_CONVERT_TINYINT                 =>    68
+, SQL_CONVERT_VARBINARY               =>    69
+, SQL_CONVERT_VARCHAR                 =>    70
+, SQL_CONVERT_WCHAR                   =>   122
+, SQL_CONVERT_WLONGVARCHAR            =>   125
+, SQL_CONVERT_WVARCHAR                =>   126
+, SQL_CORRELATION_NAME                =>    74
+, SQL_CREATE_ASSERTION                =>   127
+, SQL_CREATE_CHARACTER_SET            =>   128
+, SQL_CREATE_COLLATION                =>   129
+, SQL_CREATE_DOMAIN                   =>   130
+, SQL_CREATE_SCHEMA                   =>   131
+, SQL_CREATE_TABLE                    =>   132
+, SQL_CREATE_TRANSLATION              =>   133
+, SQL_CREATE_VIEW                     =>   134
+, SQL_CURSOR_COMMIT_BEHAVIOR          =>    23
+, SQL_CURSOR_ROLLBACK_BEHAVIOR        =>    24
+, SQL_CURSOR_SENSITIVITY              => 10001
+, SQL_DATA_SOURCE_NAME                =>     2
+, SQL_DATA_SOURCE_READ_ONLY           =>    25
+, SQL_DATABASE_NAME                   =>    16 
+, SQL_DATETIME_LITERALS               =>   119
+, SQL_DBMS_NAME                       =>    17
+, SQL_DBMS_VER                        =>    18
+, SQL_DDL_INDEX                       =>   170
+, SQL_DEFAULT_TXN_ISOLATION           =>    26
+, SQL_DESCRIBE_PARAMETER              => 10002
+, SQL_DM_VER                          =>   171
+, SQL_DRIVER_HDBC                     =>     3
+, SQL_DRIVER_HDESC                    =>   135
+, SQL_DRIVER_HENV                     =>     4
+, SQL_DRIVER_HLIB                     =>    76
+, SQL_DRIVER_HSTMT                    =>     5
+, SQL_DRIVER_NAME                     =>     6
+, SQL_DRIVER_ODBC_VER                 =>    77
+, SQL_DRIVER_VER                      =>     7
+, SQL_DROP_ASSERTION                  =>   136
+, SQL_DROP_CHARACTER_SET              =>   137
+, SQL_DROP_COLLATION                  =>   138
+, SQL_DROP_DOMAIN                     =>   139
+, SQL_DROP_SCHEMA                     =>   140
+, SQL_DROP_TABLE                      =>   141
+, SQL_DROP_TRANSLATION                =>   142
+, SQL_DROP_VIEW                       =>   143
+, SQL_DYNAMIC_CURSOR_ATTRIBUTES1      =>   144
+, SQL_DYNAMIC_CURSOR_ATTRIBUTES2      =>   145
+, SQL_EXPRESSIONS_IN_ORDERBY          =>    27
+, SQL_FETCH_DIRECTION                 =>     8
+, SQL_FILE_USAGE                      =>    84
+, SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1 =>   146
+, SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2 =>   147
+, SQL_GETDATA_EXTENSIONS              =>    81
+, SQL_GROUP_BY                        =>    88
+, SQL_IDENTIFIER_CASE                 =>    28
+, SQL_IDENTIFIER_QUOTE_CHAR           =>    29
+, SQL_INDEX_KEYWORDS                  =>   148
+# SQL_INFO_DRIVER_START               =>  1000
+# SQL_INFO_FIRST                      =>     0
+# SQL_INFO_LAST                       =>   114  # SQL_QUALIFIER_LOCATION
+, SQL_INFO_SCHEMA_VIEWS               =>   149
+, SQL_INSERT_STATEMENT                =>   172
+, SQL_INTEGRITY                       =>    73
+, SQL_KEYSET_CURSOR_ATTRIBUTES1       =>   150
+, SQL_KEYSET_CURSOR_ATTRIBUTES2       =>   151
+, SQL_KEYWORDS                        =>    89
+, SQL_LIKE_ESCAPE_CLAUSE              =>   113
+, SQL_LOCK_TYPES                      =>    78
+, SQL_MAXIMUM_CATALOG_NAME_LENGTH     =>    34  # SQL_MAX_CATALOG_NAME_LEN
+, SQL_MAXIMUM_COLUMNS_IN_GROUP_BY     =>    97  # SQL_MAX_COLUMNS_IN_GROUP_BY
+, SQL_MAXIMUM_COLUMNS_IN_INDEX        =>    98  # SQL_MAX_COLUMNS_IN_INDEX
+, SQL_MAXIMUM_COLUMNS_IN_ORDER_BY     =>    99  # SQL_MAX_COLUMNS_IN_ORDER_BY
+, SQL_MAXIMUM_COLUMNS_IN_SELECT       =>   100  # SQL_MAX_COLUMNS_IN_SELECT
+, SQL_MAXIMUM_COLUMN_NAME_LENGTH      =>    30  # SQL_MAX_COLUMN_NAME_LEN
+, SQL_MAXIMUM_CONCURRENT_ACTIVITIES   =>     1  # SQL_MAX_CONCURRENT_ACTIVITIES
+, SQL_MAXIMUM_CURSOR_NAME_LENGTH      =>    31  # SQL_MAX_CURSOR_NAME_LEN
+, SQL_MAXIMUM_DRIVER_CONNECTIONS      =>     0  # SQL_MAX_DRIVER_CONNECTIONS
+, SQL_MAXIMUM_IDENTIFIER_LENGTH       => 10005  # SQL_MAX_IDENTIFIER_LEN
+, SQL_MAXIMUM_INDEX_SIZE              =>   102  # SQL_MAX_INDEX_SIZE
+, SQL_MAXIMUM_ROW_SIZE                =>   104  # SQL_MAX_ROW_SIZE
+, SQL_MAXIMUM_SCHEMA_NAME_LENGTH      =>    32  # SQL_MAX_SCHEMA_NAME_LEN
+, SQL_MAXIMUM_STATEMENT_LENGTH        =>   105  # SQL_MAX_STATEMENT_LEN
+, SQL_MAXIMUM_TABLES_IN_SELECT        =>   106  # SQL_MAX_TABLES_IN_SELECT
+, SQL_MAXIMUM_USER_NAME_LENGTH        =>   107  # SQL_MAX_USER_NAME_LEN
+, SQL_MAX_ASYNC_CONCURRENT_STATEMENTS => 10022
+, SQL_MAX_BINARY_LITERAL_LEN          =>   112
+, SQL_MAX_CATALOG_NAME_LEN            =>    34
+, SQL_MAX_CHAR_LITERAL_LEN            =>   108
+, SQL_MAX_COLUMNS_IN_GROUP_BY         =>    97
+, SQL_MAX_COLUMNS_IN_INDEX            =>    98
+, SQL_MAX_COLUMNS_IN_ORDER_BY         =>    99
+, SQL_MAX_COLUMNS_IN_SELECT           =>   100
+, SQL_MAX_COLUMNS_IN_TABLE            =>   101
+, SQL_MAX_COLUMN_NAME_LEN             =>    30
+, SQL_MAX_CONCURRENT_ACTIVITIES       =>     1
+, SQL_MAX_CURSOR_NAME_LEN             =>    31
+, SQL_MAX_DRIVER_CONNECTIONS          =>     0
+, SQL_MAX_IDENTIFIER_LEN              => 10005
+, SQL_MAX_INDEX_SIZE                  =>   102
+, SQL_MAX_OWNER_NAME_LEN              =>    32
+, SQL_MAX_PROCEDURE_NAME_LEN          =>    33
+, SQL_MAX_QUALIFIER_NAME_LEN          =>    34
+, SQL_MAX_ROW_SIZE                    =>   104
+, SQL_MAX_ROW_SIZE_INCLUDES_LONG      =>   103
+, SQL_MAX_SCHEMA_NAME_LEN             =>    32
+, SQL_MAX_STATEMENT_LEN               =>   105
+, SQL_MAX_TABLES_IN_SELECT            =>   106
+, SQL_MAX_TABLE_NAME_LEN              =>    35
+, SQL_MAX_USER_NAME_LEN               =>   107
+, SQL_MULTIPLE_ACTIVE_TXN             =>    37
+, SQL_MULT_RESULT_SETS                =>    36
+, SQL_NEED_LONG_DATA_LEN              =>   111
+, SQL_NON_NULLABLE_COLUMNS            =>    75
+, SQL_NULL_COLLATION                  =>    85
+, SQL_NUMERIC_FUNCTIONS               =>    49
+, SQL_ODBC_API_CONFORMANCE            =>     9
+, SQL_ODBC_INTERFACE_CONFORMANCE      =>   152
+, SQL_ODBC_SAG_CLI_CONFORMANCE        =>    12
+, SQL_ODBC_SQL_CONFORMANCE            =>    15
+, SQL_ODBC_SQL_OPT_IEF                =>    73
+, SQL_ODBC_VER                        =>    10
+, SQL_OJ_CAPABILITIES                 =>   115
+, SQL_ORDER_BY_COLUMNS_IN_SELECT      =>    90
+, SQL_OUTER_JOINS                     =>    38
+, SQL_OUTER_JOIN_CAPABILITIES         =>   115  # SQL_OJ_CAPABILITIES
+, SQL_OWNER_TERM                      =>    39
+, SQL_OWNER_USAGE                     =>    91
+, SQL_PARAM_ARRAY_ROW_COUNTS          =>   153
+, SQL_PARAM_ARRAY_SELECTS             =>   154
+, SQL_POSITIONED_STATEMENTS           =>    80
+, SQL_POS_OPERATIONS                  =>    79
+, SQL_PROCEDURES                      =>    21
+, SQL_PROCEDURE_TERM                  =>    40
+, SQL_QUALIFIER_LOCATION              =>   114
+, SQL_QUALIFIER_NAME_SEPARATOR        =>    41
+, SQL_QUALIFIER_TERM                  =>    42
+, SQL_QUALIFIER_USAGE                 =>    92
+, SQL_QUOTED_IDENTIFIER_CASE          =>    93
+, SQL_ROW_UPDATES                     =>    11
+, SQL_SCHEMA_TERM                     =>    39  # SQL_OWNER_TERM
+, SQL_SCHEMA_USAGE                    =>    91  # SQL_OWNER_USAGE
+, SQL_SCROLL_CONCURRENCY              =>    43
+, SQL_SCROLL_OPTIONS                  =>    44
+, SQL_SEARCH_PATTERN_ESCAPE           =>    14
+, SQL_SERVER_NAME                     =>    13
+, SQL_SPECIAL_CHARACTERS              =>    94
+, SQL_SQL92_DATETIME_FUNCTIONS        =>   155
+, SQL_SQL92_FOREIGN_KEY_DELETE_RULE   =>   156
+, SQL_SQL92_FOREIGN_KEY_UPDATE_RULE   =>   157
+, SQL_SQL92_GRANT                     =>   158
+, SQL_SQL92_NUMERIC_VALUE_FUNCTIONS   =>   159
+, SQL_SQL92_PREDICATES                =>   160
+, SQL_SQL92_RELATIONAL_JOIN_OPERATORS =>   161
+, SQL_SQL92_REVOKE                    =>   162
+, SQL_SQL92_ROW_VALUE_CONSTRUCTOR     =>   163
+, SQL_SQL92_STRING_FUNCTIONS          =>   164
+, SQL_SQL92_VALUE_EXPRESSIONS         =>   165
+, SQL_SQL_CONFORMANCE                 =>   118
+, SQL_STANDARD_CLI_CONFORMANCE        =>   166
+, SQL_STATIC_CURSOR_ATTRIBUTES1       =>   167
+, SQL_STATIC_CURSOR_ATTRIBUTES2       =>   168
+, SQL_STATIC_SENSITIVITY              =>    83
+, SQL_STRING_FUNCTIONS                =>    50
+, SQL_SUBQUERIES                      =>    95
+, SQL_SYSTEM_FUNCTIONS                =>    51
+, SQL_TABLE_TERM                      =>    45
+, SQL_TIMEDATE_ADD_INTERVALS          =>   109
+, SQL_TIMEDATE_DIFF_INTERVALS         =>   110
+, SQL_TIMEDATE_FUNCTIONS              =>    52
+, SQL_TRANSACTION_CAPABLE             =>    46  # SQL_TXN_CAPABLE
+, SQL_TRANSACTION_ISOLATION_OPTION    =>    72  # SQL_TXN_ISOLATION_OPTION
+, SQL_TXN_CAPABLE                     =>    46
+, SQL_TXN_ISOLATION_OPTION            =>    72
+, SQL_UNION                           =>    96
+, SQL_UNION_STATEMENT                 =>    96  # SQL_UNION
+, SQL_USER_NAME                       =>    47
+, SQL_XOPEN_CLI_YEAR                  => 10000
+);
+
+=head2 %ReturnTypes
+
+See: mk:@MSITStore:X:\dm\cli\mdac\sdk26\Docs\odbc.chm::/htm/odbcsqlgetinfo.htm
+
+  =>     : alias
+  => !!! : edited
+
+=cut
+
+%ReturnTypes =
+(
+  SQL_ACCESSIBLE_PROCEDURES           => 'SQLCHAR'             #    20
+, SQL_ACCESSIBLE_TABLES               => 'SQLCHAR'             #    19
+, SQL_ACTIVE_CONNECTIONS              => 'SQLUSMALLINT'        #     0  =>
+, SQL_ACTIVE_ENVIRONMENTS             => 'SQLUSMALLINT'        #   116
+, SQL_ACTIVE_STATEMENTS               => 'SQLUSMALLINT'        #     1  =>
+, SQL_AGGREGATE_FUNCTIONS             => 'SQLUINTEGER bitmask' #   169
+, SQL_ALTER_DOMAIN                    => 'SQLUINTEGER bitmask' #   117
+, SQL_ALTER_TABLE                     => 'SQLUINTEGER bitmask' #    86
+, SQL_ASYNC_MODE                      => 'SQLUINTEGER'         # 10021
+, SQL_BATCH_ROW_COUNT                 => 'SQLUINTEGER bitmask' #   120
+, SQL_BATCH_SUPPORT                   => 'SQLUINTEGER bitmask' #   121
+, SQL_BOOKMARK_PERSISTENCE            => 'SQLUINTEGER bitmask' #    82
+, SQL_CATALOG_LOCATION                => 'SQLUSMALLINT'        #   114
+, SQL_CATALOG_NAME                    => 'SQLCHAR'             # 10003
+, SQL_CATALOG_NAME_SEPARATOR          => 'SQLCHAR'             #    41
+, SQL_CATALOG_TERM                    => 'SQLCHAR'             #    42
+, SQL_CATALOG_USAGE                   => 'SQLUINTEGER bitmask' #    92
+, SQL_COLLATION_SEQ                   => 'SQLCHAR'             # 10004
+, SQL_COLUMN_ALIAS                    => 'SQLCHAR'             #    87
+, SQL_CONCAT_NULL_BEHAVIOR            => 'SQLUSMALLINT'        #    22
+, SQL_CONVERT_BIGINT                  => 'SQLUINTEGER bitmask' #    53
+, SQL_CONVERT_BINARY                  => 'SQLUINTEGER bitmask' #    54
+, SQL_CONVERT_BIT                     => 'SQLUINTEGER bitmask' #    55
+, SQL_CONVERT_CHAR                    => 'SQLUINTEGER bitmask' #    56
+, SQL_CONVERT_DATE                    => 'SQLUINTEGER bitmask' #    57
+, SQL_CONVERT_DECIMAL                 => 'SQLUINTEGER bitmask' #    58
+, SQL_CONVERT_DOUBLE                  => 'SQLUINTEGER bitmask' #    59
+, SQL_CONVERT_FLOAT                   => 'SQLUINTEGER bitmask' #    60
+, SQL_CONVERT_FUNCTIONS               => 'SQLUINTEGER bitmask' #    48
+, SQL_CONVERT_GUID                    => 'SQLUINTEGER bitmask' #   173
+, SQL_CONVERT_INTEGER                 => 'SQLUINTEGER bitmask' #    61
+, SQL_CONVERT_INTERVAL_DAY_TIME       => 'SQLUINTEGER bitmask' #   123
+, SQL_CONVERT_INTERVAL_YEAR_MONTH     => 'SQLUINTEGER bitmask' #   124
+, SQL_CONVERT_LONGVARBINARY           => 'SQLUINTEGER bitmask' #    71
+, SQL_CONVERT_LONGVARCHAR             => 'SQLUINTEGER bitmask' #    62
+, SQL_CONVERT_NUMERIC                 => 'SQLUINTEGER bitmask' #    63
+, SQL_CONVERT_REAL                    => 'SQLUINTEGER bitmask' #    64
+, SQL_CONVERT_SMALLINT                => 'SQLUINTEGER bitmask' #    65
+, SQL_CONVERT_TIME                    => 'SQLUINTEGER bitmask' #    66
+, SQL_CONVERT_TIMESTAMP               => 'SQLUINTEGER bitmask' #    67
+, SQL_CONVERT_TINYINT                 => 'SQLUINTEGER bitmask' #    68
+, SQL_CONVERT_VARBINARY               => 'SQLUINTEGER bitmask' #    69
+, SQL_CONVERT_VARCHAR                 => 'SQLUINTEGER bitmask' #    70
+, SQL_CONVERT_WCHAR                   => 'SQLUINTEGER bitmask' #   122  => !!!
+, SQL_CONVERT_WLONGVARCHAR            => 'SQLUINTEGER bitmask' #   125  => !!!
+, SQL_CONVERT_WVARCHAR                => 'SQLUINTEGER bitmask' #   126  => !!!
+, SQL_CORRELATION_NAME                => 'SQLUSMALLINT'        #    74
+, SQL_CREATE_ASSERTION                => 'SQLUINTEGER bitmask' #   127
+, SQL_CREATE_CHARACTER_SET            => 'SQLUINTEGER bitmask' #   128
+, SQL_CREATE_COLLATION                => 'SQLUINTEGER bitmask' #   129
+, SQL_CREATE_DOMAIN                   => 'SQLUINTEGER bitmask' #   130
+, SQL_CREATE_SCHEMA                   => 'SQLUINTEGER bitmask' #   131
+, SQL_CREATE_TABLE                    => 'SQLUINTEGER bitmask' #   132
+, SQL_CREATE_TRANSLATION              => 'SQLUINTEGER bitmask' #   133
+, SQL_CREATE_VIEW                     => 'SQLUINTEGER bitmask' #   134
+, SQL_CURSOR_COMMIT_BEHAVIOR          => 'SQLUSMALLINT'        #    23
+, SQL_CURSOR_ROLLBACK_BEHAVIOR        => 'SQLUSMALLINT'        #    24
+, SQL_CURSOR_SENSITIVITY              => 'SQLUINTEGER'         # 10001
+, SQL_DATA_SOURCE_NAME                => 'SQLCHAR'             #     2
+, SQL_DATA_SOURCE_READ_ONLY           => 'SQLCHAR'             #    25
+, SQL_DATABASE_NAME                   => 'SQLCHAR'             #    16 
+, SQL_DATETIME_LITERALS               => 'SQLUINTEGER bitmask' #   119
+, SQL_DBMS_NAME                       => 'SQLCHAR'             #    17
+, SQL_DBMS_VER                        => 'SQLCHAR'             #    18
+, SQL_DDL_INDEX                       => 'SQLUINTEGER bitmask' #   170
+, SQL_DEFAULT_TXN_ISOLATION           => 'SQLUINTEGER'         #    26
+, SQL_DESCRIBE_PARAMETER              => 'SQLCHAR'             # 10002
+, SQL_DM_VER                          => 'SQLCHAR'             #   171
+, SQL_DRIVER_HDBC                     => 'SQLUINTEGER'         #     3
+, SQL_DRIVER_HDESC                    => 'SQLUINTEGER'         #   135
+, SQL_DRIVER_HENV                     => 'SQLUINTEGER'         #     4
+, SQL_DRIVER_HLIB                     => 'SQLUINTEGER'         #    76
+, SQL_DRIVER_HSTMT                    => 'SQLUINTEGER'         #     5
+, SQL_DRIVER_NAME                     => 'SQLCHAR'             #     6
+, SQL_DRIVER_ODBC_VER                 => 'SQLCHAR'             #    77
+, SQL_DRIVER_VER                      => 'SQLCHAR'             #     7
+, SQL_DROP_ASSERTION                  => 'SQLUINTEGER bitmask' #   136
+, SQL_DROP_CHARACTER_SET              => 'SQLUINTEGER bitmask' #   137
+, SQL_DROP_COLLATION                  => 'SQLUINTEGER bitmask' #   138
+, SQL_DROP_DOMAIN                     => 'SQLUINTEGER bitmask' #   139
+, SQL_DROP_SCHEMA                     => 'SQLUINTEGER bitmask' #   140
+, SQL_DROP_TABLE                      => 'SQLUINTEGER bitmask' #   141
+, SQL_DROP_TRANSLATION                => 'SQLUINTEGER bitmask' #   142
+, SQL_DROP_VIEW                       => 'SQLUINTEGER bitmask' #   143
+, SQL_DYNAMIC_CURSOR_ATTRIBUTES1      => 'SQLUINTEGER bitmask' #   144
+, SQL_DYNAMIC_CURSOR_ATTRIBUTES2      => 'SQLUINTEGER bitmask' #   145
+, SQL_EXPRESSIONS_IN_ORDERBY          => 'SQLCHAR'             #    27
+, SQL_FETCH_DIRECTION                 => 'SQLUINTEGER bitmask' #     8  => !!!
+, SQL_FILE_USAGE                      => 'SQLUSMALLINT'        #    84
+, SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1 => 'SQLUINTEGER bitmask' #   146
+, SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2 => 'SQLUINTEGER bitmask' #   147
+, SQL_GETDATA_EXTENSIONS              => 'SQLUINTEGER bitmask' #    81
+, SQL_GROUP_BY                        => 'SQLUSMALLINT'        #    88
+, SQL_IDENTIFIER_CASE                 => 'SQLUSMALLINT'        #    28
+, SQL_IDENTIFIER_QUOTE_CHAR           => 'SQLCHAR'             #    29
+, SQL_INDEX_KEYWORDS                  => 'SQLUINTEGER bitmask' #   148
+# SQL_INFO_DRIVER_START               => ''                    #  1000  =>
+# SQL_INFO_FIRST                      => 'SQLUSMALLINT'        #     0  =>
+# SQL_INFO_LAST                       => 'SQLUSMALLINT'        #   114  =>
+, SQL_INFO_SCHEMA_VIEWS               => 'SQLUINTEGER bitmask' #   149
+, SQL_INSERT_STATEMENT                => 'SQLUINTEGER bitmask' #   172
+, SQL_INTEGRITY                       => 'SQLCHAR'             #    73
+, SQL_KEYSET_CURSOR_ATTRIBUTES1       => 'SQLUINTEGER bitmask' #   150
+, SQL_KEYSET_CURSOR_ATTRIBUTES2       => 'SQLUINTEGER bitmask' #   151
+, SQL_KEYWORDS                        => 'SQLCHAR'             #    89
+, SQL_LIKE_ESCAPE_CLAUSE              => 'SQLCHAR'             #   113
+, SQL_LOCK_TYPES                      => 'SQLUINTEGER bitmask' #    78  => !!!
+, SQL_MAXIMUM_CATALOG_NAME_LENGTH     => 'SQLUSMALLINT'        #    34  =>
+, SQL_MAXIMUM_COLUMNS_IN_GROUP_BY     => 'SQLUSMALLINT'        #    97  =>
+, SQL_MAXIMUM_COLUMNS_IN_INDEX        => 'SQLUSMALLINT'        #    98  =>
+, SQL_MAXIMUM_COLUMNS_IN_ORDER_BY     => 'SQLUSMALLINT'        #    99  =>
+, SQL_MAXIMUM_COLUMNS_IN_SELECT       => 'SQLUSMALLINT'        #   100  =>
+, SQL_MAXIMUM_COLUMN_NAME_LENGTH      => 'SQLUSMALLINT'        #    30  =>
+, SQL_MAXIMUM_CONCURRENT_ACTIVITIES   => 'SQLUSMALLINT'        #     1  =>
+, SQL_MAXIMUM_CURSOR_NAME_LENGTH      => 'SQLUSMALLINT'        #    31  =>
+, SQL_MAXIMUM_DRIVER_CONNECTIONS      => 'SQLUSMALLINT'        #     0  =>
+, SQL_MAXIMUM_IDENTIFIER_LENGTH       => 'SQLUSMALLINT'        # 10005  =>
+, SQL_MAXIMUM_INDEX_SIZE              => 'SQLUINTEGER'         #   102  =>
+, SQL_MAXIMUM_ROW_SIZE                => 'SQLUINTEGER'         #   104  =>
+, SQL_MAXIMUM_SCHEMA_NAME_LENGTH      => 'SQLUSMALLINT'        #    32  =>
+, SQL_MAXIMUM_STATEMENT_LENGTH        => 'SQLUINTEGER'         #   105  =>
+, SQL_MAXIMUM_TABLES_IN_SELECT        => 'SQLUSMALLINT'        #   106  =>
+, SQL_MAXIMUM_USER_NAME_LENGTH        => 'SQLUSMALLINT'        #   107  =>
+, SQL_MAX_ASYNC_CONCURRENT_STATEMENTS => 'SQLUINTEGER'         # 10022
+, SQL_MAX_BINARY_LITERAL_LEN          => 'SQLUINTEGER'         #   112
+, SQL_MAX_CATALOG_NAME_LEN            => 'SQLUSMALLINT'        #    34
+, SQL_MAX_CHAR_LITERAL_LEN            => 'SQLUINTEGER'         #   108
+, SQL_MAX_COLUMNS_IN_GROUP_BY         => 'SQLUSMALLINT'        #    97
+, SQL_MAX_COLUMNS_IN_INDEX            => 'SQLUSMALLINT'        #    98
+, SQL_MAX_COLUMNS_IN_ORDER_BY         => 'SQLUSMALLINT'        #    99
+, SQL_MAX_COLUMNS_IN_SELECT           => 'SQLUSMALLINT'        #   100
+, SQL_MAX_COLUMNS_IN_TABLE            => 'SQLUSMALLINT'        #   101
+, SQL_MAX_COLUMN_NAME_LEN             => 'SQLUSMALLINT'        #    30
+, SQL_MAX_CONCURRENT_ACTIVITIES       => 'SQLUSMALLINT'        #     1
+, SQL_MAX_CURSOR_NAME_LEN             => 'SQLUSMALLINT'        #    31
+, SQL_MAX_DRIVER_CONNECTIONS          => 'SQLUSMALLINT'        #     0
+, SQL_MAX_IDENTIFIER_LEN              => 'SQLUSMALLINT'        # 10005
+, SQL_MAX_INDEX_SIZE                  => 'SQLUINTEGER'         #   102
+, SQL_MAX_OWNER_NAME_LEN              => 'SQLUSMALLINT'        #    32  =>
+, SQL_MAX_PROCEDURE_NAME_LEN          => 'SQLUSMALLINT'        #    33
+, SQL_MAX_QUALIFIER_NAME_LEN          => 'SQLUSMALLINT'        #    34  =>
+, SQL_MAX_ROW_SIZE                    => 'SQLUINTEGER'         #   104
+, SQL_MAX_ROW_SIZE_INCLUDES_LONG      => 'SQLCHAR'             #   103
+, SQL_MAX_SCHEMA_NAME_LEN             => 'SQLUSMALLINT'        #    32
+, SQL_MAX_STATEMENT_LEN               => 'SQLUINTEGER'         #   105
+, SQL_MAX_TABLES_IN_SELECT            => 'SQLUSMALLINT'        #   106
+, SQL_MAX_TABLE_NAME_LEN              => 'SQLUSMALLINT'        #    35
+, SQL_MAX_USER_NAME_LEN               => 'SQLUSMALLINT'        #   107
+, SQL_MULTIPLE_ACTIVE_TXN             => 'SQLCHAR'             #    37
+, SQL_MULT_RESULT_SETS                => 'SQLCHAR'             #    36
+, SQL_NEED_LONG_DATA_LEN              => 'SQLCHAR'             #   111
+, SQL_NON_NULLABLE_COLUMNS            => 'SQLUSMALLINT'        #    75
+, SQL_NULL_COLLATION                  => 'SQLUSMALLINT'        #    85
+, SQL_NUMERIC_FUNCTIONS               => 'SQLUINTEGER bitmask' #    49
+, SQL_ODBC_API_CONFORMANCE            => 'SQLUSMALLINT'        #     9  => !!!
+, SQL_ODBC_INTERFACE_CONFORMANCE      => 'SQLUINTEGER'         #   152
+, SQL_ODBC_SAG_CLI_CONFORMANCE        => 'SQLUSMALLINT'        #    12  => !!!
+, SQL_ODBC_SQL_CONFORMANCE            => 'SQLUSMALLINT'        #    15  => !!!
+, SQL_ODBC_SQL_OPT_IEF                => 'SQLCHAR'             #    73  =>
+, SQL_ODBC_VER                        => 'SQLCHAR'             #    10
+, SQL_OJ_CAPABILITIES                 => 'SQLUINTEGER bitmask' #   115
+, SQL_ORDER_BY_COLUMNS_IN_SELECT      => 'SQLCHAR'             #    90
+, SQL_OUTER_JOINS                     => 'SQLCHAR'             #    38  => !!!
+, SQL_OUTER_JOIN_CAPABILITIES         => 'SQLUINTEGER bitmask' #   115  =>
+, SQL_OWNER_TERM                      => 'SQLCHAR'             #    39  =>
+, SQL_OWNER_USAGE                     => 'SQLUINTEGER bitmask' #    91  =>
+, SQL_PARAM_ARRAY_ROW_COUNTS          => 'SQLUINTEGER'         #   153
+, SQL_PARAM_ARRAY_SELECTS             => 'SQLUINTEGER'         #   154
+, SQL_POSITIONED_STATEMENTS           => 'SQLUINTEGER bitmask' #    80  => !!!
+, SQL_POS_OPERATIONS                  => 'SQLINTEGER bitmask'  #    79
+, SQL_PROCEDURES                      => 'SQLCHAR'             #    21
+, SQL_PROCEDURE_TERM                  => 'SQLCHAR'             #    40
+, SQL_QUALIFIER_LOCATION              => 'SQLUSMALLINT'        #   114  =>
+, SQL_QUALIFIER_NAME_SEPARATOR        => 'SQLCHAR'             #    41  =>
+, SQL_QUALIFIER_TERM                  => 'SQLCHAR'             #    42  =>
+, SQL_QUALIFIER_USAGE                 => 'SQLUINTEGER bitmask' #    92  =>
+, SQL_QUOTED_IDENTIFIER_CASE          => 'SQLUSMALLINT'        #    93
+, SQL_ROW_UPDATES                     => 'SQLCHAR'             #    11
+, SQL_SCHEMA_TERM                     => 'SQLCHAR'             #    39
+, SQL_SCHEMA_USAGE                    => 'SQLUINTEGER bitmask' #    91
+, SQL_SCROLL_CONCURRENCY              => 'SQLUINTEGER bitmask' #    43  => !!!
+, SQL_SCROLL_OPTIONS                  => 'SQLUINTEGER bitmask' #    44
+, SQL_SEARCH_PATTERN_ESCAPE           => 'SQLCHAR'             #    14
+, SQL_SERVER_NAME                     => 'SQLCHAR'             #    13
+, SQL_SPECIAL_CHARACTERS              => 'SQLCHAR'             #    94
+, SQL_SQL92_DATETIME_FUNCTIONS        => 'SQLUINTEGER bitmask' #   155
+, SQL_SQL92_FOREIGN_KEY_DELETE_RULE   => 'SQLUINTEGER bitmask' #   156
+, SQL_SQL92_FOREIGN_KEY_UPDATE_RULE   => 'SQLUINTEGER bitmask' #   157
+, SQL_SQL92_GRANT                     => 'SQLUINTEGER bitmask' #   158
+, SQL_SQL92_NUMERIC_VALUE_FUNCTIONS   => 'SQLUINTEGER bitmask' #   159
+, SQL_SQL92_PREDICATES                => 'SQLUINTEGER bitmask' #   160
+, SQL_SQL92_RELATIONAL_JOIN_OPERATORS => 'SQLUINTEGER bitmask' #   161
+, SQL_SQL92_REVOKE                    => 'SQLUINTEGER bitmask' #   162
+, SQL_SQL92_ROW_VALUE_CONSTRUCTOR     => 'SQLUINTEGER bitmask' #   163
+, SQL_SQL92_STRING_FUNCTIONS          => 'SQLUINTEGER bitmask' #   164
+, SQL_SQL92_VALUE_EXPRESSIONS         => 'SQLUINTEGER bitmask' #   165
+, SQL_SQL_CONFORMANCE                 => 'SQLUINTEGER'         #   118
+, SQL_STANDARD_CLI_CONFORMANCE        => 'SQLUINTEGER bitmask' #   166
+, SQL_STATIC_CURSOR_ATTRIBUTES1       => 'SQLUINTEGER bitmask' #   167
+, SQL_STATIC_CURSOR_ATTRIBUTES2       => 'SQLUINTEGER bitmask' #   168
+, SQL_STATIC_SENSITIVITY              => 'SQLUINTEGER bitmask' #    83  => !!!
+, SQL_STRING_FUNCTIONS                => 'SQLUINTEGER bitmask' #    50
+, SQL_SUBQUERIES                      => 'SQLUINTEGER bitmask' #    95
+, SQL_SYSTEM_FUNCTIONS                => 'SQLUINTEGER bitmask' #    51
+, SQL_TABLE_TERM                      => 'SQLCHAR'             #    45
+, SQL_TIMEDATE_ADD_INTERVALS          => 'SQLUINTEGER bitmask' #   109
+, SQL_TIMEDATE_DIFF_INTERVALS         => 'SQLUINTEGER bitmask' #   110
+, SQL_TIMEDATE_FUNCTIONS              => 'SQLUINTEGER bitmask' #    52
+, SQL_TRANSACTION_CAPABLE             => 'SQLUSMALLINT'        #    46  =>
+, SQL_TRANSACTION_ISOLATION_OPTION    => 'SQLUINTEGER bitmask' #    72  =>
+, SQL_TXN_CAPABLE                     => 'SQLUSMALLINT'        #    46
+, SQL_TXN_ISOLATION_OPTION            => 'SQLUINTEGER bitmask' #    72
+, SQL_UNION                           => 'SQLUINTEGER bitmask' #    96
+, SQL_UNION_STATEMENT                 => 'SQLUINTEGER bitmask' #    96  =>
+, SQL_USER_NAME                       => 'SQLCHAR'             #    47
+, SQL_XOPEN_CLI_YEAR                  => 'SQLCHAR'             # 10000
+);
+
+=head2 %ReturnValues
+
+See: sql.h, sqlext.h
+Edited:
+  SQL_TXN_ISOLATION_OPTION
+
+=cut
+
+$ReturnValues{SQL_AGGREGATE_FUNCTIONS} =
+{
+  SQL_AF_AVG                                => 0x00000001
+, SQL_AF_COUNT                              => 0x00000002
+, SQL_AF_MAX                                => 0x00000004
+, SQL_AF_MIN                                => 0x00000008
+, SQL_AF_SUM                                => 0x00000010
+, SQL_AF_DISTINCT                           => 0x00000020
+, SQL_AF_ALL                                => 0x00000040
+};
+$ReturnValues{SQL_ALTER_DOMAIN} =
+{
+  SQL_AD_CONSTRAINT_NAME_DEFINITION         => 0x00000001
+, SQL_AD_ADD_DOMAIN_CONSTRAINT              => 0x00000002
+, SQL_AD_DROP_DOMAIN_CONSTRAINT             => 0x00000004
+, SQL_AD_ADD_DOMAIN_DEFAULT                 => 0x00000008
+, SQL_AD_DROP_DOMAIN_DEFAULT                => 0x00000010
+, SQL_AD_ADD_CONSTRAINT_INITIALLY_DEFERRED  => 0x00000020
+, SQL_AD_ADD_CONSTRAINT_INITIALLY_IMMEDIATE => 0x00000040
+, SQL_AD_ADD_CONSTRAINT_DEFERRABLE          => 0x00000080
+, SQL_AD_ADD_CONSTRAINT_NON_DEFERRABLE      => 0x00000100
+};
+$ReturnValues{SQL_ALTER_TABLE} =
+{
+  SQL_AT_ADD_COLUMN                         => 0x00000001
+, SQL_AT_DROP_COLUMN                        => 0x00000002
+, SQL_AT_ADD_CONSTRAINT                     => 0x00000008
+, SQL_AT_ADD_COLUMN_SINGLE                  => 0x00000020
+, SQL_AT_ADD_COLUMN_DEFAULT                 => 0x00000040
+, SQL_AT_ADD_COLUMN_COLLATION               => 0x00000080
+, SQL_AT_SET_COLUMN_DEFAULT                 => 0x00000100
+, SQL_AT_DROP_COLUMN_DEFAULT                => 0x00000200
+, SQL_AT_DROP_COLUMN_CASCADE                => 0x00000400
+, SQL_AT_DROP_COLUMN_RESTRICT               => 0x00000800
+, SQL_AT_ADD_TABLE_CONSTRAINT               => 0x00001000
+, SQL_AT_DROP_TABLE_CONSTRAINT_CASCADE      => 0x00002000
+, SQL_AT_DROP_TABLE_CONSTRAINT_RESTRICT     => 0x00004000
+, SQL_AT_CONSTRAINT_NAME_DEFINITION         => 0x00008000
+, SQL_AT_CONSTRAINT_INITIALLY_DEFERRED      => 0x00010000
+, SQL_AT_CONSTRAINT_INITIALLY_IMMEDIATE     => 0x00020000
+, SQL_AT_CONSTRAINT_DEFERRABLE              => 0x00040000
+, SQL_AT_CONSTRAINT_NON_DEFERRABLE          => 0x00080000
+};
+$ReturnValues{SQL_ASYNC_MODE} =
+{
+  SQL_AM_NONE                               => 0
+, SQL_AM_CONNECTION                         => 1
+, SQL_AM_STATEMENT                          => 2
+, SQL_AM_NONE                               => 0
+, SQL_AM_CONNECTION                         => 1
+, SQL_AM_STATEMENT                          => 2
+};
+$ReturnValues{SQL_ATTR_MAX_ROWS} =
+{
+  SQL_CA2_MAX_ROWS_SELECT                   => 0x00000080
+, SQL_CA2_MAX_ROWS_INSERT                   => 0x00000100
+, SQL_CA2_MAX_ROWS_DELETE                   => 0x00000200
+, SQL_CA2_MAX_ROWS_UPDATE                   => 0x00000400
+, SQL_CA2_MAX_ROWS_CATALOG                  => 0x00000800
+# SQL_CA2_MAX_ROWS_AFFECTS_ALL              =>
+};
+$ReturnValues{SQL_ATTR_SCROLL_CONCURRENCY} =
+{
+  SQL_CA2_READ_ONLY_CONCURRENCY             => 0x00000001
+, SQL_CA2_LOCK_CONCURRENCY                  => 0x00000002
+, SQL_CA2_OPT_ROWVER_CONCURRENCY            => 0x00000004
+, SQL_CA2_OPT_VALUES_CONCURRENCY            => 0x00000008
+, SQL_CA2_SENSITIVITY_ADDITIONS             => 0x00000010
+, SQL_CA2_SENSITIVITY_DELETIONS             => 0x00000020
+, SQL_CA2_SENSITIVITY_UPDATES               => 0x00000040
+};
+$ReturnValues{SQL_BATCH_ROW_COUNT} =
+{
+  SQL_BRC_PROCEDURES                        => 0x0000001
+, SQL_BRC_EXPLICIT                          => 0x0000002
+, SQL_BRC_ROLLED_UP                         => 0x0000004
+};
+$ReturnValues{SQL_BATCH_SUPPORT} =
+{
+  SQL_BS_SELECT_EXPLICIT                    => 0x00000001
+, SQL_BS_ROW_COUNT_EXPLICIT                 => 0x00000002
+, SQL_BS_SELECT_PROC                        => 0x00000004
+, SQL_BS_ROW_COUNT_PROC                     => 0x00000008
+};
+$ReturnValues{SQL_BOOKMARK_PERSISTENCE} =
+{
+  SQL_BP_CLOSE                              => 0x00000001
+, SQL_BP_DELETE                             => 0x00000002
+, SQL_BP_DROP                               => 0x00000004
+, SQL_BP_TRANSACTION                        => 0x00000008
+, SQL_BP_UPDATE                             => 0x00000010
+, SQL_BP_OTHER_HSTMT                        => 0x00000020
+, SQL_BP_SCROLL                             => 0x00000040
+};
+$ReturnValues{SQL_CATALOG_LOCATION} =
+{
+  SQL_CL_START                              => 0x0001  # SQL_QL_START
+, SQL_CL_END                                => 0x0002  # SQL_QL_END
+};
+$ReturnValues{SQL_CATALOG_USAGE} =
+{
+  SQL_CU_DML_STATEMENTS                     => 0x00000001  # SQL_QU_DML_STATEMENTS
+, SQL_CU_PROCEDURE_INVOCATION               => 0x00000002  # SQL_QU_PROCEDURE_INVOCATION
+, SQL_CU_TABLE_DEFINITION                   => 0x00000004  # SQL_QU_TABLE_DEFINITION
+, SQL_CU_INDEX_DEFINITION                   => 0x00000008  # SQL_QU_INDEX_DEFINITION
+, SQL_CU_PRIVILEGE_DEFINITION               => 0x00000010  # SQL_QU_PRIVILEGE_DEFINITION
+};
+$ReturnValues{SQL_CONCAT_NULL_BEHAVIOR} =
+{
+  SQL_CB_NULL                               => 0x0000
+, SQL_CB_NON_NULL                           => 0x0001
+};
+$ReturnValues{SQL_CONVERT_} =
+{
+  SQL_CVT_CHAR                              => 0x00000001
+, SQL_CVT_NUMERIC                           => 0x00000002
+, SQL_CVT_DECIMAL                           => 0x00000004
+, SQL_CVT_INTEGER                           => 0x00000008
+, SQL_CVT_SMALLINT                          => 0x00000010
+, SQL_CVT_FLOAT                             => 0x00000020
+, SQL_CVT_REAL                              => 0x00000040
+, SQL_CVT_DOUBLE                            => 0x00000080
+, SQL_CVT_VARCHAR                           => 0x00000100
+, SQL_CVT_LONGVARCHAR                       => 0x00000200
+, SQL_CVT_BINARY                            => 0x00000400
+, SQL_CVT_VARBINARY                         => 0x00000800
+, SQL_CVT_BIT                               => 0x00001000
+, SQL_CVT_TINYINT                           => 0x00002000
+, SQL_CVT_BIGINT                            => 0x00004000
+, SQL_CVT_DATE                              => 0x00008000
+, SQL_CVT_TIME                              => 0x00010000
+, SQL_CVT_TIMESTAMP                         => 0x00020000
+, SQL_CVT_LONGVARBINARY                     => 0x00040000
+, SQL_CVT_INTERVAL_YEAR_MONTH               => 0x00080000
+, SQL_CVT_INTERVAL_DAY_TIME                 => 0x00100000
+, SQL_CVT_WCHAR                             => 0x00200000
+, SQL_CVT_WLONGVARCHAR                      => 0x00400000
+, SQL_CVT_WVARCHAR                          => 0x00800000
+, SQL_CVT_GUID                              => 0x01000000
+};
+$ReturnValues{SQL_CONVERT_BIGINT             } = $ReturnValues{SQL_CONVERT_};
+$ReturnValues{SQL_CONVERT_BINARY             } = $ReturnValues{SQL_CONVERT_};
+$ReturnValues{SQL_CONVERT_BIT                } = $ReturnValues{SQL_CONVERT_};
+$ReturnValues{SQL_CONVERT_CHAR               } = $ReturnValues{SQL_CONVERT_};
+$ReturnValues{SQL_CONVERT_DATE               } = $ReturnValues{SQL_CONVERT_};
+$ReturnValues{SQL_CONVERT_DECIMAL            } = $ReturnValues{SQL_CONVERT_};
+$ReturnValues{SQL_CONVERT_DOUBLE             } = $ReturnValues{SQL_CONVERT_};
+$ReturnValues{SQL_CONVERT_FLOAT              } = $ReturnValues{SQL_CONVERT_};
+$ReturnValues{SQL_CONVERT_GUID               } = $ReturnValues{SQL_CONVERT_};
+$ReturnValues{SQL_CONVERT_INTEGER            } = $ReturnValues{SQL_CONVERT_};
+$ReturnValues{SQL_CONVERT_INTERVAL_DAY_TIME  } = $ReturnValues{SQL_CONVERT_};
+$ReturnValues{SQL_CONVERT_INTERVAL_YEAR_MONTH} = $ReturnValues{SQL_CONVERT_};
+$ReturnValues{SQL_CONVERT_LONGVARBINARY      } = $ReturnValues{SQL_CONVERT_};
+$ReturnValues{SQL_CONVERT_LONGVARCHAR        } = $ReturnValues{SQL_CONVERT_};
+$ReturnValues{SQL_CONVERT_NUMERIC            } = $ReturnValues{SQL_CONVERT_};
+$ReturnValues{SQL_CONVERT_REAL               } = $ReturnValues{SQL_CONVERT_};
+$ReturnValues{SQL_CONVERT_SMALLINT           } = $ReturnValues{SQL_CONVERT_};
+$ReturnValues{SQL_CONVERT_TIME               } = $ReturnValues{SQL_CONVERT_};
+$ReturnValues{SQL_CONVERT_TIMESTAMP          } = $ReturnValues{SQL_CONVERT_};
+$ReturnValues{SQL_CONVERT_TINYINT            } = $ReturnValues{SQL_CONVERT_};
+$ReturnValues{SQL_CONVERT_VARBINARY          } = $ReturnValues{SQL_CONVERT_};
+$ReturnValues{SQL_CONVERT_VARCHAR            } = $ReturnValues{SQL_CONVERT_};
+$ReturnValues{SQL_CONVERT_WCHAR              } = $ReturnValues{SQL_CONVERT_};
+$ReturnValues{SQL_CONVERT_WLONGVARCHAR       } = $ReturnValues{SQL_CONVERT_};
+$ReturnValues{SQL_CONVERT_WVARCHAR           } = $ReturnValues{SQL_CONVERT_};
+
+$ReturnValues{SQL_CONVERT_FUNCTIONS} =
+{
+  SQL_FN_CVT_CONVERT                        => 0x00000001
+, SQL_FN_CVT_CAST                           => 0x00000002
+};
+$ReturnValues{SQL_CORRELATION_NAME} =
+{
+  SQL_CN_NONE                               => 0x0000
+, SQL_CN_DIFFERENT                          => 0x0001
+, SQL_CN_ANY                                => 0x0002
+};
+$ReturnValues{SQL_CREATE_ASSERTION} =
+{
+  SQL_CA_CREATE_ASSERTION                   => 0x00000001
+, SQL_CA_CONSTRAINT_INITIALLY_DEFERRED      => 0x00000010
+, SQL_CA_CONSTRAINT_INITIALLY_IMMEDIATE     => 0x00000020
+, SQL_CA_CONSTRAINT_DEFERRABLE              => 0x00000040
+, SQL_CA_CONSTRAINT_NON_DEFERRABLE          => 0x00000080
+};
+$ReturnValues{SQL_CREATE_CHARACTER_SET} =
+{
+  SQL_CCS_CREATE_CHARACTER_SET              => 0x00000001
+, SQL_CCS_COLLATE_CLAUSE                    => 0x00000002
+, SQL_CCS_LIMITED_COLLATION                 => 0x00000004
+};
+$ReturnValues{SQL_CREATE_COLLATION} =
+{
+  SQL_CCOL_CREATE_COLLATION                 => 0x00000001
+};
+$ReturnValues{SQL_CREATE_DOMAIN} =
+{
+  SQL_CDO_CREATE_DOMAIN                     => 0x00000001
+, SQL_CDO_DEFAULT                           => 0x00000002
+, SQL_CDO_CONSTRAINT                        => 0x00000004
+, SQL_CDO_COLLATION                         => 0x00000008
+, SQL_CDO_CONSTRAINT_NAME_DEFINITION        => 0x00000010
+, SQL_CDO_CONSTRAINT_INITIALLY_DEFERRED     => 0x00000020
+, SQL_CDO_CONSTRAINT_INITIALLY_IMMEDIATE    => 0x00000040
+, SQL_CDO_CONSTRAINT_DEFERRABLE             => 0x00000080
+, SQL_CDO_CONSTRAINT_NON_DEFERRABLE         => 0x00000100
+};
+$ReturnValues{SQL_CREATE_SCHEMA} =
+{
+  SQL_CS_CREATE_SCHEMA                      => 0x00000001
+, SQL_CS_AUTHORIZATION                      => 0x00000002
+, SQL_CS_DEFAULT_CHARACTER_SET              => 0x00000004
+};
+$ReturnValues{SQL_CREATE_TABLE} =
+{
+  SQL_CT_CREATE_TABLE                       => 0x00000001
+, SQL_CT_COMMIT_PRESERVE                    => 0x00000002
+, SQL_CT_COMMIT_DELETE                      => 0x00000004
+, SQL_CT_GLOBAL_TEMPORARY                   => 0x00000008
+, SQL_CT_LOCAL_TEMPORARY                    => 0x00000010
+, SQL_CT_CONSTRAINT_INITIALLY_DEFERRED      => 0x00000020
+, SQL_CT_CONSTRAINT_INITIALLY_IMMEDIATE     => 0x00000040
+, SQL_CT_CONSTRAINT_DEFERRABLE              => 0x00000080
+, SQL_CT_CONSTRAINT_NON_DEFERRABLE          => 0x00000100
+, SQL_CT_COLUMN_CONSTRAINT                  => 0x00000200
+, SQL_CT_COLUMN_DEFAULT                     => 0x00000400
+, SQL_CT_COLUMN_COLLATION                   => 0x00000800
+, SQL_CT_TABLE_CONSTRAINT                   => 0x00001000
+, SQL_CT_CONSTRAINT_NAME_DEFINITION         => 0x00002000
+};
+$ReturnValues{SQL_CREATE_TRANSLATION} =
+{
+  SQL_CTR_CREATE_TRANSLATION                => 0x00000001
+};
+$ReturnValues{SQL_CREATE_VIEW} =
+{
+  SQL_CV_CREATE_VIEW                        => 0x00000001
+, SQL_CV_CHECK_OPTION                       => 0x00000002
+, SQL_CV_CASCADED                           => 0x00000004
+, SQL_CV_LOCAL                              => 0x00000008
+};
+$ReturnValues{SQL_CURSOR_COMMIT_BEHAVIOR} =
+{
+  SQL_CB_DELETE                             => 0
+, SQL_CB_CLOSE                              => 1
+, SQL_CB_PRESERVE                           => 2
+};
+$ReturnValues{SQL_CURSOR_ROLLBACK_BEHAVIOR} = $ReturnValues{SQL_CURSOR_COMMIT_BEHAVIOR};
+
+$ReturnValues{SQL_CURSOR_SENSITIVITY} =
+{
+  SQL_UNSPECIFIED                           => 0
+, SQL_INSENSITIVE                           => 1
+, SQL_SENSITIVE                             => 2
+};
+$ReturnValues{SQL_DATETIME_LITERALS} =
+{
+  SQL_DL_SQL92_DATE                         => 0x00000001
+, SQL_DL_SQL92_TIME                         => 0x00000002
+, SQL_DL_SQL92_TIMESTAMP                    => 0x00000004
+, SQL_DL_SQL92_INTERVAL_YEAR                => 0x00000008
+, SQL_DL_SQL92_INTERVAL_MONTH               => 0x00000010
+, SQL_DL_SQL92_INTERVAL_DAY                 => 0x00000020
+, SQL_DL_SQL92_INTERVAL_HOUR                => 0x00000040
+, SQL_DL_SQL92_INTERVAL_MINUTE              => 0x00000080
+, SQL_DL_SQL92_INTERVAL_SECOND              => 0x00000100
+, SQL_DL_SQL92_INTERVAL_YEAR_TO_MONTH       => 0x00000200
+, SQL_DL_SQL92_INTERVAL_DAY_TO_HOUR         => 0x00000400
+, SQL_DL_SQL92_INTERVAL_DAY_TO_MINUTE       => 0x00000800
+, SQL_DL_SQL92_INTERVAL_DAY_TO_SECOND       => 0x00001000
+, SQL_DL_SQL92_INTERVAL_HOUR_TO_MINUTE      => 0x00002000
+, SQL_DL_SQL92_INTERVAL_HOUR_TO_SECOND      => 0x00004000
+, SQL_DL_SQL92_INTERVAL_MINUTE_TO_SECOND    => 0x00008000
+};
+$ReturnValues{SQL_DDL_INDEX} =
+{
+  SQL_DI_CREATE_INDEX                       => 0x00000001
+, SQL_DI_DROP_INDEX                         => 0x00000002
+};
+$ReturnValues{SQL_DIAG_CURSOR_ROW_COUNT} =
+{
+  SQL_CA2_CRC_EXACT                         => 0x00001000
+, SQL_CA2_CRC_APPROXIMATE                   => 0x00002000
+, SQL_CA2_SIMULATE_NON_UNIQUE               => 0x00004000
+, SQL_CA2_SIMULATE_TRY_UNIQUE               => 0x00008000
+, SQL_CA2_SIMULATE_UNIQUE                   => 0x00010000
+};
+$ReturnValues{SQL_DROP_ASSERTION} =
+{
+  SQL_DA_DROP_ASSERTION                     => 0x00000001
+};
+$ReturnValues{SQL_DROP_CHARACTER_SET} =
+{
+  SQL_DCS_DROP_CHARACTER_SET                => 0x00000001
+};
+$ReturnValues{SQL_DROP_COLLATION} =
+{
+  SQL_DC_DROP_COLLATION                     => 0x00000001
+};
+$ReturnValues{SQL_DROP_DOMAIN} =
+{
+  SQL_DD_DROP_DOMAIN                        => 0x00000001
+, SQL_DD_RESTRICT                           => 0x00000002
+, SQL_DD_CASCADE                            => 0x00000004
+};
+$ReturnValues{SQL_DROP_SCHEMA} =
+{
+  SQL_DS_DROP_SCHEMA                        => 0x00000001
+, SQL_DS_RESTRICT                           => 0x00000002
+, SQL_DS_CASCADE                            => 0x00000004
+};
+$ReturnValues{SQL_DROP_TABLE} =
+{
+  SQL_DT_DROP_TABLE                         => 0x00000001
+, SQL_DT_RESTRICT                           => 0x00000002
+, SQL_DT_CASCADE                            => 0x00000004
+};
+$ReturnValues{SQL_DROP_TRANSLATION} =
+{
+  SQL_DTR_DROP_TRANSLATION                  => 0x00000001
+};
+$ReturnValues{SQL_DROP_VIEW} =
+{
+  SQL_DV_DROP_VIEW                          => 0x00000001
+, SQL_DV_RESTRICT                           => 0x00000002
+, SQL_DV_CASCADE                            => 0x00000004
+};
+$ReturnValues{SQL_CURSOR_ATTRIBUTES1} =
+{
+  SQL_CA1_NEXT                              => 0x00000001
+, SQL_CA1_ABSOLUTE                          => 0x00000002
+, SQL_CA1_RELATIVE                          => 0x00000004
+, SQL_CA1_BOOKMARK                          => 0x00000008
+, SQL_CA1_LOCK_NO_CHANGE                    => 0x00000040
+, SQL_CA1_LOCK_EXCLUSIVE                    => 0x00000080
+, SQL_CA1_LOCK_UNLOCK                       => 0x00000100
+, SQL_CA1_POS_POSITION                      => 0x00000200
+, SQL_CA1_POS_UPDATE                        => 0x00000400
+, SQL_CA1_POS_DELETE                        => 0x00000800
+, SQL_CA1_POS_REFRESH                       => 0x00001000
+, SQL_CA1_POSITIONED_UPDATE                 => 0x00002000
+, SQL_CA1_POSITIONED_DELETE                 => 0x00004000
+, SQL_CA1_SELECT_FOR_UPDATE                 => 0x00008000
+, SQL_CA1_BULK_ADD                          => 0x00010000
+, SQL_CA1_BULK_UPDATE_BY_BOOKMARK           => 0x00020000
+, SQL_CA1_BULK_DELETE_BY_BOOKMARK           => 0x00040000
+, SQL_CA1_BULK_FETCH_BY_BOOKMARK            => 0x00080000
+};
+$ReturnValues{     SQL_DYNAMIC_CURSOR_ATTRIBUTES1} = $ReturnValues{SQL_CURSOR_ATTRIBUTES1};
+$ReturnValues{SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1} = $ReturnValues{SQL_CURSOR_ATTRIBUTES1};
+$ReturnValues{      SQL_KEYSET_CURSOR_ATTRIBUTES1} = $ReturnValues{SQL_CURSOR_ATTRIBUTES1};
+$ReturnValues{      SQL_STATIC_CURSOR_ATTRIBUTES1} = $ReturnValues{SQL_CURSOR_ATTRIBUTES1};
+
+$ReturnValues{SQL_CURSOR_ATTRIBUTES2} =
+{
+  SQL_CA2_READ_ONLY_CONCURRENCY             => 0x00000001
+, SQL_CA2_LOCK_CONCURRENCY                  => 0x00000002
+, SQL_CA2_OPT_ROWVER_CONCURRENCY            => 0x00000004
+, SQL_CA2_OPT_VALUES_CONCURRENCY            => 0x00000008
+, SQL_CA2_SENSITIVITY_ADDITIONS             => 0x00000010
+, SQL_CA2_SENSITIVITY_DELETIONS             => 0x00000020
+, SQL_CA2_SENSITIVITY_UPDATES               => 0x00000040
+, SQL_CA2_MAX_ROWS_SELECT                   => 0x00000080
+, SQL_CA2_MAX_ROWS_INSERT                   => 0x00000100
+, SQL_CA2_MAX_ROWS_DELETE                   => 0x00000200
+, SQL_CA2_MAX_ROWS_UPDATE                   => 0x00000400
+, SQL_CA2_MAX_ROWS_CATALOG                  => 0x00000800
+, SQL_CA2_CRC_EXACT                         => 0x00001000
+, SQL_CA2_CRC_APPROXIMATE                   => 0x00002000
+, SQL_CA2_SIMULATE_NON_UNIQUE               => 0x00004000
+, SQL_CA2_SIMULATE_TRY_UNIQUE               => 0x00008000
+, SQL_CA2_SIMULATE_UNIQUE                   => 0x00010000
+};
+$ReturnValues{     SQL_DYNAMIC_CURSOR_ATTRIBUTES2} = $ReturnValues{SQL_CURSOR_ATTRIBUTES2};
+$ReturnValues{SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2} = $ReturnValues{SQL_CURSOR_ATTRIBUTES2};
+$ReturnValues{      SQL_KEYSET_CURSOR_ATTRIBUTES2} = $ReturnValues{SQL_CURSOR_ATTRIBUTES2};
+$ReturnValues{      SQL_STATIC_CURSOR_ATTRIBUTES2} = $ReturnValues{SQL_CURSOR_ATTRIBUTES2};
+
+$ReturnValues{SQL_FETCH_DIRECTION} =
+{
+  SQL_FD_FETCH_NEXT                         => 0x00000001
+, SQL_FD_FETCH_FIRST                        => 0x00000002
+, SQL_FD_FETCH_LAST                         => 0x00000004
+, SQL_FD_FETCH_PRIOR                        => 0x00000008
+, SQL_FD_FETCH_ABSOLUTE                     => 0x00000010
+, SQL_FD_FETCH_RELATIVE                     => 0x00000020
+, SQL_FD_FETCH_RESUME                       => 0x00000040
+, SQL_FD_FETCH_BOOKMARK                     => 0x00000080
+};
+$ReturnValues{SQL_FILE_USAGE} =
+{
+  SQL_FILE_NOT_SUPPORTED                    => 0x0000
+, SQL_FILE_TABLE                            => 0x0001
+, SQL_FILE_QUALIFIER                        => 0x0002
+, SQL_FILE_CATALOG                          => 0x0002  # SQL_FILE_QUALIFIER
+};
+$ReturnValues{SQL_GETDATA_EXTENSIONS} =
+{
+  SQL_GD_ANY_COLUMN                         => 0x00000001
+, SQL_GD_ANY_ORDER                          => 0x00000002
+, SQL_GD_BLOCK                              => 0x00000004
+, SQL_GD_BOUND                              => 0x00000008
+};
+$ReturnValues{SQL_GROUP_BY} =
+{
+  SQL_GB_NOT_SUPPORTED                      => 0x0000
+, SQL_GB_GROUP_BY_EQUALS_SELECT             => 0x0001
+, SQL_GB_GROUP_BY_CONTAINS_SELECT           => 0x0002
+, SQL_GB_NO_RELATION                        => 0x0003
+, SQL_GB_COLLATE                            => 0x0004
+};
+$ReturnValues{SQL_IDENTIFIER_CASE} =
+{
+  SQL_IC_UPPER                              => 1
+, SQL_IC_LOWER                              => 2
+, SQL_IC_SENSITIVE                          => 3
+, SQL_IC_MIXED                              => 4
+};
+$ReturnValues{SQL_INDEX_KEYWORDS} =
+{
+  SQL_IK_NONE                               => 0x00000000
+, SQL_IK_ASC                                => 0x00000001
+, SQL_IK_DESC                               => 0x00000002
+# SQL_IK_ALL                                =>
+};
+$ReturnValues{SQL_INFO_SCHEMA_VIEWS} =
+{
+  SQL_ISV_ASSERTIONS                        => 0x00000001
+, SQL_ISV_CHARACTER_SETS                    => 0x00000002
+, SQL_ISV_CHECK_CONSTRAINTS                 => 0x00000004
+, SQL_ISV_COLLATIONS                        => 0x00000008
+, SQL_ISV_COLUMN_DOMAIN_USAGE               => 0x00000010
+, SQL_ISV_COLUMN_PRIVILEGES                 => 0x00000020
+, SQL_ISV_COLUMNS                           => 0x00000040
+, SQL_ISV_CONSTRAINT_COLUMN_USAGE           => 0x00000080
+, SQL_ISV_CONSTRAINT_TABLE_USAGE            => 0x00000100
+, SQL_ISV_DOMAIN_CONSTRAINTS                => 0x00000200
+, SQL_ISV_DOMAINS                           => 0x00000400
+, SQL_ISV_KEY_COLUMN_USAGE                  => 0x00000800
+, SQL_ISV_REFERENTIAL_CONSTRAINTS           => 0x00001000
+, SQL_ISV_SCHEMATA                          => 0x00002000
+, SQL_ISV_SQL_LANGUAGES                     => 0x00004000
+, SQL_ISV_TABLE_CONSTRAINTS                 => 0x00008000
+, SQL_ISV_TABLE_PRIVILEGES                  => 0x00010000
+, SQL_ISV_TABLES                            => 0x00020000
+, SQL_ISV_TRANSLATIONS                      => 0x00040000
+, SQL_ISV_USAGE_PRIVILEGES                  => 0x00080000
+, SQL_ISV_VIEW_COLUMN_USAGE                 => 0x00100000
+, SQL_ISV_VIEW_TABLE_USAGE                  => 0x00200000
+, SQL_ISV_VIEWS                             => 0x00400000
+};
+$ReturnValues{SQL_INSERT_STATEMENT} =
+{
+  SQL_IS_INSERT_LITERALS                    => 0x00000001
+, SQL_IS_INSERT_SEARCHED                    => 0x00000002
+, SQL_IS_SELECT_INTO                        => 0x00000004
+};
+$ReturnValues{SQL_LOCK_TYPES} =
+{
+  SQL_LCK_NO_CHANGE                         => 0x00000001
+, SQL_LCK_EXCLUSIVE                         => 0x00000002
+, SQL_LCK_UNLOCK                            => 0x00000004
+};
+$ReturnValues{SQL_NON_NULLABLE_COLUMNS} =
+{
+  SQL_NNC_NULL                              => 0x0000
+, SQL_NNC_NON_NULL                          => 0x0001
+};
+$ReturnValues{SQL_NULL_COLLATION} =
+{
+  SQL_NC_HIGH                               => 0
+, SQL_NC_LOW                                => 1
+, SQL_NC_START                              => 0x0002
+, SQL_NC_END                                => 0x0004
+};
+$ReturnValues{SQL_NUMERIC_FUNCTIONS} =
+{
+  SQL_FN_NUM_ABS                            => 0x00000001
+, SQL_FN_NUM_ACOS                           => 0x00000002
+, SQL_FN_NUM_ASIN                           => 0x00000004
+, SQL_FN_NUM_ATAN                           => 0x00000008
+, SQL_FN_NUM_ATAN2                          => 0x00000010
+, SQL_FN_NUM_CEILING                        => 0x00000020
+, SQL_FN_NUM_COS                            => 0x00000040
+, SQL_FN_NUM_COT                            => 0x00000080
+, SQL_FN_NUM_EXP                            => 0x00000100
+, SQL_FN_NUM_FLOOR                          => 0x00000200
+, SQL_FN_NUM_LOG                            => 0x00000400
+, SQL_FN_NUM_MOD                            => 0x00000800
+, SQL_FN_NUM_SIGN                           => 0x00001000
+, SQL_FN_NUM_SIN                            => 0x00002000
+, SQL_FN_NUM_SQRT                           => 0x00004000
+, SQL_FN_NUM_TAN                            => 0x00008000
+, SQL_FN_NUM_PI                             => 0x00010000
+, SQL_FN_NUM_RAND                           => 0x00020000
+, SQL_FN_NUM_DEGREES                        => 0x00040000
+, SQL_FN_NUM_LOG10                          => 0x00080000
+, SQL_FN_NUM_POWER                          => 0x00100000
+, SQL_FN_NUM_RADIANS                        => 0x00200000
+, SQL_FN_NUM_ROUND                          => 0x00400000
+, SQL_FN_NUM_TRUNCATE                       => 0x00800000
+};
+$ReturnValues{SQL_ODBC_API_CONFORMANCE} =
+{
+  SQL_OAC_NONE                              => 0x0000
+, SQL_OAC_LEVEL1                            => 0x0001
+, SQL_OAC_LEVEL2                            => 0x0002
+};
+$ReturnValues{SQL_ODBC_INTERFACE_CONFORMANCE} =
+{
+  SQL_OIC_CORE                              => 1
+, SQL_OIC_LEVEL1                            => 2
+, SQL_OIC_LEVEL2                            => 3
+};
+$ReturnValues{SQL_ODBC_SAG_CLI_CONFORMANCE} =
+{
+  SQL_OSCC_NOT_COMPLIANT                    => 0x0000
+, SQL_OSCC_COMPLIANT                        => 0x0001
+};
+$ReturnValues{SQL_ODBC_SQL_CONFORMANCE} =
+{
+  SQL_OSC_MINIMUM                           => 0x0000
+, SQL_OSC_CORE                              => 0x0001
+, SQL_OSC_EXTENDED                          => 0x0002
+};
+$ReturnValues{SQL_OJ_CAPABILITIES} =
+{
+  SQL_OJ_LEFT                               => 0x00000001
+, SQL_OJ_RIGHT                              => 0x00000002
+, SQL_OJ_FULL                               => 0x00000004
+, SQL_OJ_NESTED                             => 0x00000008
+, SQL_OJ_NOT_ORDERED                        => 0x00000010
+, SQL_OJ_INNER                              => 0x00000020
+, SQL_OJ_ALL_COMPARISON_OPS                 => 0x00000040
+};
+$ReturnValues{SQL_OWNER_USAGE} =
+{
+  SQL_OU_DML_STATEMENTS                     => 0x00000001
+, SQL_OU_PROCEDURE_INVOCATION               => 0x00000002
+, SQL_OU_TABLE_DEFINITION                   => 0x00000004
+, SQL_OU_INDEX_DEFINITION                   => 0x00000008
+, SQL_OU_PRIVILEGE_DEFINITION               => 0x00000010
+};
+$ReturnValues{SQL_PARAM_ARRAY_ROW_COUNTS} =
+{
+  SQL_PARC_BATCH                            => 1
+, SQL_PARC_NO_BATCH                         => 2
+};
+$ReturnValues{SQL_PARAM_ARRAY_SELECTS} =
+{
+  SQL_PAS_BATCH                             => 1
+, SQL_PAS_NO_BATCH                          => 2
+, SQL_PAS_NO_SELECT                         => 3
+};
+$ReturnValues{SQL_POSITIONED_STATEMENTS} =
+{
+  SQL_PS_POSITIONED_DELETE                  => 0x00000001
+, SQL_PS_POSITIONED_UPDATE                  => 0x00000002
+, SQL_PS_SELECT_FOR_UPDATE                  => 0x00000004
+};
+$ReturnValues{SQL_POS_OPERATIONS} =
+{
+  SQL_POS_POSITION                          => 0x00000001
+, SQL_POS_REFRESH                           => 0x00000002
+, SQL_POS_UPDATE                            => 0x00000004
+, SQL_POS_DELETE                            => 0x00000008
+, SQL_POS_ADD                               => 0x00000010
+};
+$ReturnValues{SQL_QUALIFIER_LOCATION} =
+{
+  SQL_QL_START                              => 0x0001
+, SQL_QL_END                                => 0x0002
+};
+$ReturnValues{SQL_QUALIFIER_USAGE} =
+{
+  SQL_QU_DML_STATEMENTS                     => 0x00000001
+, SQL_QU_PROCEDURE_INVOCATION               => 0x00000002
+, SQL_QU_TABLE_DEFINITION                   => 0x00000004
+, SQL_QU_INDEX_DEFINITION                   => 0x00000008
+, SQL_QU_PRIVILEGE_DEFINITION               => 0x00000010
+};
+$ReturnValues{SQL_QUOTED_IDENTIFIER_CASE}   = $ReturnValues{SQL_IDENTIFIER_CASE};
+
+$ReturnValues{SQL_SCHEMA_USAGE} =
+{
+  SQL_SU_DML_STATEMENTS                     => 0x00000001  # SQL_OU_DML_STATEMENTS
+, SQL_SU_PROCEDURE_INVOCATION               => 0x00000002  # SQL_OU_PROCEDURE_INVOCATION
+, SQL_SU_TABLE_DEFINITION                   => 0x00000004  # SQL_OU_TABLE_DEFINITION
+, SQL_SU_INDEX_DEFINITION                   => 0x00000008  # SQL_OU_INDEX_DEFINITION
+, SQL_SU_PRIVILEGE_DEFINITION               => 0x00000010  # SQL_OU_PRIVILEGE_DEFINITION
+};
+$ReturnValues{SQL_SCROLL_CONCURRENCY} =
+{
+  SQL_SCCO_READ_ONLY                        => 0x00000001
+, SQL_SCCO_LOCK                             => 0x00000002
+, SQL_SCCO_OPT_ROWVER                       => 0x00000004
+, SQL_SCCO_OPT_VALUES                       => 0x00000008
+};
+$ReturnValues{SQL_SCROLL_OPTIONS} =
+{
+  SQL_SO_FORWARD_ONLY                       => 0x00000001
+, SQL_SO_KEYSET_DRIVEN                      => 0x00000002
+, SQL_SO_DYNAMIC                            => 0x00000004
+, SQL_SO_MIXED                              => 0x00000008
+, SQL_SO_STATIC                             => 0x00000010
+};
+$ReturnValues{SQL_SQL92_DATETIME_FUNCTIONS} =
+{
+  SQL_SDF_CURRENT_DATE                      => 0x00000001
+, SQL_SDF_CURRENT_TIME                      => 0x00000002
+, SQL_SDF_CURRENT_TIMESTAMP                 => 0x00000004
+};
+$ReturnValues{SQL_SQL92_FOREIGN_KEY_DELETE_RULE} =
+{
+  SQL_SFKD_CASCADE                          => 0x00000001
+, SQL_SFKD_NO_ACTION                        => 0x00000002
+, SQL_SFKD_SET_DEFAULT                      => 0x00000004
+, SQL_SFKD_SET_NULL                         => 0x00000008
+};
+$ReturnValues{SQL_SQL92_FOREIGN_KEY_UPDATE_RULE} =
+{
+  SQL_SFKU_CASCADE                          => 0x00000001
+, SQL_SFKU_NO_ACTION                        => 0x00000002
+, SQL_SFKU_SET_DEFAULT                      => 0x00000004
+, SQL_SFKU_SET_NULL                         => 0x00000008
+};
+$ReturnValues{SQL_SQL92_GRANT} =
+{
+  SQL_SG_USAGE_ON_DOMAIN                    => 0x00000001
+, SQL_SG_USAGE_ON_CHARACTER_SET             => 0x00000002
+, SQL_SG_USAGE_ON_COLLATION                 => 0x00000004
+, SQL_SG_USAGE_ON_TRANSLATION               => 0x00000008
+, SQL_SG_WITH_GRANT_OPTION                  => 0x00000010
+, SQL_SG_DELETE_TABLE                       => 0x00000020
+, SQL_SG_INSERT_TABLE                       => 0x00000040
+, SQL_SG_INSERT_COLUMN                      => 0x00000080
+, SQL_SG_REFERENCES_TABLE                   => 0x00000100
+, SQL_SG_REFERENCES_COLUMN                  => 0x00000200
+, SQL_SG_SELECT_TABLE                       => 0x00000400
+, SQL_SG_UPDATE_TABLE                       => 0x00000800
+, SQL_SG_UPDATE_COLUMN                      => 0x00001000
+};
+$ReturnValues{SQL_SQL92_NUMERIC_VALUE_FUNCTIONS} =
+{
+  SQL_SNVF_BIT_LENGTH                       => 0x00000001
+, SQL_SNVF_CHAR_LENGTH                      => 0x00000002
+, SQL_SNVF_CHARACTER_LENGTH                 => 0x00000004
+, SQL_SNVF_EXTRACT                          => 0x00000008
+, SQL_SNVF_OCTET_LENGTH                     => 0x00000010
+, SQL_SNVF_POSITION                         => 0x00000020
+};
+$ReturnValues{SQL_SQL92_PREDICATES} =
+{
+  SQL_SP_EXISTS                             => 0x00000001
+, SQL_SP_ISNOTNULL                          => 0x00000002
+, SQL_SP_ISNULL                             => 0x00000004
+, SQL_SP_MATCH_FULL                         => 0x00000008
+, SQL_SP_MATCH_PARTIAL                      => 0x00000010
+, SQL_SP_MATCH_UNIQUE_FULL                  => 0x00000020
+, SQL_SP_MATCH_UNIQUE_PARTIAL               => 0x00000040
+, SQL_SP_OVERLAPS                           => 0x00000080
+, SQL_SP_UNIQUE                             => 0x00000100
+, SQL_SP_LIKE                               => 0x00000200
+, SQL_SP_IN                                 => 0x00000400
+, SQL_SP_BETWEEN                            => 0x00000800
+, SQL_SP_COMPARISON                         => 0x00001000
+, SQL_SP_QUANTIFIED_COMPARISON              => 0x00002000
+};
+$ReturnValues{SQL_SQL92_RELATIONAL_JOIN_OPERATORS} =
+{
+  SQL_SRJO_CORRESPONDING_CLAUSE             => 0x00000001
+, SQL_SRJO_CROSS_JOIN                       => 0x00000002
+, SQL_SRJO_EXCEPT_JOIN                      => 0x00000004
+, SQL_SRJO_FULL_OUTER_JOIN                  => 0x00000008
+, SQL_SRJO_INNER_JOIN                       => 0x00000010
+, SQL_SRJO_INTERSECT_JOIN                   => 0x00000020
+, SQL_SRJO_LEFT_OUTER_JOIN                  => 0x00000040
+, SQL_SRJO_NATURAL_JOIN                     => 0x00000080
+, SQL_SRJO_RIGHT_OUTER_JOIN                 => 0x00000100
+, SQL_SRJO_UNION_JOIN                       => 0x00000200
+};
+$ReturnValues{SQL_SQL92_REVOKE} =
+{
+  SQL_SR_USAGE_ON_DOMAIN                    => 0x00000001
+, SQL_SR_USAGE_ON_CHARACTER_SET             => 0x00000002
+, SQL_SR_USAGE_ON_COLLATION                 => 0x00000004
+, SQL_SR_USAGE_ON_TRANSLATION               => 0x00000008
+, SQL_SR_GRANT_OPTION_FOR                   => 0x00000010
+, SQL_SR_CASCADE                            => 0x00000020
+, SQL_SR_RESTRICT                           => 0x00000040
+, SQL_SR_DELETE_TABLE                       => 0x00000080
+, SQL_SR_INSERT_TABLE                       => 0x00000100
+, SQL_SR_INSERT_COLUMN                      => 0x00000200
+, SQL_SR_REFERENCES_TABLE                   => 0x00000400
+, SQL_SR_REFERENCES_COLUMN                  => 0x00000800
+, SQL_SR_SELECT_TABLE                       => 0x00001000
+, SQL_SR_UPDATE_TABLE                       => 0x00002000
+, SQL_SR_UPDATE_COLUMN                      => 0x00004000
+};
+$ReturnValues{SQL_SQL92_ROW_VALUE_CONSTRUCTOR} =
+{
+  SQL_SRVC_VALUE_EXPRESSION                 => 0x00000001
+, SQL_SRVC_NULL                             => 0x00000002
+, SQL_SRVC_DEFAULT                          => 0x00000004
+, SQL_SRVC_ROW_SUBQUERY                     => 0x00000008
+};
+$ReturnValues{SQL_SQL92_STRING_FUNCTIONS} =
+{
+  SQL_SSF_CONVERT                           => 0x00000001
+, SQL_SSF_LOWER                             => 0x00000002
+, SQL_SSF_UPPER                             => 0x00000004
+, SQL_SSF_SUBSTRING                         => 0x00000008
+, SQL_SSF_TRANSLATE                         => 0x00000010
+, SQL_SSF_TRIM_BOTH                         => 0x00000020
+, SQL_SSF_TRIM_LEADING                      => 0x00000040
+, SQL_SSF_TRIM_TRAILING                     => 0x00000080
+};
+$ReturnValues{SQL_SQL92_VALUE_EXPRESSIONS} =
+{
+  SQL_SVE_CASE                              => 0x00000001
+, SQL_SVE_CAST                              => 0x00000002
+, SQL_SVE_COALESCE                          => 0x00000004
+, SQL_SVE_NULLIF                            => 0x00000008
+};
+$ReturnValues{SQL_SQL_CONFORMANCE} =
+{
+  SQL_SC_SQL92_ENTRY                        => 0x00000001
+, SQL_SC_FIPS127_2_TRANSITIONAL             => 0x00000002
+, SQL_SC_SQL92_INTERMEDIATE                 => 0x00000004
+, SQL_SC_SQL92_FULL                         => 0x00000008
+};
+$ReturnValues{SQL_STANDARD_CLI_CONFORMANCE} =
+{
+  SQL_SCC_XOPEN_CLI_VERSION1                => 0x00000001
+, SQL_SCC_ISO92_CLI                         => 0x00000002
+};
+$ReturnValues{SQL_STATIC_SENSITIVITY} =
+{
+  SQL_SS_ADDITIONS                          => 0x00000001
+, SQL_SS_DELETIONS                          => 0x00000002
+, SQL_SS_UPDATES                            => 0x00000004
+};
+$ReturnValues{SQL_STRING_FUNCTIONS} =
+{
+  SQL_FN_STR_CONCAT                         => 0x00000001
+, SQL_FN_STR_INSERT                         => 0x00000002
+, SQL_FN_STR_LEFT                           => 0x00000004
+, SQL_FN_STR_LTRIM                          => 0x00000008
+, SQL_FN_STR_LENGTH                         => 0x00000010
+, SQL_FN_STR_LOCATE                         => 0x00000020
+, SQL_FN_STR_LCASE                          => 0x00000040
+, SQL_FN_STR_REPEAT                         => 0x00000080
+, SQL_FN_STR_REPLACE                        => 0x00000100
+, SQL_FN_STR_RIGHT                          => 0x00000200
+, SQL_FN_STR_RTRIM                          => 0x00000400
+, SQL_FN_STR_SUBSTRING                      => 0x00000800
+, SQL_FN_STR_UCASE                          => 0x00001000
+, SQL_FN_STR_ASCII                          => 0x00002000
+, SQL_FN_STR_CHAR                           => 0x00004000
+, SQL_FN_STR_DIFFERENCE                     => 0x00008000
+, SQL_FN_STR_LOCATE_2                       => 0x00010000
+, SQL_FN_STR_SOUNDEX                        => 0x00020000
+, SQL_FN_STR_SPACE                          => 0x00040000
+, SQL_FN_STR_BIT_LENGTH                     => 0x00080000
+, SQL_FN_STR_CHAR_LENGTH                    => 0x00100000
+, SQL_FN_STR_CHARACTER_LENGTH               => 0x00200000
+, SQL_FN_STR_OCTET_LENGTH                   => 0x00400000
+, SQL_FN_STR_POSITION                       => 0x00800000
+};
+$ReturnValues{SQL_SUBQUERIES} =
+{
+  SQL_SQ_COMPARISON                         => 0x00000001
+, SQL_SQ_EXISTS                             => 0x00000002
+, SQL_SQ_IN                                 => 0x00000004
+, SQL_SQ_QUANTIFIED                         => 0x00000008
+, SQL_SQ_CORRELATED_SUBQUERIES              => 0x00000010
+};
+$ReturnValues{SQL_SYSTEM_FUNCTIONS} =
+{
+  SQL_FN_SYS_USERNAME                       => 0x00000001
+, SQL_FN_SYS_DBNAME                         => 0x00000002
+, SQL_FN_SYS_IFNULL                         => 0x00000004
+};
+$ReturnValues{SQL_TIMEDATE_ADD_INTERVALS} =
+{
+  SQL_FN_TSI_FRAC_SECOND                    => 0x00000001
+, SQL_FN_TSI_SECOND                         => 0x00000002
+, SQL_FN_TSI_MINUTE                         => 0x00000004
+, SQL_FN_TSI_HOUR                           => 0x00000008
+, SQL_FN_TSI_DAY                            => 0x00000010
+, SQL_FN_TSI_WEEK                           => 0x00000020
+, SQL_FN_TSI_MONTH                          => 0x00000040
+, SQL_FN_TSI_QUARTER                        => 0x00000080
+, SQL_FN_TSI_YEAR                           => 0x00000100
+};
+$ReturnValues{SQL_TIMEDATE_FUNCTIONS} =
+{
+  SQL_FN_TD_NOW                             => 0x00000001
+, SQL_FN_TD_CURDATE                         => 0x00000002
+, SQL_FN_TD_DAYOFMONTH                      => 0x00000004
+, SQL_FN_TD_DAYOFWEEK                       => 0x00000008
+, SQL_FN_TD_DAYOFYEAR                       => 0x00000010
+, SQL_FN_TD_MONTH                           => 0x00000020
+, SQL_FN_TD_QUARTER                         => 0x00000040
+, SQL_FN_TD_WEEK                            => 0x00000080
+, SQL_FN_TD_YEAR                            => 0x00000100
+, SQL_FN_TD_CURTIME                         => 0x00000200
+, SQL_FN_TD_HOUR                            => 0x00000400
+, SQL_FN_TD_MINUTE                          => 0x00000800
+, SQL_FN_TD_SECOND                          => 0x00001000
+, SQL_FN_TD_TIMESTAMPADD                    => 0x00002000
+, SQL_FN_TD_TIMESTAMPDIFF                   => 0x00004000
+, SQL_FN_TD_DAYNAME                         => 0x00008000
+, SQL_FN_TD_MONTHNAME                       => 0x00010000
+, SQL_FN_TD_CURRENT_DATE                    => 0x00020000
+, SQL_FN_TD_CURRENT_TIME                    => 0x00040000
+, SQL_FN_TD_CURRENT_TIMESTAMP               => 0x00080000
+, SQL_FN_TD_EXTRACT                         => 0x00100000
+};
+$ReturnValues{SQL_TXN_CAPABLE} =
+{
+  SQL_TC_NONE                               => 0
+, SQL_TC_DML                                => 1
+, SQL_TC_ALL                                => 2
+, SQL_TC_DDL_COMMIT                         => 3
+, SQL_TC_DDL_IGNORE                         => 4
+};
+$ReturnValues{SQL_TRANSACTION_ISOLATION_OPTION} =
+{
+  SQL_TRANSACTION_READ_UNCOMMITTED          => 0x00000001  # SQL_TXN_READ_UNCOMMITTED
+, SQL_TRANSACTION_READ_COMMITTED            => 0x00000002  # SQL_TXN_READ_COMMITTED
+, SQL_TRANSACTION_REPEATABLE_READ           => 0x00000004  # SQL_TXN_REPEATABLE_READ
+, SQL_TRANSACTION_SERIALIZABLE              => 0x00000008  # SQL_TXN_SERIALIZABLE
+};
+$ReturnValues{SQL_DEFAULT_TRANSACTION_ISOLATION} = $ReturnValues{SQL_TRANSACTION_ISOLATION_OPTION};
+
+$ReturnValues{SQL_TXN_ISOLATION_OPTION} =
+{
+  SQL_TXN_READ_UNCOMMITTED                  => 0x00000001
+, SQL_TXN_READ_COMMITTED                    => 0x00000002
+, SQL_TXN_REPEATABLE_READ                   => 0x00000004
+, SQL_TXN_SERIALIZABLE                      => 0x00000008
+};
+$ReturnValues{SQL_DEFAULT_TXN_ISOLATION} = $ReturnValues{SQL_TXN_ISOLATION_OPTION};
+
+$ReturnValues{SQL_TXN_VERSIONING} =
+{
+  SQL_TXN_VERSIONING                        => 0x00000010
+};
+$ReturnValues{SQL_UNION} =
+{
+  SQL_U_UNION                               => 0x00000001
+, SQL_U_UNION_ALL                           => 0x00000002
+};
+$ReturnValues{SQL_UNION_STATEMENT} =
+{
+  SQL_US_UNION                              => 0x00000001  # SQL_U_UNION
+, SQL_US_UNION_ALL                          => 0x00000002  # SQL_U_UNION_ALL
+};
+
+1;
+
+=head1 TODO
+
+  Corrections?
+  SQL_NULL_COLLATION: ODBC vs ANSI
+  Unique values for $ReturnValues{...}?, e.g. SQL_FILE_USAGE
+
+=cut
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/Const/GetInfoReturn.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/Const/GetInfoReturn.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/Const/GetInfoReturn.pm	(revision 14139)
@@ -0,0 +1,104 @@
+# $Id$
+#
+# Copyright (c) 2002  Tim Bunce  Ireland
+#
+# Constant data describing return values from the DBI getinfo function.
+#
+# You may distribute under the terms of either the GNU General Public
+# License or the Artistic License, as specified in the Perl README file.
+
+package DBI::Const::GetInfoReturn;
+
+use strict;
+
+use Exporter ();
+
+use vars qw(@ISA @EXPORT @EXPORT_OK %GetInfoReturnTypes %GetInfoReturnValues);
+
+@ISA = qw(Exporter);
+@EXPORT = qw(%GetInfoReturnTypes %GetInfoReturnValues);
+
+my
+$VERSION = sprintf "%d.%02d", '$Revision$ ' =~ /(\d+)\.(\d+)/;
+
+=head1 NAME
+
+DBI::Const::GetInfoReturn - Data and functions for describing GetInfo results
+
+=head1 SYNOPSIS
+
+The interface to this module is undocumented and liable to change.
+
+=head1 DESCRIPTION
+
+Data and functions for describing GetInfo results
+
+=cut
+
+use DBI::Const::GetInfoType;
+
+use DBI::Const::GetInfo::ANSI ();
+use DBI::Const::GetInfo::ODBC ();
+
+%GetInfoReturnTypes =
+(
+  %DBI::Const::GetInfo::ANSI::ReturnTypes
+, %DBI::Const::GetInfo::ODBC::ReturnTypes
+);
+
+%GetInfoReturnValues = ();
+{
+  my $A = \%DBI::Const::GetInfo::ANSI::ReturnValues;
+  my $O = \%DBI::Const::GetInfo::ODBC::ReturnValues;
+  while ( my ($k, $v) = each %$A ) {
+    my %h = ( exists $O->{$k} ) ? ( %$v, %{$O->{$k}} ) : %$v;
+    $GetInfoReturnValues{$k} = \%h;
+  }
+  while ( my ($k, $v) = each %$O ) {
+    next if exists $A->{$k};
+    my %h = %$v;
+    $GetInfoReturnValues{$k} = \%h;
+  }
+}
+
+# -----------------------------------------------------------------------------
+
+sub Format {
+  my $InfoType = shift;
+  my $Value    = shift;
+
+  return '' unless defined $Value;
+
+  my $ReturnType = $GetInfoReturnTypes{$InfoType};
+
+  return sprintf '0x%08X', $Value if $ReturnType eq 'SQLUINTEGER bitmask';
+  return sprintf '0x%08X', $Value if $ReturnType eq 'SQLINTEGER bitmask';
+# return '"' . $Value . '"'       if $ReturnType eq 'SQLCHAR';
+  return $Value;
+}
+
+
+sub Explain {
+  my $InfoType = shift;
+  my $Value    = shift;
+
+  return '' unless defined $Value;
+  return '' unless exists $GetInfoReturnValues{$InfoType};
+
+  $Value = int $Value;
+  my $ReturnType = $GetInfoReturnTypes{$InfoType};
+  my %h = reverse %{$GetInfoReturnValues{$InfoType}};
+
+  if ( $ReturnType eq 'SQLUINTEGER bitmask'|| $ReturnType eq 'SQLINTEGER bitmask') {
+    my @a = ();
+    for my $k ( sort { $a <=> $b } keys %h ) {
+      push @a, $h{$k} if $Value & $k;
+    }
+    return wantarray ? @a : join(' ', @a );
+  }
+  else {
+    return $h{$Value} ||'?';
+  }
+}
+
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/Const/GetInfoType.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/Const/GetInfoType.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/Const/GetInfoType.pm	(revision 14139)
@@ -0,0 +1,53 @@
+# $Id$
+#
+# Copyright (c) 2002  Tim Bunce  Ireland
+#
+# Constant data describing info type codes for the DBI getinfo function.
+#
+# You may distribute under the terms of either the GNU General Public
+# License or the Artistic License, as specified in the Perl README file.
+
+package DBI::Const::GetInfoType;
+
+use strict;
+
+use Exporter ();
+
+use vars qw(@ISA @EXPORT @EXPORT_OK %GetInfoType);
+
+@ISA = qw(Exporter);
+@EXPORT = qw(%GetInfoType);
+
+my
+$VERSION = sprintf "%d.%02d", '$Revision$ ' =~ /(\d+)\.(\d+)/;
+
+=head1 NAME
+
+DBI::Const::GetInfoType - Data describing GetInfo type codes
+
+=head1 SYNOPSIS
+
+  use DBI::Const::GetInfoType;
+
+=head1 DESCRIPTION
+
+Imports a %GetInfoType hash which maps names for GetInfo Type Codes
+into their corresponding numeric values. For example:
+
+  $database_version = $dbh->get_info( $GetInfoType{SQL_DBMS_VER} );
+
+The interface to this module is new and nothing beyond what is
+written here is guaranteed.
+
+=cut
+
+use DBI::Const::GetInfo::ANSI ();	# liable to change
+use DBI::Const::GetInfo::ODBC ();	# liable to change
+
+%GetInfoType =
+(
+  %DBI::Const::GetInfo::ANSI::InfoTypes	# liable to change
+, %DBI::Const::GetInfo::ODBC::InfoTypes	# liable to change
+);
+
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/DBD.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/DBD.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/DBD.pm	(revision 14139)
@@ -0,0 +1,2905 @@
+package DBI::DBD;
+# vim:ts=8:sw=4
+
+use vars qw($VERSION);	# set $VERSION early so we don't confuse PAUSE/CPAN etc
+
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/o);
+
+# $Id$
+#
+# Copyright (c) 1997-2003 Jonathan Leffler, Jochen Wiedmann, Steffen
+# Goeldner and Tim Bunce
+#
+# You may distribute under the terms of either the GNU General Public
+# License or the Artistic License, as specified in the Perl README file.
+
+=head1 NAME
+
+DBI::DBD - Perl DBI Database Driver Writer's Guide
+
+=head1 SYNOPSIS
+
+  perldoc DBI::DBD
+
+=head2 Version and volatility
+
+  $Revision$
+  $Date$
+
+This document is I<still> a minimal draft which is in need of further work.
+
+The changes will occur both because the DBI specification is changing
+and hence the requirements on DBD drivers change, and because feedback
+from people reading this document will suggest improvements to it.
+
+Please read the DBI documentation first and fully, including the DBI FAQ.
+Then reread the DBI specification again as you're reading this. It'll help.
+
+This document is a patchwork of contributions from various authors.
+More contributions (preferably as patches) are very welcome.
+
+=head1 DESCRIPTION
+
+This document is primarily intended to help people writing new
+database drivers for the Perl Database Interface (Perl DBI).
+It may also help others interested in discovering why the internals of
+a DBD driver are written the way they are.
+
+This is a guide.  Few (if any) of the statements in it are completely
+authoritative under all possible circumstances.  This means you will
+need to use judgement in applying the guidelines in this document.
+If in I<any> doubt at all, please do contact the dbi-dev mailing list
+(details given below) where Tim Bunce and other driver authors can help.
+
+=head1 CREATING A NEW DRIVER
+
+The first rule for creating a new database driver for the Perl DBI is
+very simple: "DON'T!"
+
+There is usually a driver already available for the database you want to
+use, almost regardless of which database you choose.
+And very often, the database will provide an ODBC driver interface, so
+you can often use DBD::ODBC to access the database.
+This is typically less convenient on a Unix box than on a Microsoft
+Windows box, but there are numerous options for ODBC driver managers on
+Unix too, and very often the ODBC driver is provided by the database
+supplier.
+Before deciding that you need to write a driver, do your homework to
+ensure that you are not wasting your energies.
+
+[As of December 2002, the consensus is that if you need an ODBC driver
+manager on Unix, then the unixODBC driver (available from
+L<http://www.unixodbc.org/>) is the way to go.]
+
+The second rule for creating a new database driver for the Perl DBI is
+also very simple: "Don't -- get someone else to do it for you!"
+
+Nevertheless, there are occasions when it is necessary to write a new
+driver, often to use a proprietary language or API to access the
+database more swiftly, or more comprehensively, than an ODBC driver can.
+Then you should read this document very carefully, but with a suitably
+sceptical eye.
+If there is something in here that does not make any sense, question it.
+You might be right that the information is bogus.
+But don't come to that conclusion too quickly.
+
+=head2 URLs and mailing lists
+
+The primary web-site for locating DBI software and information is
+
+  http://dbi.perl.org/
+
+There are two main and one auxilliary mailing lists for people working
+with DBI.  The primary lists are dbi-users@perl.org for general users
+of DBI and DBD drivers, and dbi-dev@perl.org mainly for DBD driver
+writers (don't join the dbi-dev list unless you have a good reason).
+The auxilliary list is dbi-announce@perl.org for announcing new
+releases of DBI or DBD drivers.
+
+You can join these lists by accessing the web-site
+L<http://dbi.perl.org/>.
+The lists are closed so you cannot send email to any of the lists
+unless you join the list first.
+
+You should also consider monitoring the comp.lang.perl.* newsgroups,
+especially comp.lang.perl.modules.
+
+=head2 The Cheetah book
+
+The definitive book on Perl DBI is the Cheetah book, so called because
+of the picture on the cover.
+Its proper title is 'Programming the Perl DBI: Database programming with
+Perl' by Alligator Descartes and Tim Bunce, published by O'Reilly
+Associates, February 2000, ISBN 1-56592-699-4.
+Buy it now if you have not already done so, and read it.
+
+=head2 Locating drivers
+
+Before writing a new driver, it is in your interests to find out
+whether there already is a driver for your database.  If there is such
+a driver, it would be much easier to make use of it than to write your
+own!
+
+The primary web-site for locating Perl software is
+L<http://search.cpan.org/>.  You should look under the various
+modules listings for the software you are after. For example:
+
+  http://search.cpan.org/modlist/Database_Interfaces
+
+Follow the DBD:: and DBIx:: links at the top to see those subsets.
+
+See the DBI docs for information on DBI web sites and mailing lists.
+
+=head2 Registering a new driver
+
+Before going through any official registration process, you will need
+to establish that there is no driver already in the works.
+You'll do that by asking the DBI mailing lists whether there is such a
+driver available, or whether anybody is working on one.
+
+When you get the go ahead, you will need to establish the name of the
+driver and a prefix for the driver.
+Typically, the name is based on the name of the database software it
+uses, and the prefix is a contraction of that.
+Hence, DBD::Oracle has the name Oracle and the prefix 'ora_'.
+This information will be recorded in the DBI module.
+Apart from documentation purposes, registration is a prerequisite for
+L<installing private methods|DBI/install_method>.
+
+This document assumes you are writing a driver called DBD::Driver, and
+that the prefix 'drv_' is assigned to the driver.
+
+=head2 Two styles of database driver
+
+There are two distinct styles of database driver that can be written to
+work with the Perl DBI.
+
+Your driver can be written in pure Perl, requiring no C compiler.
+When feasible, this is the best solution, but most databases are not
+written in such a way that this can be done.
+Some example pure Perl drivers are DBD::File and DBD::CSV.
+
+Alternatively, and most commonly, your driver will need to use some C
+code to gain access to the database.
+This will be classified as a C/XS driver.
+
+=head2 What code will you write?
+
+There are a number of files that need to be written for either a pure
+Perl driver or a C/XS driver.
+There are no extra files needed only by a pure Perl driver, but there are
+several extra files needed only by a C/XS driver.
+
+=head3 Files common to pure Perl and C/XS drivers
+
+Assuming that your driver is called DBD::Driver, these files are:
+
+=over 4
+
+=item * Makefile.PL
+
+=item * README
+
+=item * MANIFEST
+
+=item * Driver.pm
+
+=item * lib/Bundle/DBD/Driver.pm
+
+=item * lib/DBD/Driver/Summary.pm
+
+=item * t/*.t
+
+=back
+
+Needless to say, all these files are either text files or pure Perl.
+
+The first four files are mandatory.
+Makefile.PL is used to control how the driver is built and installed.
+The README file tells people who download the file about how to build
+the module and any prerequisite software that must be installed.
+The MANIFEST file is used by the standard Perl module distribution mechanism.
+It lists all the source files that need to be distributed with your module.
+Driver.pm is what is loaded by the DBI code; it contains the methods
+peculiar to your driver.
+
+The lib/Bundle/DBD/Driver.pm file allows you to specify other Perl
+modules on which yours depends in a format that allows someone to type a
+simple command and ensure that all the pre-requisites are in place as
+well as building your driver.
+The lib/DBD/Driver/Summary.pm file contains (an updated version of) the
+information that was included - or that would have been included - in
+the appendices of the Cheetah book as a summary of the abilities of your
+driver and the associated database.
+
+The files in the t subdirectory are unit tests for your driver.
+You should write your tests as stringently as possible, while taking
+into account the diversity of installations that you can encounter.
+Your tests should not casually modify operational databases.
+You should never damage existing tables in a database.
+You should code your tests to use a constrained name space within the
+database.
+For example, the tables (and all other named objects) that are created
+could all begin with 'dbd_drv_'.
+At the end of a test run, there should be no testing objects left behind
+in the database.
+If you create any databases, you should remove them.
+If your database supports temporary tables that are automatically
+removed at the end of a session, then exploit them as often as possible.
+Try to make your tests independent of each other.
+If you have a test t/t11dowhat.t that depends upon the successful
+running of t/t10thingamy.t, people cannot run the single test case
+t/t11dowhat.t.
+Further, running t/t11dowhat.t twice in a row is likely to fail (at
+least, if t/t11dowhat.t modifies the database at all) because the
+database at the start of the second run is not what you saw at the start
+of the first run.
+Document in your README file what you do, and what privileges people
+need to do it.
+You can, and probably should, sequence your tests by including a test
+number before an abbreviated version of the test name; the tests are run
+in the order in which the names are expanded by shell-style globbing.
+
+Many drivers also install sub-modules DBD::Driver::SubModule for any of
+a variety of different reasons, such as to support the metadata methods
+(see the discussion of L</METADATA METHODS> below).
+Such sub-modules are conventionally stored in the directory lib/DBD/Driver.
+The module itself would usually be in a file SubModule.pm.
+All such sub-modules should themselves be version stamped (see the
+discussions far below).
+
+=head3 Extra files needed by C/XS drivers
+
+The software for a C/XS driver will typically contain at least four
+extra files that are not relevant to a pure Perl driver.
+
+=over 4
+
+=item * Driver.xs
+
+=item * Driver.h
+
+=item * dbdimp.h
+
+=item * dbdimp.c
+
+=back
+
+The Driver.xs file is used to generate C code that Perl can call to gain
+access to the C functions you write that will, in turn, call down onto
+your database software.
+
+The Driver.h header is a stylized header that ensures you can access the
+necessary Perl and DBI macros, types, and function declarations.
+
+The dbdimp.h is used to specify which functions have been implemented by
+your driver.
+
+The dbdimp.c file is where you write the C code that does the real work
+of translating between Perl-ish data types and what the database expects
+to use and return.
+
+There are some (mainly small, but very important) differences between
+the contents of Makefile.PL and Driver.pm for pure Perl and C/XS
+drivers, so those files are described both in the section on creating a
+pure Perl driver and in the section on creating a C/XS driver.
+
+Obviously, you can add extra source code files to the list.
+
+=head2 Requirements on a driver and driver writer
+
+To be remotely useful, your driver must be implemented in a format that
+allows it to be distributed via CPAN, the Comprehensive Perl Archive
+Network (http://www.cpan.org/ and http://search.cpan.org).
+Of course, it is easier if you do not have to meet this criterion, but
+you will not be able to ask for much help if you do not do so, and
+no-one is likely to want to install your module if they have to learn a
+new installation mechanism.
+
+=head1 CREATING A PURE PERL DRIVER
+
+Writing a pure Perl driver is surprisingly simple. However, there are
+some problems you should be aware of. The best option is of course
+picking up an existing driver and carefully modifying one method
+after the other.
+
+Also look carefully at DBD::AnyData and DBD::Template.
+
+As an example we take a look at the I<DBD::File> driver, a driver for
+accessing plain files as tables, which is part of the I<DBD::CSV>
+package.
+In what follows I assume the name C<Driver> for your new package and the
+prefix 'drv_'.
+The minimal set of files we have to implement are I<Makefile.PL>,
+I<README>, I<MANIFEST> and I<Driver.pm>.
+Files in the 'nice to have' category include '
+
+=head2 Pure Perl version of Makefile.PL
+
+You typically start with writing C<Makefile.PL>, a Makefile generator.
+The contents of this file are described in detail in the
+C<ExtUtils::MakeMaker> man pages.
+It is definitely a good idea if you start reading them.
+At least you should know about the variables I<CONFIGURE>, I<DEFINED>,
+I<PM>, I<DIR>, I<EXE_FILES>, I<INC>, I<LIBS>, I<LINKTYPE>, I<NAME>,
+I<OPTIMIZE>, I<PL_FILES>, I<VERSION>, I<VERSION_FROM>, I<clean>,
+I<depend>, I<realclean> from the C<ExtUtils::MakeMaker> man page: These
+are used in almost any Makefile.PL.
+Additionally read the section on I<Overriding MakeMaker Methods> and the
+descriptions of the I<distcheck>, I<disttest> and I<dist> targets: They
+will definitely be useful for you.
+
+Of special importance for DBI drivers is the I<postamble> method from
+the C<ExtUtils::MM_Unix> man page.
+And, for Emacs users, I recommend the I<libscan> method, which removes
+Emacs backup files (file names which end with a tilde '~') from lists of
+files.
+
+Now an example, I use the word C<Driver> wherever you should insert
+your driver's name:
+
+  # -*- perl -*-
+
+  use DBI 1.03;
+  use DBI::DBD;
+  use ExtUtils::MakeMaker;
+
+  WriteMakefile(
+      dbd_edit_mm_attribs( {
+          'NAME'         => 'DBD::Driver',
+          'VERSION_FROM' => 'Driver.pm',
+          'INC'          => $DBI_INC_DIR,
+          'dist'         => { 'SUFFIX'   => '.gz',
+                              'COMPRESS' => 'gzip -9f' },
+          'realclean'    => { FILES => '*.xsi' },
+      },
+      { create_pp_tests => 1})
+  );
+
+  package MY;
+  sub postamble { return main::dbd_postamble(@_); }
+  sub libscan {
+      my ($self, $path) = @_;
+      ($path =~ m/\~$/) ? undef : $path;
+  }
+
+Note the calls to C<dbd_edit_mm_attribs>() and C<dbd_postamble>().
+The second hash reference in the call to C<dbd_edit_mm_attribs>
+(containing C<create_pp_tests>) is optional; you should not use it
+unless your driver is a pure Perl driver (that is, it does not use C and
+XS code).
+Therefore, the call to C<dbd_edit_mm_attribs> is not relevant for C/XS
+drivers and may be omitted; simply use the (single) hash reference
+containing NAME etc as the only argument to C<WriteMakefile>().
+Note that the C<dbd_edit_mm_attribs> code will fail if you do not have a
+C<t> sub-directory containing at least one test case.
+All drivers must use C<dbd_postamble> or risk running into problems.
+
+Note the specification of VERSION_FROM; the named file (Driver.pm) will
+be scanned for the first line that looks like an assignment to $VERSION,
+and the subsequent text will be used to determine the version number.
+Note the commentary in L<ExtUtils::MakeMaker> on the subject of
+correctly formatted version numbers.
+
+If your driver depends upon external software (it usually will), you
+will need to add code to ensure that your environment is workable before
+the call to C<WriteMakefile>().
+A full-fledged Makefile.PL can be quite large (for example, the files
+for DBD::Oracle and DBD::Informix are both over 1000 lines long, and the
+Informix one uses - and creates - auxilliary modules too).
+
+See also L<ExtUtils::MakeMaker> and L<ExtUtils::MM_Unix>.
+Consider using L<CPAN::MakeMaker> in place of ExtUtils::MakeMaker.
+
+=head2 README
+
+The README file should describe what the driver is for, the
+pre-requisites for the build process, the actual build process, how to
+report errors, and who to report them to.
+Users will find ways of breaking the driver build and test process which
+you would never even have dreamed to be possible in your worst
+nightmares.
+Therefore, you need to write this document defensively, precisely and
+concisely.
+Also, it is in your interests to ensure that your tests work as widely
+as possible.
+As always, use the README from one of the established drivers as a basis
+for your own; the version in DBD::Informix is worth a look as it has
+been quite successful in heading off problems.
+
+=over 2
+
+=item *
+
+Note that users will have versions of Perl and DBI that are both older
+and newer than you expected, but this will seldom cause much trouble.
+When it does, it will be because you are using features of DBI that are
+not supported in the version they are using.
+
+=item *
+
+Note that users will have versions of the database software that are
+both older and newer than you expected.
+You will save yourself time in the long run if you can identify the
+range of versions which have been tested and warn about versions which
+are not known to be OK.
+
+=item *
+
+Note that many people trying to install your driver will not be experts
+in the database software.
+
+=item *
+
+Note that many people trying to install your driver will not be experts
+in C or Perl.
+
+=back
+
+=head2 MANIFEST
+
+The MANIFEST will be used by the Makefile's dist target to build the
+distribution tar file that is uploaded to CPAN. It should list every
+file that you want to include in your distribution, one per line.
+
+=head2 lib/Bundle/DBD/Driver.pm
+
+The CPAN module provides an extremely powerful bundle mechanism that
+allows you to specify pre-requisites for your driver.
+The primary pre-requisite is Bundle::DBI; you may want or need to add
+some more.
+With the bundle set up correctly, the user can type:
+
+        perl -MCPAN -e 'install Bundle::DBD::Driver'
+
+and Perl will download, compile, test and install all the Perl modules
+needed to build your driver.
+
+A suitable skeleton for this file is shown below.
+The prerequisite modules are listed in the C<CONTENTS> section, with the
+official name of the module followed by a dash and an informal name or
+description.
+Listing Bundle::DBI as the main pre-requisite simplifies life.
+Don't forget to list your driver.
+Note that unless the DBMS is itself a Perl module, you cannot list it as
+a pre-requisite in this file.
+You should keep the version of the bundle the same as the version of
+your driver.
+You should add configuration management, copyright, and licencing
+information at the top.
+
+  package Bundle::DBD::Driver;
+
+  $VERSION = '0.01';
+
+  1;
+
+  __END__
+
+  =head1 NAME
+
+  Bundle::DBD::Driver - A bundle to install all DBD::Driver related modules
+
+  =head1 SYNOPSIS
+
+  C<perl -MCPAN -e 'install Bundle::DBD::Driver'>
+
+  =head1 CONTENTS
+
+  Bundle::DBI  - Bundle for DBI by TIMB (Tim Bunce)
+
+  DBD::Driver  - DBD::Driver by YOU (Your Name)
+
+  =head1 DESCRIPTION
+
+  This bundle includes all the modules used by the Perl Database
+  Interface (DBI) driver for Driver (DBD::Driver), assuming the
+  use of DBI version 1.13 or later, created by Tim Bunce.
+
+  If you've not previously used the CPAN module to install any
+  bundles, you will be interrogated during its setup phase.
+  But when you've done it once, it remembers what you told it.
+  You could start by running:
+
+    C<perl -MCPAN -e 'install Bundle::CPAN'>
+
+  =head1 SEE ALSO
+
+  Bundle::DBI
+
+  =head1 AUTHOR
+
+  Your Name E<lt>F<you@yourdomain.com>E<gt>
+
+  =head1 THANKS
+
+  This bundle was created by ripping off Bundle::libnet created by
+  Graham Barr E<lt>F<gbarr@ti.com>E<gt>, and radically simplified
+  with some information from Jochen Wiedmann E<lt>F<joe@ispsoft.de>E<gt>.
+  The template was then included in the DBI::DBD documentation by
+  Jonathan Leffler E<lt>F<jleffler@informix.com>E<gt>.
+
+  =cut
+
+=head2 lib/DBD/Driver/Summary.pm
+
+There is no substitute for taking the summary file from a driver that
+was documented in the Perl book (such as DBD::Oracle or DBD::Informix or
+DBD::ODBC, to name but three), and adapting it to describe the
+facilities available via DBD::Driver when accessing the Driver database.
+
+=head2 Pure Perl version of Driver.pm
+
+The C<Driver.pm> file defines the Perl module DBD::Driver for your driver.
+It will define a package DBD::Driver along with some version information,
+some variable definitions, and a function driver() which will have a more
+or less standard structure.
+
+It will also define three sub-packages of DBD::Driver:
+
+=over 2
+
+=item DBD::Driver::dr
+
+with methods connect(), data_sources() and disconnect_all();
+
+=item DBD::Driver::db
+
+with methods such as prepare();
+
+=item DBD::Driver::st
+
+with methods such as execute() and fetch().
+
+=back
+
+The Driver.pm file will also contain the documentation specific to
+DBD::Driver in the format used by perldoc.
+
+In a pure Perl driver, the Driver.pm file is the core of the
+implementation.
+You will need to provide all the key methods needed by DBI.
+
+Now let's take a closer look at an excerpt of File.pm as an example.
+We ignore things that are common to any module (even non-DBI modules)
+or really specific to the DBD::File package.
+
+=head3 The DBD::Driver package
+
+=head4 The header
+
+  package DBD::File;
+
+  use strict;
+  use vars qw($VERSION $drh);
+
+  $VERSION = "1.23.00"  # Version number of DBD::File
+
+This is where the version number of your driver is specified.
+The code in Makefile.PL is told to look in this file for the
+information.
+It is recommended that you use a two-part (1.23) or three-part (1.23.45)
+version number.
+Please ensure that any other modules added with your driver are also
+version stamped so that CPAN does not get confused.
+Also consider the CPAN system, which gets confused and considers
+version 1.10 to precede version 1.9, so that using a raw CVS, RCS or
+SCCS version number is probably not appropriate (despite being very
+common). For RCS or CVS you can use this code:
+
+  $VERSION = sprintf "%d.%02d", '$Revision$ ' =~ /(\d+)\.(\d+)/;
+
+which pads out the fractional part with leading zeros so all is well
+(so long as you don't go past x.99)
+
+  $drh = undef;         # holds driver handle once initialized
+
+This is where the driver handle will be stored, once created.
+Note that you may assume there is only one handle for your driver.
+
+=head4 The driver constructor
+
+Note that the I<driver> method is in the DBD::Driver package, not in one
+of the sub-packages DBD::Driver::dr, DBD::Driver::db, or
+DBD::Driver::db.
+
+  sub driver
+  {
+      return $drh if $drh;      # already created - return same one
+      my ($class, $attr) = @_;
+
+      $class .= "::dr";
+
+      # not a 'my' since we use it above to prevent multiple drivers
+      $drh = DBI::_new_drh($class, {
+              'Name'        => 'File',
+              'Version'     => $VERSION,
+              'Attribution' => 'DBD::File by Jochen Wiedmann',
+          })
+          or return undef;
+
+      return $drh;
+  }
+
+The I<driver> method is the driver handle constructor. It's a
+reasonable example of how DBI implements its handles. There are three
+kinds: B<driver handles> (typically stored in C<$drh>; from now on
+called C<drh> or C<$drh>), B<database handles> (from now on called C<dbh> or
+C<$dbh>) and B<statement handles> (from now on called C<sth> or
+C<$sth>).
+
+The prototype of DBI::_new_drh is
+
+  $drh = DBI::_new_drh($class, $public_attrs, $private_attrs);
+
+with the following arguments:
+
+=over 4
+
+=item I<$class>
+
+is typically the class for your driver, (for example, "DBD::File::dr"),
+passed as the first argument to the I<driver> method.
+
+=item I<$public_attrs>
+
+is a hash ref to attributes like I<Name>, I<Version>, and I<Attribution>.
+These are processed and used by DBI.
+You had better not make any assumptions about them nor should you add
+private attributes here.
+
+=item I<$private_attrs>
+
+This is another (optional) hash ref with your private attributes.
+DBI will store them and otherwise leave them alone.
+
+=back
+
+The I<DBI::new_drh> method and the I<driver> method both return C<undef>
+for failure (in which case you must look at $DBI::err and $DBI::errstr
+for the failure information, because you have no driver handle to use).
+
+=head4 The CLONE special subroutine
+
+Also needed here, in the DBD::Driver package, is a CLONE() method
+that will be called by perl when an intrepreter is cloned. All your
+CLONE method needs to do, currently, is clear the cached $drh so
+the new interpreter won't start using the cached $drh from the old
+interpreter:
+
+  sub CLONE {
+    undef $drh;
+  }
+
+See L<http://search.cpan.org/dist/perl/pod/perlmod.pod#Making_your_module_threadsafe>
+for details.
+
+=head3 The DBD::Driver::dr package
+
+=head4 The database handle constructor
+
+The next lines of code look as follows:
+
+  package DBD::Driver::dr; # ====== DRIVER ======
+
+  $DBD::Driver::dr::imp_data_size = 0;
+
+Note that no @ISA is needed here, or for the other DBD::Driver::*
+classes, because the DBI takes care of that for you when the driver is
+loaded.
+
+The database handle constructor is a driver method, thus we have
+to change the namespace.
+
+  sub connect
+  {
+      my ($drh, $dr_dsn, $user, $auth, $attr) = @_;
+
+      # Some database specific verifications, default settings
+      # and the like can go here. This should only include
+      # syntax checks or similar stuff where it's legal to
+      # 'die' in case of errors.
+      # For example, many database packages requires specific
+      # environment variables to be set; this could be where you
+      # validate that they are set, or default them if they are not set.
+
+      $my $driver_prefix = "drv_"; # the assigned prefix for this driver
+
+      # Process attributes from the DSN; we assume ODBC syntax
+      # here, that is, the DSN looks like var1=val1;...;varN=valN
+      foreach my $var ( split /;/, $dr_dsn ) {
+          my ($attr_name, $attr_value) = split '=', $var, 2;
+	  return $drh->set_err(1, "Can't parse DSN part '$var'")
+              unless defined $attr_value;
+
+          # add driver prefix to attribute name if it doesn't have it already
+          $attr_name = $driver_prefix.$attr_name
+              unless $attr_name =~ /^$driver_prefix/o;
+
+	  # Store attribute into %$attr, replacing any existing value.
+          # The DBI will STORE() these into $dbh after we've connected
+	  $attr->{$attr_name} = $attr_value;
+      }
+
+      # Get the attributes we'll use to connect.
+      # We use delete here because these no need to STORE them
+      my $db = delete $attr->{drv_database} || delete $attr->{drv_db}
+          or return $drh->set_err(1, "No database name given in DSN '$dr_dsn'");
+      my $host = delete $attr->{drv_host} || 'localhost';
+      my $port = delete $attr->{drv_port} || 123456;
+
+      # Assume you can attach to your database via drv_connect:
+      my $connection = drv_connect($db, $host, $port, $user, $auth)
+          or return $drh->set_err(1, "Can't connect to $dr_dsn: ...");
+
+      # create a 'blank' dbh (call superclass constructor)
+      my ($outer, $dbh) = DBI::_new_dbh($drh, { Name => $dr_dsn });
+
+      $dbh->STORE('Active', 1 );
+      $dbh->{drv_connection} = $connection;
+
+      return $outer;
+  }
+
+The Name attribute is a standard DBI attribute.
+
+This is mostly the same as in the I<driver handle constructor> above.
+The arguments are described in the DBI man page.
+See L<DBI>.
+The constructor _new_dbh is called, returning a database handle.
+The constructor's prototype is:
+
+  ($outer, $inner) = DBI::_new_dbh($drh, $public_attr, $private_attr);
+
+with similar arguments to those in the I<driver handle constructor>,
+except that the C<$class> is replaced by C<$drh>.
+
+In scalar context, only the outer handle is returned.
+
+Note the use of the I<STORE> method for setting the dbh attributes.
+That's because within the driver code, the handle object you have is
+the 'inner' handle of a tied hash, not the outer handle that the
+users of your driver have.
+
+Because you have the inner handle, tie magic doesn't get invoked
+when you get or set values in the hash. This is often very handy for
+speed when you want to get or set simple non-special driver-specific
+attributes.
+
+However, some attribute values, such as those handled by the DBI
+like PrintError, don't actually exist in the hash and must be
+read via $h->FETCH($attrib) and set via $h->STORE($attrib, $value).
+If in any doubt, use these methods.
+
+=head4 The data_sources method
+
+The data_sources method must populate and return a list of valid data
+sources, prefixed with the "dbi:Driver" incantation that allows them to
+be used in the first argument of the C<DBI-E<gt>connect> method.
+An example of this might be scanning the I<$HOME/.odbcini> file on Unix
+for ODBC data sources (DSNs).
+As a trivial example, consider a fixed list of data sources:
+
+  sub data_sources
+  {
+      my($drh, $attr) = @_;
+      my(@list) = ();
+      # You need more sophisticated code than this to set @list...
+      push @list, "dbi:Driver:abc";
+      push @list, "dbi:Driver:def";
+      push @list, "dbi:Driver:ghi";
+      # End of code to set @list
+      return @list;
+  }
+
+=head4 Error handling
+
+It is quite likely that something fails in the connect method.
+With DBD::File for example, you might catch an error when setting the
+current directory to something not existent by using the
+(driver-specific) f_dir attribute.
+
+To report an error, you use the C<set_err> method:
+
+  $h->set_err($err, $errmsg, $state);
+
+This will ensure that the error is recorded correctly and that
+RaiseError and PrintError etc are handled correctly.
+Typically you'll
+always use the method instance, aka your method's first argument.
+
+As set_err always returns undef your error handling code can
+usually be simplified to something like this:
+
+  return $h->set_err($err, $errmsg, $state) if ...;
+
+=head4 The disconnect_all method
+
+If you need to release any resources when the driver is unloaded, you
+can provide a disconnect_all method.
+
+=head4 Other driver handle methods
+
+If you need any other driver handle methods, they can follow here.
+
+=head3 The DBD::Driver::db package
+
+=head4 The statement handle constructor
+
+There's nothing much new in the statement handle constructor.
+
+  package DBD::Driver::db; # ====== DATABASE ======
+
+  $DBD::Driver::db::imp_data_size = 0;
+
+  sub prepare
+  {
+      my ($dbh, $statement, @attribs) = @_;
+
+      # create a 'blank' sth
+      my ($outer, $sth) = DBI::_new_sth($dbh, { Statement => $statement });
+
+      $sth->STORE('NUM_OF_PARAMS', ($statement =~ tr/?//));
+
+      $sth->{drv_params} = [];
+
+      return $outer;
+  }
+
+This is still the same: check the arguments and call the super class
+constructor I<DBI::_new_sth>.
+Again, in scalar context, only the outer handle is returned.
+The C<Statement> attribute should be cached as shown.
+
+Note the prefix I<drv_> in the attribute names: it is required that
+all your private attributes use a lowercase prefix unique to your driver.
+The DBI contains a registry of known driver prefixes and may one day
+warn about unknown attributes that don't have a registered prefix.
+
+Note that we parse the statement here in order to set the attribute
+I<NUM_OF_PARAMS>.
+The technique illustrated is not very reliable; it can be confused by
+question marks appearing in quoted strings, delimited identifiers or in
+SQL comments that are part of the SQL statement.
+We could set I<NUM_OF_PARAMS> in the I<execute> method instead because
+the DBI specification explicitly allows a driver to defer this, but then
+the user could not call I<bind_param>.
+
+=head4 Transaction handling
+
+Pure Perl drivers will rarely support transactions. Thus your I<commit>
+and I<rollback> methods will typically be quite simple:
+
+  sub commit
+  {
+      my ($dbh) = @_;
+      if ($dbh->FETCH('Warn')) {
+          warn("Commit ineffective while AutoCommit is on");
+      }
+      0;
+  }
+
+  sub rollback {
+      my ($dbh) = @_;
+      if ($dbh->FETCH('Warn')) {
+          warn("Rollback ineffective while AutoCommit is on");
+      }
+      0;
+  }
+
+Or even simpler, just use the default methods provided by the DBI that
+do nothing except return undef.
+
+The DBI's default begin_work method can be used by inheritance.
+
+=head4 The STORE and FETCH methods
+
+These methods (that we have already used, see above) are called for
+you, whenever the user does a:
+
+  $dbh->{$attr} = $val;
+
+or, respectively,
+
+  $val = $dbh->{$attr};
+
+See L<perltie> for details on tied hash refs to understand why these
+methods are required.
+
+The DBI will handle most attributes for you, in particular attributes
+like I<RaiseError> or I<PrintError>.
+All you have to do is handle your driver's private attributes and any
+attributes, like AutoCommit and ChopBlanks, that the DBI can't handle
+for you.
+A good example might look like this:
+
+  sub STORE
+  {
+      my ($dbh, $attr, $val) = @_;
+      if ($attr eq 'AutoCommit') {
+          # AutoCommit is currently the only standard attribute we have
+          # to consider.
+          if (!$val) { die "Can't disable AutoCommit"; }
+          return 1;
+      }
+      if ($attr =~ m/^drv_/) {
+          # Handle only our private attributes here
+          # Note that we could trigger arbitrary actions.
+          # Ideally we should warn about unknown attributes.
+          $dbh->{$attr} = $val; # Yes, we are allowed to do this,
+          return 1;             # but only for our private attributes
+      }
+      # Else pass up to DBI to handle for us
+      $dbh->SUPER::STORE($attr, $val);
+  }
+
+  sub FETCH
+  {
+      my ($dbh, $attr) = @_;
+      if ($attr eq 'AutoCommit') { return 1; }
+      if ($attr =~ m/^drv_/) {
+          # Handle only our private attributes here
+          # Note that we could trigger arbitrary actions.
+          return $dbh->{$attr}; # Yes, we are allowed to do this,
+                                # but only for our private attributes
+      }
+      # Else pass up to DBI to handle
+      $dbh->SUPER::FETCH($attr);
+  }
+
+The DBI will actually store and fetch driver-specific attributes (with all
+lowercase names) without warning or error, so there's actually no need to
+implement driver-specific any code in your FETCH and STORE methods unless
+you need extra logic/checks, beyond getting or setting the value.
+
+Unless your driver documentation indicates otherwise, the return value of
+the STORE method is unspecified and the caller shouldn't use that value.
+
+=head4 Other database handle methods
+
+As with the driver package, other database handle methods may follow
+here.
+In particular you should consider a (possibly empty) I<disconnect>
+method and possibly a I<quote> method if DBI's default isn't correct for
+you.
+
+Where reasonable use $h->SUPER::foo() to call the DBI's method in
+some or all cases and just wrap your custom behavior around that.
+
+If you want to use private trace flags you'll probably want to be
+able to set them by name. To do that you'll need to define a
+parse_trace_flag() method (note that's parse_trace_flag not parse_trace_flags).
+
+  sub parse_trace_flag {
+      my ($h, $name) = @_;
+      return 0x01000000 if $name eq 'foo';
+      return 0x02000000 if $name eq 'bar';
+      return 0x04000000 if $name eq 'baz';
+      return 0x08000000 if $name eq 'boo';
+      return 0x10000000 if $name eq 'bop';
+      return $h->SUPER::parse_trace_flag($name);
+  }
+
+All private flag names must be lowercase, and all private flags
+must be in the top 8 of the 32 bits.
+
+=head3 The DBD::Driver::st package
+
+=head4 The execute method
+
+This is perhaps the most difficult method because we have to consider
+parameter bindings here. We present a simplified implementation by
+using the I<drv_params> attribute from above:
+
+  package DBD::Driver::st;
+
+  $DBD::Driver::st::imp_data_size = 0;
+
+  sub bind_param
+  {
+      my ($sth, $pNum, $val, $attr) = @_;
+      my $type = (ref $attr) ? $attr->{TYPE} : $attr;
+      if ($type) {
+          my $dbh = $sth->{Database};
+          $val = $dbh->quote($sth, $type);
+      }
+      my $params = $sth->{drv_params};
+      $params->[$pNum-1] = $val;
+      1;
+  }
+
+  sub execute
+  {
+      my ($sth, @bind_values) = @_;
+
+      # start of by finishing any previous execution if still active
+      $sth->finish if $sth->FETCH('Active');
+
+      my $params = (@bind_values) ?
+          \@bind_values : $sth->{drv_params};
+      my $numParam = $sth->FETCH('NUM_OF_PARAMS');
+      return $sth->set_err(1, "Wrong number of parameters")
+          if @$params != $numParam;
+      my $statement = $sth->{'Statement'};
+      for (my $i = 0;  $i < $numParam;  $i++) {
+          $statement =~ s/?/$params->[$i]/; # XXX doesn't deal with quoting etc!
+      }
+      # Do anything ... we assume that an array ref of rows is
+      # created and store it:
+      $sth->{'drv_data'} = $data;
+      $sth->{'drv_rows'} = @$data; # number of rows
+      $sth->STORE('NUM_OF_FIELDS') = $numFields;
+      @$data || '0E0';
+  }
+
+There are a number of things you should note here.
+We setup the NUM_OF_FIELDS attribute
+here, because this is essential for I<bind_columns> to work.
+We use attribute C<$sth-E<gt>{Statement}> which we created
+within I<prepare>. The attribute C<$sth-E<gt>{Database}>, which is
+nothing else than the I<dbh>, was automatically created by DBI.
+
+Finally note that (as specified in the DBI specification) we return the
+string '0E0' instead of the number 0, so that the result tests true but
+equal to zero.
+
+  $sth->execute() or die $sth->errstr;
+
+=head4 Fetching data
+
+We should not implement the methods I<fetchrow_array>, I<fetchall_arrayref>,
+... because these are already part of DBI.
+All we need is the method
+I<fetchrow_arrayref>:
+
+  sub fetchrow_arrayref
+  {
+      my ($sth) = @_;
+      my $data = $sth->{drv_data};
+      my $row = shift @$data;
+      if (!$row) {
+          $sth->STORE(Active => 0); # mark as no longer active
+          return undef;
+      }
+      if ($sth->FETCH('ChopBlanks')) {
+          map { $_ =~ s/\s+$//; } @$row;
+      }
+      return $sth->_set_fbav($row);
+  }
+  *fetch = \&fetchrow_arrayref; # required alias for fetchrow_arrayref
+
+Note the use of the method I<_set_fbav>: This is required so that
+I<bind_col> and I<bind_columns> work.
+
+If an error occurs which leaves the $sth in a state where remaining rows
+can't be fetched then Active should be turned off
+before the method returns.
+
+The rows method for this driver can be implemented like this:
+
+  sub rows { shift->{drv_rows} }
+
+because it knows in advance how many rows it has fetched.
+Alternatively you could delete that method and so fallback
+to the DBI's own method which does the right thing based
+on the number of calls to _set_fbav().
+
+=head4 Statement attributes
+
+The main difference between dbh and sth attributes is, that you
+should implement a lot of attributes here that are required by
+the DBI, such as I<NAME>, I<NULLABLE>, I<TYPE>, ...
+
+Besides that the STORE and FETCH methods are mainly the same
+as above for dbh's.
+
+=head4 Other statement methods
+
+A trivial C<finish> method to discard the stored data and do
+$sth->SUPER::finish;
+
+If you've defined a parse_trace_flag() method in ::db you'll also want
+it in ::st, so just alias it in:
+
+  *parse_trace_flag = \&DBD::foo:db::parse_trace_flag;
+
+And perhaps some other methods that are not part of the DBI
+specification, in particular to make metadata available.
+Remember that they must have names that begin with your drivers
+registered prefix so they can be installed using install_method().
+
+If DESTROY() is called on a statement handle that's still active
+($sth->{Active} is true) then it should effectively call finish().
+
+    sub DESTROY {
+        my $sth = shift;
+        $sth->finish if $sth->FETCH('Active');
+    }
+
+=head2 Tests
+
+The test process should conform as closely as possibly to the Perl
+standard test harness.
+
+In particular, most (all) of the tests should be run in the t sub-directory,
+and should simply produce an 'ok' when run under 'make test'.
+For details on how this is done, see the Camel book and the section in
+Chapter 7, "The Standard Perl Library" on L<Test::Harness>.
+
+The tests may need to adapt to the type of database which is being
+used for testing, and to the privileges of the user testing the
+driver.
+
+The DBD::Informix test code has to adapt in a number of places to the
+type of database to which it is connected as different Informix
+databases have different capabilities.
+For example, some of the tests are for databases without transaction
+logs; others are for databases with a transaction log.
+Some versions of the server have support for blobs, or stored
+procedures, or user-defined data types, and others do not.
+When a complete file of tests must be skipped, you can provide a reason
+in a pseudo-comment:
+
+    if ($no_transactions_available)
+    {
+        print "1..0 # Skip: No transactions available\n";
+        exit 0;
+    }
+
+Consider downloading the DBD::Informix code and look at the code in
+DBD/Informix/TestHarness.pm which is used throughout the
+DBD::Informix tests in the t sub-directory.
+
+=head1 CREATING A C/XS DRIVER
+
+Creating a new C/XS driver from scratch will always be a daunting task.
+You can and should greatly simplify your task by taking a good
+reference driver implementation and modifying that to match the
+database product for which you are writing a driver.
+
+The de facto reference driver has been the one for DBD::Oracle written
+by Tim Bunce, who is also the author of the DBI package. The DBD::Oracle
+module is a good example of a driver implemented around a C-level API.
+
+Nowadays it it seems better to base on DBD::ODBC, another driver
+maintained by Tim and Jeff Urlwin, because it offers a lot of metadata
+and seems to become the guideline for the future development. (Also as
+DBD::Oracle digs deeper into the Oracle 8 OCI interface it'll get even
+more hairy than it is now.)
+
+The DBD::Informix driver is one driver implemented using embedded SQL
+instead of a function-based API.
+DBD::Ingres may also be worth a look.
+
+=head2 C/XS version of Driver.pm
+
+A lot of the code in the Driver.pm file is very similar to the code for pure Perl modules
+- see above.  However,
+there are also some subtle (and not so subtle) differences, including:
+
+=over 8
+
+=item *
+
+The variables $DBD::File::{dr|db|st}::imp_data_size are not defined
+here, but in the XS code, because they declare the size of certain
+C structures.
+
+=item *
+
+Some methods are typically moved to the XS code, in particular
+I<prepare>, I<execute>, I<disconnect>, I<disconnect_all> and the STORE
+and FETCH methods.
+
+=item *
+
+Other methods are still part of C<Driver.pm>, but have callbacks to
+the XS code.
+
+=item *
+
+If the driver-specific parts of the imp_drh_t structure need to be
+formally initialized (which does not seem to be a common requirement),
+then you need to add a call to an appropriate XS function in the driver
+method of DBD::Driver::driver, and you define the corresponding function
+in Driver.xs, and you define the C code in dbdimp.c and the prototype in
+dbdimp.h.
+
+For example, DBD::Informix has such a requirement, and adds the
+following call after the call to _new_drh in Informix.pm:
+
+  DBD::Informix::dr::driver_init($drh);
+
+and the following code in Informix.xs:
+
+  # Initialize the DBD::Informix driver data structure
+  void
+  driver_init(drh)
+      SV *drh
+      CODE:
+      ST(0) = dbd_ix_dr_driver_init(drh) ? &sv_yes : &sv_no;
+
+and the code in dbdimp.h declares:
+
+  extern int dbd_ix_dr_driver_init(SV *drh);
+
+and the code in dbdimp.ec (equivalent to dbdimp.c) defines:
+
+  /* Formally initialize the DBD::Informix driver structure */
+  int
+  dbd_ix_dr_driver(SV *drh)
+  {
+      D_imp_drh(drh);
+      imp_drh->n_connections = 0;       /* No active connections */
+      imp_drh->current_connection = 0;  /* No current connection */
+      imp_drh->multipleconnections = (ESQLC_VERSION >= 600) ? True : False;
+      dbd_ix_link_newhead(&imp_drh->head);  /* Empty linked list of connections */
+      return 1;
+  }
+
+DBD::Oracle has a similar requirement but gets around it by checking
+whether the private data part of the driver handle is all zeroed out,
+rather than add extra functions.
+
+=back
+
+Now let's take a closer look at an excerpt from Oracle.pm (revised
+heavily to remove idiosyncrasies) as an example.
+We also ignore things that are already discussed for pure Perl drivers.
+
+=head3 The connect method
+
+The connect method is the database handle constructor.
+You could write either of two versions of this method: either one which
+takes connection attributes (new code) and one which ignores them (old
+code only).
+If you ignore the connection attributes, then you omit all mention of
+the $auth variable (which is a reference to a hash of attributes), and
+the XS system manages the differences for you.
+
+  sub connect
+  {
+      my ($drh, $dbname, $user, $auth, $attr) = @_;
+
+      # Some database specific verifications, default settings
+      # and the like following here. This should only include
+      # syntax checks or similar stuff where it's legal to
+      # 'die' in case of errors.
+
+      my $dbh = DBI::_new_dbh($drh, {
+              'Name'   => $dbname,
+          })
+          or return undef;
+
+      # Call the driver-specific function _login in Driver.xs file which
+      # calls the DBMS-specific function(s) to connect to the database,
+      # and populate internal handle data.
+      DBD::Driver::db::_login($dbh, $dbname, $user, $auth, $attr)
+          or return undef;
+
+      $dbh;
+  }
+
+This is mostly the same as in the pure Perl case, the exception being
+the use of the private I<_login> callback, which is the function that
+will really connect to the database.
+It is implemented in Driver.xst (you should not implement it) and calls
+I<dbd_db_login6> from I<dbdimp.c>.
+See below for details.
+
+ *FIX ME* Discuss removing attributes from hash reference as an optimization
+ to skip later calls to $dbh->STORE made by DBI->connect.
+
+ *FIX ME* Discuss removing attributes in Perl code.
+
+ *FIX ME* Discuss removing attributes in C code.
+
+=head3 The disconnect_all method
+
+ *FIX ME* T.B.S
+
+=head3 The data_sources method
+
+If your I<data_sources> method can be implemented in pure Perl, then do
+so because it is easier than doing it in XS code (see the section above
+for pure Perl drivers).
+If your I<data_sources> method must call onto compiled functions, then
+you will need to define dbd_dr_data_sources in your dbdimp.h file, which
+will trigger Driver.xst (in DBI v1.33 or greater) to generate the XS
+code that calls your actual C function (see the discussion below for
+details) and you do not code anything in Driver.pm to handle it.
+
+=head3 The prepare method
+
+The prepare method is the statement handle constructor, and most of it
+is not new.
+Like the I<connect> method, it now has a C callback:
+
+  package DBD::Driver::db; # ====== DATABASE ======
+  use strict;
+
+  sub prepare
+  {
+      my ($dbh, $statement, $attribs) = @_;
+
+      # create a 'blank' sth
+      my $sth = DBI::_new_sth($dbh, {
+          'Statement' => $statement,
+          })
+          or return undef;
+
+      # Call the driver-specific function _prepare in Driver.xs file
+      # which calls the DBMS-specific function(s) to prepare a statement
+      # and populate internal handle data.
+      DBD::Driver::st::_prepare($sth, $statement, $attribs)
+          or return undef;
+      $sth;
+  }
+
+=head3 The execute method
+
+ *FIX ME* T.B.S
+
+=head3 The fetchrow_arrayref method
+
+ *FIX ME* T.B.S
+
+=head3 Other methods?
+
+ *FIX ME* T.B.S
+
+=head2 Driver.xs
+
+Driver.xs should look something like this:
+
+  #include "Driver.h"
+
+  DBISTATE_DECLARE;
+
+  INCLUDE: Driver.xsi
+
+  MODULE = DBD::Driver    PACKAGE = DBD::Driver::dr
+
+  /* Non-standard drh XS methods following here, if any.       */
+  /* If none (the usual case), omit the MODULE line above too. */
+
+  MODULE = DBD::Driver    PACKAGE = DBD::Driver::db
+
+  /* Non-standard dbh XS methods following here, if any.       */
+  /* Currently this includes things like _list_tables from     */
+  /* DBD::mSQL and DBD::mysql.                                 */
+
+  MODULE = DBD::Driver    PACKAGE = DBD::Driver::st
+
+  /* Non-standard sth XS methods following here, if any.       */
+  /* In particular this includes things like _list_fields from */
+  /* DBD::mSQL and DBD::mysql for accessing metadata.          */
+
+Note especially the include of I<Driver.xsi> here: DBI inserts stub
+functions for almost all private methods here which will typically do
+much work for you.
+Wherever you really have to implement something, it will call a private
+function in I<dbdimp.c>, and this is what you have to implement.
+
+You need to set up an extra routine if your driver needs to export
+constants of its own, analogous to the SQL types available when you say:
+
+  use DBI qw(:sql_types);
+
+ *FIX ME* T.B.S
+
+=head2 Driver.h
+
+Driver.h is very simple and the operational contents should look like this:
+
+  #ifndef DRIVER_H_INCLUDED
+  #define DRIVER_H_INCLUDED
+
+  #define NEED_DBIXS_VERSION 93    /* 93 for DBI versions 1.00 to 1.32 */
+
+  #include <DBIXS.h>      /* installed by the DBI module  */
+
+  #include "dbdimp.h"
+
+  #include "dbivport.h"   /* see below                    */
+
+  #include <dbd_xsh.h>    /* installed by the DBI module  */
+
+  #endif /* DRIVER_H_INCLUDED */
+
+The C<DBIXS.h> header defines most of the interesting information that
+the writer of a driver needs.
+The file C<dbd_xsh.h> header provides prototype declarations for the C
+functions that you might decide to implement.
+Note that you should normally only define one of I<dbd_db_login> and
+I<dbd_db_login6> unless you are intent on supporting really old versions of
+DBI (prior to DBI 1.06) as well as modern versions.
+The only standard, DBI-mandated functions that you need write are those
+specified in the dbd_xsh.h header.
+You might also add extra driver-specific functions in Driver.xs.
+
+The dbivport.h file should be I<copied> from the latest DBI release into
+your distribution each time you enhance your driver to use new features
+for which the DBI is offering backwards compatibility via dbivport.h.
+
+Its job is to allow you to enhance your code to work with the latest
+DBI API while still allowing your driver to be compiled and used
+with older versions of the DBI. For example, when the DBIh_SET_ERR_CHAR
+macro was added to DBI 1.41 in an emulation of it was added to dbivport.h.
+
+Copying dbivport.h into your driver distribution and #including it
+in Driver.h, as shown above, lets you enhance your driver to use
+the new DBIh_SET_ERR_CHAR macro even with versions of the DBI earlier
+than 1.41. This makes users happy and your life easier.
+
+Always read the notes in dbivport.h to check for any limitations
+in the emulation that you should be aware of.
+
+
+=head2 Implementation header dbdimp.h
+
+This header file has two jobs:
+
+First it defines data structures for your private part of the handles.
+
+Second it defines macros that rename the generic names like
+I<dbd_db_login> to database specific names like I<ora_db_login>. This
+avoids name clashes and enables use of different drivers when you work
+with a statically linked perl.
+
+It also will have the important task of disabling XS methods that you
+don't want to implement.
+
+Finally, the macros will also be used to select alternate
+implementations of some functions.
+For example, the I<dbd_db_login> function is not passed the attribute
+hash.
+Since DBI v1.06, if a I<dbd_db_login6> macro is defined (for a function
+with 6 arguments), it will be used instead with the attribute hash
+passed as the sixth argument.
+
+People used to just pick Oracle's dbdimp.c and use the same names,
+structures and types.
+I strongly recommend against that.
+At first glance this saves time, but your implementation will be less
+readable.
+It was just hell when I had to separate DBI specific parts, Oracle
+specific parts, mSQL specific parts and mysql specific parts in
+DBD::mysql's I<dbdimp.h> and I<dbdimp.c>.
+(DBD::mysql was a port of DBD::mSQL which was based on DBD::Oracle.)
+[Seconded, based on the experience taking DBD::Informix apart, even
+though the version inherited in 1996 was only based on DBD::Oracle.]
+
+This part of the driver is I<your exclusive part>.
+Rewrite it from scratch, so it will be clean and short: in other words,
+a better piece of code.
+(Of course keep an eye on other people's work.)
+
+  struct imp_drh_st {
+      dbih_drc_t com;           /* MUST be first element in structure   */
+      /* Insert your driver handle attributes here */
+  };
+
+  struct imp_dbh_st {
+      dbih_dbc_t com;           /* MUST be first element in structure   */
+      /* Insert your database handle attributes here */
+  };
+
+  struct imp_sth_st {
+      dbih_stc_t com;           /* MUST be first element in structure   */
+      /* Insert your statement handle attributes here */
+  };
+
+  /*  Rename functions for avoiding name clashes; prototypes are  */
+  /*  in dbd_xst.h                                                */
+  #define dbd_init         drv_dr_init
+  #define dbd_db_login6    drv_db_login
+  #define dbd_db_do        drv_db_do
+  ... many more here ...
+
+These structures implement your private part of the handles.
+You I<have> to use the name I<imp_dbh_{dr|db|st}> and the first field
+I<must> be of type I<dbih_drc_t|_dbc_t|_stc_t> and I<must> be called
+C<com>.
+You should never access these fields directly, except by using the
+I<DBIc_xxx> macros below.
+
+=head2 Implementation source dbdimp.c
+
+Conventionally, I<dbdimp.c> is the main implementation file (but
+DBD::Informix calls the file dbdimp.ec).
+This section includes a short note on each function that is used in the
+Driver.xsi template and thus B<has> to be implemented.
+
+Of course, you will probably also need to implement other support
+functions, which should usually be file static if the are placed in
+I<dbdimp.c>.
+If they are placed in other files, you need to list those files in
+Makefile.PL (and MANIFEST) to handle them correctly.
+
+It is wise to adhere to a namespace convention for your functions to
+avoid conflicts.
+For example, for a driver with prefix "drv", you might call externally
+visible functions "dbd_drv_xxxx".
+You should also avoid non-constant global variables as much as possible
+to improve the support for threading.
+
+Since Perl 5.6 requires support for function prototypes (ANSI or ISO or
+Standard C), you should write your code using function prototypes too.
+Although technically DBI still supports Perl 5.005_03, which did not
+mandate prototype support from the C compiler, the only platform where
+prototypes are a problem is on HP-UX with the bundled C compiler (which
+is strictly K&R).
+The solution for that is to get a copy of the GNU Compiler Collection
+(GCC, aka the GNU C Compiler) for HP-UX.
+
+It is possible to use either the unmapped names such as C<dbd_init> or
+the mapped names such as C<dbd_ix_dr_init> in the C<dbdimp.c> file.
+DBD::Informix uses the mapped names which makes it easier to identify
+where to look for linkage problems at runtime (which will report errors
+using the mapped names).
+Most other drivers, and in particular DBD::Oracle, use the unmapped
+names in the source code which makes it a little easier to compare code
+between drivers and eases discussions on the dbi-dev mailing list.
+The majority of the code fragments here will use the unmapped names.
+
+Ultimately, you should provide implementations for most fo the functions
+listed in the I<dbd_xsh.h> header.
+The exceptions are optional functions (such as I<dbd_st_rows>) and those
+functions with alternative signatures, such as I<dbd_db_login6> and
+I<dbd_db_login>.
+Then you should only implement one of the alternatives, and generally
+the newer one of the alternatives.
+
+=head3 The dbd_init method
+
+  #include "Driver.h"
+
+  DBISTATE_DECLARE;
+
+  void dbd_init(dbistate_t* dbistate)
+  {
+      DBISTATE_INIT;  /*  Initialize the DBI macros  */
+  }
+
+The C<dbd_init> function will be called when your driver is first
+loaded; the bootstrap command in DBD::Driver::dr::driver triggers this,
+and the call is generated in the BOOT section of Driver.xst.
+These statements are needed to allow your driver to use the DBI macros.
+They will include your private header file I<dbdimp.h> in turn.
+Note that DBISTATE_INIT requires the name of the argument to I<dbd_init>
+to be called I<dbistate>.
+
+=head3 The dbd_drv_error method
+
+You need a function to record errors so DBI can access them properly.
+You can call it whatever you like, but we'll call it C<dbd_drv_error>
+here.
+The argument list depends on your database software; different systems
+provide different ways to get at error information.
+
+  static void dbd_drv_error(SV *h, int rc, const char *what)
+  {
+
+Note that I<h> is a generic handle, may it be a driver handle, a
+database or a statement handle.
+
+      D_imp_xxh(h);
+
+This macro will declare and initialize a variable I<imp_xxh> with
+a pointer to your private handle pointer. You may cast this to
+to I<imp_drh_t>, I<imp_dbh_t> or I<imp_sth_t>.
+
+To record the error correctly, equivalent to the set_err() method,
+use one of the DBIh_SET_ERR_CHAR(...) or DBIh_SET_ERR_SV(...) macros,
+which were added in DBI 1.41:
+
+  DBIh_SET_ERR_SV(h, imp_xxh, err, errstr, state, method);
+  DBIh_SET_ERR_CHAR(h, imp_xxh, err_c, err_i, errstr, state, method);
+
+For DBIh_SET_ERR_SV the err, errstr, state, and method parameters are SV*.
+For DBIh_SET_ERR_CHAR the err_c, errstr, state, method are char*.
+The err_i parameter is an IV that's used instead of err_c is err_c is Null.
+The method parameter can be ignored.
+
+The DBIh_SET_ERR_CHAR macro is usually the simplest to use when you
+just have an integer error code and an error message string:
+
+  DBIh_SET_ERR_CHAR(h, imp_xxh, Nullch, rc, what, Nullch, Nullch);
+
+As you can see, any parameters that aren't relevant to you can be Null.
+
+To make drivers compatible with DBI < 1.41 you should be using dbivport.h
+as described in L</Driver.h> above.
+
+The (obsolete) macros such as DBIh_EVENT2 should be removed from drivers.
+
+The names I<dbis> and I<DBIS>, which were used in previous versions of this document,
+should be replaced with the C<DBIc_STATE(imp_xxh)> macro.
+
+The name DBILOGFP, which was also used in previous  versions of this document, should be
+replaced by DBIc_LOGPIO(imp_xxh).
+
+Your code should not call the C C<E<lt>stdio.hE<gt>> I/O functions; you should use
+C<PerlIO_printf>() as shown:
+
+      if (DBIc_TRACE_LEVEL(imp_xxh) >= 2)
+          PerlIO_printf(DBIc_LOGPIO(imp_xxh), "foobar %s: %s\n",
+              foo, neatsvpv(errstr,0));
+
+That's the first time we see how tracing works within a DBI
+driver.  Make use of this as often as you can! But don't output anything
+at a trace level less than 3. Levels 1 and 2 are reserved for the DBI.
+
+You can define up to 8 private trace flags using the top 8 bits of
+DBIc_TRACE_FLAGS(imp), that is: 0xFF000000. See the parse_trace_flag() method
+elsewhere in this document.
+
+=head3 The dbd_dr_data_sources method
+
+This method is optional; the support for it was added in DBI v1.33.
+
+As noted in the discussion of Driver.pm, if the data sources can be
+determined by pure Perl code, do it that way.
+If, as in DBD::Informix, the information is obtained by a C function
+call, then you need to define a function that matches the prototype:
+
+  extern AV *dbd_dr_data_sources(SV *drh, imp_drh_t *imp_drh, SV *attrs);
+
+An outline implementation for DBD::Informix follows, assuming that the
+sqgetdbs() function call shown will return up to 100 databases names,
+with the pointers to each name in the array dbsname and the name strings
+themselves being stores in dbsarea.
+The actual DBD::Informix implementation has a number of extra lines of
+code, logs function entry and exit, reports the error from sqgetdbs(),
+and uses #define'd constatnts for the array sizes.
+
+  AV *dbd_dr_data_sources(SV *drh, imp_drh_t *imp_drh, SV *attr)
+  {
+      int ndbs;
+      int i;
+      char *dbsname[100];
+      char  dbsarea[10000];
+      AV *av = Nullav;
+
+      if (sqgetdbs(&ndbs, dbsname, 100, dbsarea, sizeof(dbsarea)) == 0)
+      {
+          av = NewAV();
+          av_extend(av, (I32)ndbs);
+          sv_2mortal((SV *)av);
+          for (i = 0; i < ndbs; i++)
+            av_store(av, i, newSVpvf("dbi:Informix:%s", dbsname[i]));
+      }
+      return(av);
+  }
+
+=head3 The dbd_db_login6 method
+
+  int dbd_db_login6(SV* dbh, imp_dbh_t* imp_dbh, char* dbname,
+                   char* user, char* auth, SV *attr);
+
+This function will really connect to the database.
+The argument I<dbh> is the database handle.
+I<imp_dbh> is the pointer to the handles private data, as is I<imp_xxx>
+in I<dbd_drv_error> above.
+The arguments I<dbname>, I<user>, I<auth> and I<attr> correspond to the
+arguments of the driver handle's I<connect> method.
+
+You will quite often use database specific attributes here, that are
+specified in the DSN.
+I recommend you parse the DSN (using Perl) within the I<connect> method
+and pass the segments of the DSN via the attributes parameter through
+I<_login> to I<dbd_db_login6>.
+Here's how you fetch them; as an example we use I<hostname> attribute,
+which can be up to 12 characters long excluding null terminator:
+
+  SV** svp;
+  STRLEN len;
+  char* hostname;
+
+  if ( (svp = DBD_ATTRIB_GET_SVP(attr, "drv_hostname", 12)) && SvTRUE(*svp)) {
+      hostname = SvPV(*svp, len);
+      DBD__ATTRIB_DELETE(attr, "drv_hostname", 12); /* avoid later STORE */
+  } else {
+      hostname = "localhost";
+  }
+
+Note that you can also obtain standard attributes such as AutoCommit and
+ChopBlanks from the attributes parameter, using DBD_ATTRIB_GET_IV for
+integer attributes.
+If, for example, your database does not support transactions but
+AutoCommit is set off (requesting transaction support), then you can
+emulate a 'failure to connect'.
+
+Now you should really connect to the database.
+In general, if the connection fails, it is best to ensure that all
+allocated resources are released so that the handle does not need to be
+destroyed separately.
+If you are successful (and possibly even if you fail but you have
+allocated some resources), you should use the following macros:
+
+  DBIc_IMPSET_on(imp_dbh);
+
+This indicates that the driver (implementor) has allocated resources in
+the imp_dbh structure and that the implementors private dbd_db_destroy
+function should be called when the handle is destroyed.
+
+  DBIc_ACTIVE_on(imp_dbh);
+
+This indicates that the handle has an active connection to the server
+and that the dbd_db_disconnect function should be called before the
+handle is destroyed.
+
+Note that if you do need to fail, you should report errors via the drh
+or imp_drh rather than via dbh or imp_dbh because imp_dbh will be
+destroyed by the failure, so errors recorded in that handle will not be
+visible to DBI, and hence not the user either.
+Note to that the function is passed dbh and imp_dbh, and there is a
+macro D_imp_drh_from_dbh which can recover the imp_drh from the imp_dbh,
+but there is no DBI macro to provide you with the drh given either the
+imp_dbh or the dbh or the imp_drh (and there's no way to recover the dbh
+given just the imp_dbh).
+This suggests that despite the notes about dbd_drv_error above taking an
+SV *, it may be better to have two error routines, one taking imp_dbh
+and one taking imp_drh instead.
+With care, you can factor most of the formatting code out so that these
+are small routines calling onto a common error formatter.
+See the code in DBD::Informix 1.05.00 for more information.
+
+The I<dbd_db_login6> function should return TRUE for success, FALSE otherwise.
+
+Drivers implemented long ago may define the five-argument function
+I<dbd_db_login> instead of I<dbd_db_login6>.
+The missing argument is the attributes.
+There are ways to work around the missing attributes, but they are
+ungainly; it is much better to use the 6-argument form.
+
+=head3 The dbd_db_commit and dbd_db_rollback methods
+
+  int dbd_db_commit(SV *dbh, imp_dbh_t *imp_dbh);
+  int dbd_db_rollback(SV* dbh, imp_dbh_t* imp_dbh);
+
+These are used for commit and rollback. They should return TRUE for
+success, FALSE for error.
+
+The arguments I<dbh> and I<imp_dbh> are the same as for I<dbd_db_login6>
+above; I will omit describing them in what follows, as they appear
+always.
+
+These functions should return TRUE for success, FALSE otherwise.
+
+=head3 The dbd_db_disconnect method
+
+This is your private part of the I<disconnect> method. Any dbh with
+the I<ACTIVE> flag on must be disconnected. (Note that you have to set
+it in I<dbd_db_connect> above.)
+
+  int dbd_db_disconnect(SV* dbh, imp_dbh_t* imp_dbh);
+
+The database handle will return TRUE for success, FALSE otherwise.
+In any case it should do a:
+
+  DBIc_ACTIVE_off(imp_dbh);
+
+before returning so DBI knows that I<dbd_db_disconnect> was executed.
+
+Note that there's nothing to stop a dbh being I<disconnected> while it
+still have active children.
+If your database API reacts badly to trying to use an sth in this
+situation then you'll need to add code like this to all sth methods:
+
+  if (!DBIc_ACTIVE(DBIc_PARENT_COM(imp_sth)))
+    return 0;
+
+Alternatively, you can add code to your driver to keep explicit track of
+the statement handles that exist for each database handle and arrange to
+destroy those handles before disconnecting from the database.
+There is code to do this in DBD::Informix.
+Similar comments apply to the driver handle keeping track of all the
+database handles.
+Note that the code which destroys the subordinate handles should only
+release the associated database resources and mark the handles inactive;
+it does not attempt to free the actual handle structures.
+
+This function should return TRUE for success, FALSE otherwise, but
+it is not clear what anything can do about a failure.
+
+=head3 The dbd_db_discon_all method
+
+  int dbd_discon_all (SV *drh, imp_drh_t *imp_drh);
+
+This function may be called at shutdown time. It should make
+best-efforts to disconnect all database handles - if possible. Some
+databases don't support that, in which case you can do nothing
+but return 'success'.
+
+This function should return TRUE for success, FALSE otherwise, but
+it is not clear what anything can do about a failure.
+
+=head3 The dbd_db_destroy method
+
+This is your private part of the database handle destructor. Any dbh with
+the I<IMPSET> flag on must be destroyed, so that you can safely free
+resources. (Note that you have to set it in I<dbd_db_connect> above.)
+
+  void dbd_db_destroy(SV* dbh, imp_dbh_t* imp_dbh)
+  {
+      DBIc_IMPSET_off(imp_dbh);
+  }
+
+The DBI Driver.xst code will have called dbd_db_disconnect for you,
+if the handle is still 'active', before calling dbd_db_destroy.
+
+Before returning the function must switch IMPSET to off, so DBI knows
+that the destructor was called.
+
+A DBI handle doesn't keep references to its children. But children
+do keep references to their parents. So a database handle won't be
+DESTROY'd until all its children have been DESTROY'd.
+
+=head3 The dbd_db_STORE_attrib method
+
+This function handles
+
+  $dbh->{$key} = $value;
+
+Its prototype is:
+
+  int dbd_db_STORE_attrib(SV* dbh, imp_dbh_t* imp_dbh, SV* keysv,
+                          SV* valuesv);
+
+You do not handle all attributes; on the contrary, you should not handle
+DBI attributes here: leave this to DBI.
+(There are two exceptions, I<AutoCommit> and I<ChopBlanks>, which you
+should care about.)
+
+The return value is TRUE if you have handled the attribute or FALSE
+otherwise. If you are handling an attribute and something fails, you
+should call I<dbd_drv_error>, so DBI can raise exceptions, if desired.
+If I<dbd_drv_error> returns, however, you have a problem: the user will
+never know about the error, because he typically will not check
+C<$dbh-E<gt>errstr>.
+
+I cannot recommend a general way of going on, if I<dbd_drv_error> returns,
+but there are examples where even the DBI specification expects that
+you croak(). (See the I<AutoCommit> method in L<DBI>.)
+
+If you have to store attributes, you should either use your private
+data structure imp_xxx, the handle hash (via (HV*)SvRV(dbh)), or use
+the private imp_data.
+
+The first is best for internal C values like integers or pointers and
+where speed is important within the driver. The handle hash is best for
+values the user may want to get/set via driver-specific attributes.
+The private imp_data is an additional SV attached to the handle. You
+could think of it as an unnamed handle attribute. It's not normally used.
+
+=head3 The dbd_db_FETCH_attrib method
+
+This is the counterpart of dbd_db_STORE_attrib, needed for:
+
+  $value = $dbh->{$key};
+
+Its prototype is:
+
+  SV* dbd_db_FETCH_attrib(SV* dbh, imp_dbh_t* imp_dbh, SV* keysv);
+
+Unlike all previous methods this returns an SV with the value. Note
+that you should normally execute sv_2mortal, if you return a nonconstant
+value. (Constant values are C<&sv_undef>, C<&sv_no> and C<&sv_yes>.)
+
+Note, that DBI implements a caching algorithm for attribute values.
+If you think, that an attribute may be fetched, you store it in the
+dbh itself:
+
+  if (cacheit) /* cache value for later DBI 'quick' fetch? */
+      hv_store((HV*)SvRV(dbh), key, kl, cachesv, 0);
+
+=head3 The dbd_st_prepare method
+
+This is the private part of the I<prepare> method. Note that you
+B<must not> really execute the statement here. You may, for example,
+preparse and validate the statement or do similar things.
+
+  int dbd_st_prepare(SV* sth, imp_sth_t* imp_sth, char* statement,
+                     SV* attribs);
+
+A typical, simple, possibility is to do nothing and rely on the perl
+perpare() code that set the Statement attribute on the handle. This
+attribute can then be used by dbd_st_execute.
+
+If the driver supports placeholders then the NUM_OF_PARAMS attribute
+must be set correctly by dbd_st_prepare:
+
+  DBIc_NUM_PARAMS(imp_sth) = ...
+
+If you can, you should also setup attributes like NUM_OF_FIELDS,
+NAME, ... here, but DBI doesn't require that. However, if you do,
+document it.
+
+In any case you should set the IMPSET flag, as you did in
+I<dbd_db_connect> above:
+
+  DBIc_IMPSET_on(imp_sth);
+
+=head3 The dbd_st_execute method
+
+This is where a statement will really be executed.
+
+  int dbd_st_execute(SV* sth, imp_sth_t* imp_sth);
+
+Note, that you must be aware, that a statement may be executed
+repeatedly.
+Also, you should not expect, that I<finish> will be called between two
+executions, so you'll might need code like the following near the start
+of the function:
+
+  if (DBIc_ACTIVE(imp_sth))
+      dbd_st_finish(h, imp_sth);
+
+If your driver supports the binding of parameters (it should!), but the
+database doesn't, you must do it here. This can be done as follows:
+
+  SV *svp;
+  char* statement = DBD_ATTRIB_GET_PV(h, "Statement", 9, svp, "");
+  int numParam = DBIc_NUM_PARAMS(imp_sth);
+  int i;
+
+  for (i = 0; i < numParam; i++)
+  {
+      char* value = dbd_db_get_param(sth, imp_sth, i);
+      /* It is your drivers task to implement dbd_db_get_param,    */
+      /* it must be setup as a counterpart of dbd_bind_ph.         */
+      /* Look for '?' and replace it with 'value'.  Difficult      */
+      /* task, note that you may have question marks inside        */
+      /* quotes and comments the like ...  :-(                     */
+      /* See DBD::mysql for an example. (Don't look too deep into  */
+      /* the example, you will notice where I was lazy ...)        */
+  }
+
+The next thing is you really execute the statement.
+Note that you must set the attributes NUM_OF_FIELDS,
+NAME, etc when the statement is successfully executed if the driver has
+not already done so.
+They may be used even before a potential I<fetchrow>.
+In particular you have to tell DBI the number of fields, that the
+statement has, because it will be used by DBI internally.
+Thus the function will typically ends with:
+
+  if (isSelectStatement) {
+      DBIc_NUM_FIELDS(imp_sth) = numFields;
+      DBIc_ACTIVE_on(imp_sth);
+  }
+
+It is important that the ACTIVE flag only be set for C<SELECT> statements
+(or any other statements that can return multiple sets of values from
+the database using a cursor-like mechanism).
+See I<dbd_db_connect> above for more explanations.
+
+There plans for a preparse function to be provided by DBI, but this has
+not reached fruition yet.
+Meantime, if you want to know how ugly it can get, try looking at the
+I<dbd_ix_preparse> in DBD::Informix I<dbdimp.ec> and the related
+functions in I<iustoken.c> and I<sqltoken.c>.
+
+=head3 The dbd_st_fetch method
+
+This function fetches a row of data. The row is stored in in an array,
+of SV's that DBI prepares for you. This has two advantages: it is fast
+(you even reuse the SV's, so they don't have to be created after the
+first fetchrow), and it guarantees that DBI handles I<bind_cols> for
+you.
+
+What you do is the following:
+
+  AV* av;
+  int numFields = DBIc_NUM_FIELDS(imp_sth); /* Correct, if NUM_FIELDS
+      is constant for this statement. There are drivers where this is
+      not the case! */
+  int chopBlanks = DBIc_is(imp_sth, DBIcf_ChopBlanks);
+  int i;
+
+  if (!fetch_new_row_of_data(...)) {
+      ... /* check for error or end-of-data */
+      DBIc_ACTIVE_off(imp_sth); /* turn off Active flag automatically */
+      return Nullav;
+  }
+  /* get the fbav (field buffer array value) for this row       */
+  /* it is very important to only call this after you know      */
+  /* that you have a row of data to return.                     */
+  av = DBIc_DBISTATE(imp_sth)->get_fbav(imp_sth);
+  for (i = 0; i < numFields; i++) {
+      SV* sv = fetch_a_field(..., i);
+      if (chopBlanks && SvOK(sv) && type_is_blank_padded(field_type[i])) {
+          /*  Remove white space from end (only) of sv  */
+      }
+      sv_setsv(AvARRAY(av)[i], sv); /* Note: (re)use! */
+  }
+  return av;
+
+There's no need to use a fetch_a_field function returning an SV*.
+It's more common to use your database API functions to fetch the
+data as character strings and use code like this:
+
+  sv_setpvn(AvARRAY(av)[i], char_ptr, char_count);
+
+NULL values must be returned as undef. You can use code like this:
+
+  SvOK_off(AvARRAY(av)[i]);
+
+The function returns the AV prepared by DBI for success or C<Nullav>
+otherwise.
+
+ *FIX ME* Discuss what happens when there's no more data to fetch.
+ Are errors permitted if another fetch occurs after the first fetch
+ that reports no more data. (Permitted, not required.)
+
+If an error occurs which leaves the $sth in a state where remaining
+rows can't be fetched then Active should be turned off before the
+method returns.
+
+=head3 The dbd_st_finish3 method
+
+The C<$sth-E<gt>finish> method can be called if the user wishes to
+indicate that no more rows will be fetched even if the database has more
+rows to offer, and the DBI code can call the function when handles are
+being destroyed.
+See the DBI specification for more background details.
+In both circumstances, the DBI code ends up calling the
+C<dbd_st_finish3> method (if you provide a mapping for I<dbd_st_finish3>
+in I<dbdimp.h>), or I<dbd_st_finish> otherwise.
+The difference is that dbd_st_finish3 takes a third argument which is an
+C<int> with the value 1 if it is being called from a destroy method and
+0 otherwise.
+
+Note that DBI v1.32 and earlier test on dbd_db_finish3 to call
+dbd_st_finish3; if you provide dbd_st_finish3, either define
+dbd_db_finish3 too, or insist on DBI v1.33 or later.
+
+All it I<needs> to do is turn off the Active flag for the sth.
+It will only be called by Driver.xst code, if the driver has set ACTIVE
+to on for the sth.
+
+Outline example:
+
+  int dbd_st_finish3(SV* sth, imp_sth_t* imp_sth, int from_destroy) {
+      if (DBIc_ACTIVE(imp_sth))
+      {
+          /* close cursor or equivalent action */
+          DBIc_ACTIVE_off(imp_sth);
+      }
+      return 1;
+  }
+
+The from_destroy parameter is true if dbd_st_finish3 is being called
+from DESTROY - and so the statement is about to be destroyed.
+For many drivers there's no point in doing anything more than turing of
+the Active flag in this case.
+
+The function returns TRUE for success, FALSE otherwise, but there isn't
+a lot anyone can do to recover if there is an error.
+
+=head3 The dbd_st_destroy method
+
+This function is the private part of the statement handle destructor.
+
+  void dbd_st_destroy(SV* sth, imp_sth_t* imp_sth) {
+      ... /* any clean-up that's needed */
+      DBIc_IMPSET_off(imp_sth); /* let DBI know we've done it   */
+  }
+
+The DBI Driver.xst code will call dbd_st_finish for you, if the sth has
+the ACTIVE flag set, before calling dbd_st_destroy.
+
+=head3 The dbd_st_STORE_attrib and dbd_st_FETCH_attrib methods
+
+These functions correspond to dbd_db_STORE and dbd_db_FETCH attrib
+above, except that they are for statement handles.
+See above.
+
+  int dbd_st_STORE_attrib(SV* sth, imp_sth_t* imp_sth, SV* keysv,
+                          SV* valuesv);
+  SV* dbd_st_FETCH_attrib(SV* sth, imp_sth_t* imp_sth, SV* keysv);
+
+=head3 The dbd_bind_ph method
+
+This function is internally used by the I<bind_param> method, the
+I<bind_param_inout> method and by the DBI Driver.xst code if C<execute>
+is called with any bind parameters.
+
+  int dbd_bind_ph (SV *sth, imp_sth_t *imp_sth, SV *param,
+                   SV *value, IV sql_type, SV *attribs,
+                   int is_inout, IV maxlen);
+
+The I<param> argument holds an IV with the parameter number (1, 2, ...).
+The I<value> argument is the parameter value and I<sql_type> is its type.
+
+If your driver does not support bind_param_inout then you should
+ignore I<maxlen> and croak if I<is_inout> is TRUE.
+
+If your driver I<does> support bind_param_inout then you should
+note that I<value> is the SV I<after> dereferencing the reference
+passed to bind_param_inout.
+
+In drivers of simple databases the function will, for example, store
+the value in a parameter array and use it later in I<dbd_st_execute>.
+See the I<DBD::mysql> driver for an example.
+
+=head3 Implementing bind_param_inout support
+
+To provide support for parameters bound by reference rather than by
+value, the driver must do a number of things.  First, and most
+importantly, it must note the references and stash them in its own
+driver structure.  Secondly, when a value is bound to a column, the
+driver must discard any previous reference bound to the column.  On
+each execute, the driver must evaluate the references and internally
+bind the values resulting from the references.  This is only applicable
+if the user writes:
+
+  $sth->execute;
+
+If the user writes:
+
+  $sth->execute(@values);
+
+then DBI automatically calls the binding code for each element of
+@values.  These calls are indistinguishable from explicit user calls to
+bind_param.
+
+=head2 C/XS version of Makefile.PL
+
+The I<Makefile.PL> file for a C/XS driver is similar to the code needed
+for a pure Perl driver, but there are a number of extra bits of
+information needed by the build system.
+For example, the attributes list passed to C<WriteMakefile> needs to
+specify the object files that need to be compiled and built into the
+shared object (DLL).
+This is often, but not necessarily, just dbdimp.o (unless that should be
+dbdimp.obj because you're building on MS Windows).
+Note that you can reliably determine the extension of the object files
+from the $Config{obj_ext} values, and there are many other useful pieces
+of configuration information lurking in that hash.
+You get access to it with:
+
+    use Config;
+
+=head2 Methods which do not need to be written
+
+The DBI code implements the majority of the methods which are
+accessed using the notation DBI->function(), the only exceptions being
+DBI->connect() and DBI->data_sources() which require support from the
+driver.
+
+The DBI code implements the following documented driver, database and
+statement functions which do not need to be written by the DBD driver
+writer.
+
+=over 4
+
+=item $dbh->do()
+
+The default implementation of this function prepares, executes and
+destroys the statement.  This can be replaced if there is a better
+way to implement this, such as EXECUTE IMMEDIATE which can
+sometimes be used if there are no parameters.
+
+=item $h->errstr()
+
+=item $h->err()
+
+=item $h->state()
+
+=item $h->trace()
+
+The DBD driver does not need to worry about these routines at all.
+
+=item $h->{ChopBlanks}
+
+This attribute needs to be honured during fetch operations, but does
+not need to be handled by the attribute handling code.
+
+=item $h->{RaiseError}
+
+The DBD driver does not need to worry about this attribute at all.
+
+=item $h->{PrintError}
+
+The DBD driver does not need to worry about this attribute at all.
+
+=item $sth->bind_col()
+
+Assuming the driver uses the DBIc_DBISTATE(imp_xxh)->get_fbav() function (C drivers,
+see below), or the $sth->_set_fbav($data) method (Perl drivers)
+the driver does not need to do anything about this routine.
+
+=item $sth->bind_columns()
+
+Regardless of whether the driver uses DBIc_DBISTATE(imp_xxh)->get_fbav(), the driver
+does not need to do anything about this routine as it simply
+iteratively calls $sth->bind_col().
+
+=back
+
+The DBI code implements a default implementation of the following
+functions which do not need to be written by the DBD driver writer
+unless the default implementation is incorrect for the Driver.
+
+=over 4
+
+=item $dbh->quote()
+
+This should only be written if the database does not accept the ANSI
+SQL standard for quoting strings, with the string enclosed in single
+quotes and any embedded single quotes replaced by two consecutive
+single quotes.
+
+For the two argument form of quote, you need to implement the
+C<type_info> method to provide the information that quote needs.
+
+=item $dbh->ping()
+
+This should be implemented as a simple efficient way to determine
+whether the connection to the database is still alive. Typically
+code like this:
+
+  sub ping {
+      my $dbh = shift;
+      $sth = $dbh->prepare_cached(q{
+          select * from A_TABLE_NAME where 1=0
+      }) or return 0;
+      $sth->execute or return 0;
+      $sth->finish;
+      return 1;
+  }
+
+where A_TABLE_NAME is the name of a table that always exists (such as a
+database system catalogue).
+
+=back
+
+=head1 METADATA METHODS
+
+The exposition above ignores the DBI MetaData methods.
+The metadata methods are all associated with a database handle.
+
+=head2 Using DBI::DBD::Metadata
+
+The DBI::DBD::Metadata module is a good semi-automatic way for the developer of a DBD module to
+write the get_info and type_info functions quickly and accurately.
+
+=head3 Generating the get_info method
+
+Prior to DBI v1.33, this existed as the method write_getinfo_pm in the
+DBI::DBD module.
+From DBI v1.33, it exists as the method write_getinfo_pm in the
+DBI::DBD::Metadata module.
+This discussion assumes you have DBI v1.33 or later.
+
+You examine the documentation for write_getinfo_pm using:
+
+    perldoc DBI::DBD::Metadata
+
+To use it, you need a Perl DBI driver for your database which implements
+the get_info method.
+In practice, this means you need to install DBD::ODBC, an ODBC driver
+manager, and an ODBC driver for your database.
+With the pre-requisites in place, you might type:
+
+    perl -MDBI::DBD::Metadata -e write_getinfo_pm \
+            dbi:ODBC:foo_db username password Driver
+
+The procedure writes to standard output the code that should be added to
+your Driver.pm file and the code that should be written to
+lib/DBD/Driver/GetInfo.pm.
+You should review the output to ensure that it is sensible.
+
+=head3 Generating the type_info method
+
+Given the idea of the write_getinfo_pm method, it was not hard to devise
+a parallel method, write_typeinfo_pm, which does the analogous job for the
+DBI type_info_all metadata method.
+The the write_typeinfo_pm method was added to DBI v1.33.
+
+You examine the documentation for write_typeinfo_pm using:
+
+    perldoc DBI::DBD::Metadata
+
+The setup is exactly analogous to the mechanism descibed in
+L</Generating the get_info method>
+With the pre-requisites in place, you might type:
+
+    perl -MDBI::DBD::Metadata -e write_typeinfo \
+            dbi:ODBC:foo_db username password Driver
+
+The procedure writes to standard output the code that should be added to
+your Driver.pm file and the code that should be written to
+lib/DBD/Driver/TypeInfo.pm.
+You should review the output to ensure that it is sensible.
+
+=head2 Writing DBD::Driver::db::get_info
+
+If you use the DBI::DBD::Metadata module, then the code you need is
+generated for you.
+
+If you decide not to use the DBI::DBD::Metadata module, you should
+probably borrow the code from a driver that has done so (eg
+DBD::Informix from version 1.05 onwards) and crib the code from there,
+or look at the code that generates that module and follow that.
+The method in Driver.pm will be very simple; the method in
+lib/DBD/Driver/GetInfo.pm is not very much more complex unless your DBMS itself is
+much more complex.
+
+Note that some of the DBI utility methods rely on information from the
+get_info method to perform their operations correctly.
+See, for example, the quote_identifier and quote methods, discussed
+below.
+
+=head2 Writing DBD::Driver::db::type_info_all
+
+If you use the DBI::DBD::Metadata module, then the code you need is
+generated for you.
+
+If you decide not to use the DBI::DBD::Metadata module, you should
+probably borrow the code from a driver that has done so (eg
+DBD::Informix from version 1.05 onwards) and crib the code from there,
+or look at the code that generates that module and follow that.
+The method in Driver.pm will be very simple; the method in
+lib/DBD/Driver/TypeInfo.pm is not very much more complex unless your DBMS
+itself is much more complex.
+
+=head2 Writing DBD::Driver::db::type_info
+
+The guidelines on writing this method are still not really clear.
+No sample implementation is available.
+
+=head2 Writing DBD::Driver::db::table_info
+
+ *FIX ME* The guidelines on writing this method have not been written yet.
+ No sample implementation is available.
+
+=head2 Writing DBD::Driver::db::column_info
+
+ *FIX ME* The guidelines on writing this method have not been written yet.
+ No sample implementation is available.
+
+=head2 Writing DBD::Driver::db::primary_key_info
+
+ *FIX ME* The guidelines on writing this method have not been written yet.
+ No sample implementation is available.
+
+=head2 Writing DBD::Driver::db::primary_key
+
+ *FIX ME* The guidelines on writing this method have not been written yet.
+ No sample implementation is available.
+
+=head2 Writing DBD::Driver::db::foreign_key_info
+
+ *FIX ME* The guidelines on writing this method have not been written yet.
+ No sample implementation is available.
+
+=head2 Writing DBD::Driver::db::tables
+
+This method generates an array of names in a format suitable for being
+embedded in SQL statements in places where a table name is expected.
+
+If your database hews close enough to the SQL standard or if you have
+implemented an appropriate table_info function and and the appropriate
+quote_identifier function, then the DBI default version of this method
+will work for your driver too.
+
+Otherwise, you have to write a function yourself, such as:
+
+    sub tables
+    {
+        my($dbh, $cat, $sch, $tab, $typ) = @_;
+        my(@res);
+        my($sth) = $dbh->table_info($cat, $sch, $tab, $typ);
+        my(@arr);
+        while (@arr = $sth->fetchrow_array)
+        {
+            push @res, $dbh->quote_identifier($arr[0], $arr[1], $arr[2]);
+        }
+        return @res;
+    }
+
+See also the default implementation in DBI.pm.
+
+=head2 Writing DBD::Driver::db::quote
+
+This method takes a value and converts it into a string suitable for
+embedding in an SQL statement as a string literal.
+
+If your DBMS accepts the SQL standard notation for strings (single
+quotes around the string as a whole with any embedded single quotes
+doubled up), then you do not need to write this method as DBI provides a
+default method that does it for you.
+If your DBMS uses an alternative notation or escape mechanism, then you
+need to provide an equivalent function.
+For example, suppose your DBMS used C notation with double quotes around
+the string and backslashes escaping both double quotes and backslashes
+themselves.
+Then you might write the function as:
+
+    sub quote
+    {
+        my($dbh, $str) = @_;
+        $str =~ s/["\\]/\\$&/gmo;
+        return qq{"$str"};
+    }
+
+Handling newlines and other control characters is left as an exercise
+for the reader.
+
+This sample method ignores the $data_type indicator which is the
+optional second argument to the method.
+
+=head2 Writing DBD::Driver::db::quote_identifier
+
+This method is called to ensure that the name of the given table (or
+other database object) can be embedded into an SQL statement without
+danger of misinterpretation.
+The result string should be usable in the text of an SQL statement as
+the identifier for a table.
+
+If your DBMS accepts the SQL standard notation for quoted identifiers
+(which uses double quotes around the identifier as a whole, with any
+embedded double quotes doubled up) and accepts "schema"."identifier"
+(and "catalog"."schema"."identifier" when a catalog is specified), then
+you do not need to write this method as DBI provides a default method
+that does it for you.
+In fact, even if your DBMS does not handle exactly that notation but you
+have implemented the get_info method and it gives the correct responses,
+then it will work for you.
+If your database is fussier, then you need to implement your own version
+of the function.
+
+For example, DBD::Informix has to deal with an environment variable
+DELIMIDENT.
+If it is not set, then the DBMS treats names enclosed in double quotes
+as strings rather than names, which is usually a syntax error.
+Additionally, the catalog portion of the name is separated from the
+schema and table by a different delimiter (colon instead of dot), and
+the catalog portion is never enclosed in quotes.
+(Fortunately, valid strings for the catalog will never contain weird
+characters that might need to be escaped, unless you count dots, dashes,
+slashes and at-signs as weird.)
+Finally, an Informix database can contain objects that cannot be
+accessed because they were created by a user with the DELIMIDENT
+environment variable set, but the current user does not have it set.
+By design choice, the quote_identifier method encloses those identifiers
+in double quotes anyway, which generally triggers a syntax error, and
+the metadata methods which generate lists of tables etc omit those
+identifiers from the result sets.
+
+    sub quote_identifier
+    {
+        my($dbh, $cat, $sch, $obj) = @_;
+        my($rv) = "";
+        my($qq) = (defined $ENV{DELIMIDENT}) ? '"' : '';
+        $rv .= qq{$cat:} if (defined $cat);
+        if (defined $sch)
+        {
+            if ($sch !~ m/^\w+$/o)
+            {
+                $qq = '"';
+                $sch =~ s/$qq/$qq$qq/gm;
+            }
+            $rv .= qq{$qq$sch$qq.};
+        }
+        if (defined $obj)
+        {
+            if ($obj !~ m/^\w+$/o)
+            {
+                $qq = '"';
+                $obj =~ s/$qq/$qq$qq/gm;
+            }
+            $rv .= qq{$qq$obj$qq};
+        }
+        return $rv;
+    }
+
+Handling newlines and other control characters is left as an exercise
+for the reader.
+
+Note that there is an optional fourth parameter to this function which
+is a reference to a hash of attributes; this sample implementation
+ignores that.
+This sample implementation also ignores the single-argument variant of
+the method.
+
+=head1 WRITING AN EMULATION LAYER FOR AN OLD PERL INTERFACE
+
+Study Oraperl.pm (supplied with DBD::Oracle) and Ingperl.pm (supplied
+with DBD::Ingres) and the corresponding dbdimp.c files for ideas.
+
+Note that the emulation code sets $dbh->{CompatMode} = 1; for each
+connection so that the internals of the driver can implement behaviour
+compatible with the old interface when dealing with those handles.
+
+=head2 Setting emulation perl variables
+
+For example, ingperl has a $sql_rowcount variable. Rather than try
+to manually update this in Ingperl.pm it can be done faster in C code.
+In dbd_init():
+
+  sql_rowcount = perl_get_sv("Ingperl::sql_rowcount", GV_ADDMULTI);
+
+In the relevant places do:
+
+  if (DBIc_COMPAT(imp_sth))     /* only do this for compatibility mode handles */
+      sv_setiv(sql_rowcount, the_row_count);
+
+=head1 OTHER MISCELLANEOUS INFORMATION
+
+=head2 The imp_xyz_t types
+
+Any handle has a corresponding C structure filled with private data.
+Some of this data is reserved for use by DBI (except for using the
+DBIc macros below), some is for you. See the description of the
+I<dbdimp.h> file above for examples. The most functions in dbdimp.c
+are passed both the handle C<xyz> and a pointer to C<imp_xyz>. In
+rare cases, however, you may use the following macros:
+
+=over 2
+
+=item D_imp_dbh(dbh)
+
+Given a function argument I<dbh>, declare a variable I<imp_dbh> and
+initialize it with a pointer to the handles private data. Note: This
+must be a part of the function header, because it declares a variable.
+
+=item D_imp_sth(sth)
+
+Likewise for statement handles.
+
+=item D_imp_xxx(h)
+
+Given any handle, declare a variable I<imp_xxx> and initialize it
+with a pointer to the handles private data. It is safe, for example,
+to cast I<imp_xxx> to C<imp_dbh_t*>, if DBIc_TYPE(imp_xxx) == DBIt_DB.
+(You can also call sv_derived_from(h, "DBI::db"), but that's much
+slower.)
+
+=item D_imp_dbh_from_sth
+
+Given a imp_sth, declare a variable I<imp_dbh> and initialize it with a
+pointer to the parent database handle's implementors structure.
+
+=back
+
+=head2 Using DBIc_IMPSET_on
+
+The driver code which initializes a handle should use DBIc_IMPSET_on()
+as soon as its state is such that the cleanup code must be called.
+When this happens is determined by your driver code.
+
+Failure to call this can lead to corruption of data structures.
+For example, DBD::Informix maintains a linked list of database handles
+in the driver, and within each handle, a linked list of statements.
+Once a statement is added to the linked list, it is crucial that it is
+cleaned up (removed from the list).
+When DBIc_IMPSET_on() was being called too late, it was able to cause
+all sorts of problems.
+
+=head2 Using DBIc_is(), DBIc_has(), DBIc_on() and DBIc_off()
+
+Once upon a long time ago, the only way of handling the internal DBI
+boolean flags/attributes was through macros such as:
+
+  DBIc_WARN       DBIc_WARN_on        DBIc_WARN_off
+  DBIc_COMPAT     DBIc_COMPAT_on      DBIc_COMPAT_off
+
+Each of these took an imp_xxh pointer as an argument.
+
+Since then, new attributes have been added such as ChopBlanks,
+RaiseError and PrintError, and these do not have the full set of
+macros.
+The approved method for handling these is now the four macros:
+
+  DBIc_is(imp, flag)
+  DBIc_has(imp, flag)       an alias for DBIc_is
+  DBIc_on(imp, flag)
+  DBIc_off(imp, flag)
+  DBIc_set(imp, flag, on)   set if on is true, else clear
+
+Consequently, the DBIc_XXXXX family of macros is now mostly deprecated
+and new drivers should avoid using them, even though the older drivers
+will probably continue to do so for quite a while yet. However...
+
+There is an I<important exception> to that. The ACTIVE and IMPSET
+flags should be set via the DBIc_ACTIVE_on and DBIc_IMPSET_on macros,
+and unset via the DBIc_ACTIVE_off and DBIc_IMPSET_off macros.
+
+=head2 Using the get_fbav() method
+
+B<THIS IS CRITICAL> for C/XS drivers.
+
+The $sth->bind_col() and $sth->bind_columns() documented in the DBI
+specification do not have to be implemented by the driver writer because
+DBI takes care of the details for you.
+However, the key to ensuring that bound columns work is to call the
+function DBIc_DBISTATE(imp_xxh)->get_fbav() in the code which fetches a
+row of data.
+This returns an AV, and each element of the AV contains the SV which
+should be set to contain the returned data.
+
+The pure Perl equivalent is the $sth->_set_fbav($data) method, as
+described in the part on pure Perl drivers.
+
+=head1 SUBCLASSING DBI DRIVERS
+
+This is definitely an open subject. It can be done, as demonstrated by
+the I<DBD::File> driver, but it is not as simple as one might think.
+
+(Note that this topic is different from subclassing the DBI. For an
+example of that, see the t/subclass.t file supplied with the DBI.)
+
+The main problem is that the dbh's and sth's that your I<connect> and
+I<prepare> methods return are not instances of your I<DBD::Driver::db>
+or I<DBD::Driver::st> packages, they are not even derived from it.
+Instead they are instances of the I<DBI::db> or I<DBI::st> classes or
+a derived subclass. Thus, if you write a method I<mymethod> and do a
+
+  $dbh->mymethod()
+
+then the autoloader will search for that method in the package I<DBI::db>.
+Of course you can instead to a
+
+  $dbh->func('mymethod')
+
+and that will indeed work, even if I<mymethod> is inherited, but not
+without additional work. Setting C<@ISA> is not sufficient.
+
+=head2 Overwriting methods
+
+The first problem is, that the I<connect> method has no idea of
+subclasses. For example, you cannot implement base class and subclass
+in the same file: The I<install_driver> method wants to do a
+
+  require DBD::Driver;
+
+In particular, your subclass B<has> to be a separate driver, from
+the view of DBI, and you cannot share driver handles.
+
+Of course that's not much of a problem. You should even be able
+to inherit the base classes I<connect> method. But you cannot
+simply overwrite the method, unless you do something like this,
+quoted from I<DBD::CSV>:
+
+  sub connect ($$;$$$) {
+      my ($drh, $dbname, $user, $auth, $attr) = @_;
+
+      my $this = $drh->DBD::File::dr::connect($dbname, $user, $auth, $attr);
+      if (!exists($this->{csv_tables})) {
+          $this->{csv_tables} = {};
+      }
+
+      $this;
+  }
+
+Note that we cannot do a
+
+  $drh->SUPER::connect($dbname, $user, $auth, $attr);
+
+as we would usually do in a an OO environment, because $drh is an instance
+of I<DBI::dr>. And note, that the I<connect> method of I<DBD::File> is
+able to handle subclass attributes. See the description of Pure Perl
+drivers above.
+
+It is essential that you always call superclass method in the above
+manner. However, that should do.
+
+=head2 Attribute handling
+
+Fortunately the DBI specifications allow a simple, but still performant way of
+handling attributes. The idea is based on the convention that any
+driver uses a prefix I<driver_> for its private methods. Thus it's
+always clear whether to pass attributes to the super class or not.
+For example, consider this STORE method from the I<DBD::CSV> class:
+
+  sub STORE {
+      my ($dbh, $attr, $val) = @_;
+      if ($attr !~ /^driver_/) {
+          return $dbh->DBD::File::db::STORE($attr, $val);
+      }
+      if ($attr eq 'driver_foo') {
+      ...
+  }
+
+=cut
+
+use Exporter ();
+use Config qw(%Config);
+use Carp;
+use Cwd;
+use strict;
+use vars qw(
+    @ISA @EXPORT
+    $is_dbi
+);
+
+BEGIN {
+    if ($^O eq 'VMS') {
+	require vmsish;
+	import  vmsish;
+	require VMS::Filespec;
+	import  VMS::Filespec;
+    }
+    else {
+	*vmsify  = sub { return $_[0] };
+	*unixify = sub { return $_[0] };
+    }
+}
+
+@ISA = qw(Exporter);
+
+@EXPORT = qw(
+    dbd_dbi_dir
+    dbd_dbi_arch_dir
+    dbd_edit_mm_attribs
+    dbd_postamble
+);
+
+BEGIN {
+    $is_dbi = (-r 'DBI.pm' && -r 'DBI.xs' && -r 'DBIXS.h');
+    require DBI unless $is_dbi;
+}
+
+my $done_inst_checks;
+
+sub _inst_checks {
+    return if $done_inst_checks++;
+    my $cwd = cwd();
+    if ($cwd =~ /\Q$Config{path_sep}/) {
+	warn "*** Warning: Path separator characters (`$Config{path_sep}') ",
+	    "in the current directory path ($cwd) may cause problems\a\n\n";
+        sleep 2;
+    }
+    if ($cwd =~ /\s/) {
+	warn "*** Warning: whitespace characters ",
+	    "in the current directory path ($cwd) may cause problems\a\n\n";
+        sleep 2;
+    }
+    if (   $^O eq 'MSWin32'
+	&& $Config{cc} eq 'cl'
+	&& !(exists $ENV{'LIB'} && exists $ENV{'INCLUDE'}))
+    {
+	print <<EOT;
+*** You're using Microsoft Visual C++ compiler but the LIB and INCLUDE environment
+    variables are not both set. If you have 'unresolved external symbol'
+    errors during linking, run the vcvars32.bat batch file to set up your
+    LIB and INCLUDE environment variables, and try again.
+    A copy of vcvars32.bat can typically be found in the following
+    directories under your Visual Studio install directory:
+        Visual C++ 6.0:     vc98\\bin
+        Visual Studio .NET: vc7\\bin
+
+EOT
+	sleep 2;
+    }
+}
+
+sub dbd_edit_mm_attribs {
+    # this both edits the attribs in-place and returns the flattened attribs
+    my $mm_attr = shift;
+    my $dbd_attr = shift || {};
+    croak "dbd_edit_mm_attribs( \%makemaker [, \%other ]): too many parameters"
+	if @_;
+    _inst_checks();
+
+    # decide what needs doing
+
+    # do whatever needs doing
+    if ($dbd_attr->{create_pp_tests}) {
+	# XXX need to convert this to work within the generated Makefile
+	# so 'make' creates them and 'make clean' deletes them
+	my %test_variants = (
+	    pp => {	name => "DBI::PurePerl",
+			add => [ 'local $ENV{DBI_PUREPERL} = 2;' ],
+	    },
+	    mx => {	name => "DBD::Multiplex",
+			add => [ q{local $ENV{DBI_AUTOPROXY} = 'dbi:Multiplex:';} ],
+	    }
+	#   px => {	name => "DBD::Proxy",
+	#		need mechanism for starting/stopping the proxy server
+	#		add => [ q{local $ENV{DBI_AUTOPROXY} = 'dbi:Proxy:XXX';} ],
+	#   }
+	);
+	# currently many tests fail - DBD::Multiplex needs more work
+	# to bring it up to date and improve transparency.
+	delete $test_variants{mx}; # unless -f "lib/DBD/Multiplex.pm";
+
+	opendir DIR, 't' or die "Can't create variants of tests in 't' directory: $!";
+	my @tests = grep { /\.t$/ } readdir DIR;
+	closedir DIR;
+
+	# XXX one day we may try combinations here, ie pp+mx!
+
+	foreach my $test (sort @tests) {
+	    next if $test !~ /^[0-8]/;
+	    my $usethr = ($test =~ /(\d+|\b)thr/ && $] >= 5.008 && $Config{useithreads});
+
+	    while ( my ($v_type, $v_info) = each %test_variants ) {
+		my $v_test = "t/zv${v_type}_$test";
+		printf "Creating %-16s test variant: $v_test %s\n",
+		    $v_info->{name}, ($usethr) ? "(use threads)" : "";
+		open PPT, ">$v_test" or warn "Can't create $v_test: $!";
+		print PPT "#!perl -w\n";
+		print PPT "use threads;\n" if $usethr;
+		print PPT "$_\n" foreach @{$v_info->{add}};
+		print PPT "do 't/$test' or warn \$!;\n";
+		print PPT 'die if $@;'."\n";
+		print PPT "exit 0\n";
+		close PPT or warn "Error writing $v_test: $!";
+	    }
+	}
+    }
+    return %$mm_attr;
+}
+
+sub dbd_dbi_dir {
+    _inst_checks();
+    return '.' if $is_dbi;
+    my $dbidir = $INC{'DBI.pm'} || die "DBI.pm not in %INC!";
+    $dbidir =~ s:/DBI\.pm$::;
+    return $dbidir;
+}
+
+sub dbd_dbi_arch_dir {
+    _inst_checks();
+    return '$(INST_ARCHAUTODIR)' if $is_dbi;
+    my $dbidir = dbd_dbi_dir();
+    my @try = map  {    vmsify( unixify($_) . "/auto/DBI/"  ) } @INC;
+    my @xst = grep { -f vmsify( unixify($_) . "/Driver.xst" ) } @try;
+    Carp::croak("Unable to locate Driver.xst in @try") unless @xst;
+    Carp::carp( "Multiple copies of Driver.xst found in: @xst") if @xst > 1;
+    print "Using DBI $DBI::VERSION (for perl $] on $Config{archname}) installed in $xst[0]\n";
+    return $xst[0];
+}
+
+sub dbd_postamble {
+    my $self = shift;
+    _inst_checks();
+    my $dbi_instarch_dir = ($is_dbi) ? "." : dbd_dbi_arch_dir();
+    my $dbi_driver_xst= '$(DBI_INSTARCH_DIR)/Driver.xst';
+    my $xstf_h = '$(DBI_INSTARCH_DIR)/Driver_xst.h';
+    if ($^O eq 'VMS') {
+	$dbi_instarch_dir = vmsify($dbi_instarch_dir.'/');
+	$dbi_instarch_dir =~ s:/$::; # for buggy old vmsify's?
+	$dbi_driver_xst= '$(DBI_INSTARCH_DIR)Driver.xst';
+	$xstf_h = '$(DBI_INSTARCH_DIR)Driver_xst.h';
+    }
+
+    # we must be careful of quotes, expecially for Win32 here.
+    return '
+# --- This section was generated by DBI::DBD::dbd_postamble()
+DBI_INSTARCH_DIR='.$dbi_instarch_dir.'
+DBI_DRIVER_XST='.$dbi_driver_xst.'
+
+# The main dependancy (technically correct but probably not used)
+$(BASEEXT).c: $(BASEEXT).xsi
+
+# This dependancy is needed since MakeMaker uses the .xs.o rule
+$(BASEEXT)$(OBJ_EXT): $(BASEEXT).xsi
+
+$(BASEEXT).xsi: $(DBI_DRIVER_XST) '.$xstf_h.'
+	$(PERL) -p -e "s/~DRIVER~/$(BASEEXT)/g" $(DBI_DRIVER_XST) > $(BASEEXT).xsi
+
+# ---
+';
+}
+
+package DBDI; # just to reserve it via PAUSE for the future
+
+1;
+
+__END__
+
+=head1 AUTHORS
+
+Jonathan Leffler <jleffler@us.ibm.com> (previously <jleffler@informix.com>),
+Jochen Wiedmann <joe@ispsoft.de>,
+Steffen Goeldner <sgoeldner@cpan.org>,
+and Tim Bunce <dbi-users@perl.org>.
+
+=cut
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/DBD/Metadata.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/DBD/Metadata.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/DBD/Metadata.pm	(revision 14139)
@@ -0,0 +1,492 @@
+package DBI::DBD::Metadata;
+
+# $Id$
+#
+# Copyright (c) 1997-2003 Jonathan Leffler, Jochen Wiedmann,
+# Steffen Goeldner and Tim Bunce
+#
+# You may distribute under the terms of either the GNU General Public
+# License or the Artistic License, as specified in the Perl README file.
+
+use Exporter ();
+use Carp;
+
+use DBI;
+use DBI::Const::GetInfoType qw(%GetInfoType);
+
+# Perl 5.005_03 does not recognize 'our'
+@ISA = qw(Exporter);
+@EXPORT = qw(write_getinfo_pm write_typeinfo_pm);
+
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+use strict;
+
+=head1 NAME
+
+DBI::DBD::Metadata - Generate the code and data for some DBI metadata methods
+
+=head1 SYNOPSIS
+
+The idea is to extract metadata information from a good quality
+ODBC driver and use it to generate code and data to use in your own
+DBI driver for the same database.
+
+For generating code to support the get_info method:
+
+  perl -MDBI::DBD::Metadata -e "write_getinfo_pm('dbi:ODBC:dsn-name','user','pass','Driver')"
+
+  perl -MDBI::DBD::Metadata -e write_getinfo_pm dbi:ODBC:foo_db username password Driver
+
+For generating code to support the type_info method:
+
+  perl -MDBI::DBD::Metadata -e "write_typeinfo_pm('dbi:ODBC:dsn-name','user','pass','Driver')"
+
+  perl -MDBI::DBD::Metadata -e write_typeinfo_pm dbi:ODBC:dsn-name user pass Driver
+
+Where C<dbi:ODBC:dsn-name> is the connection to use to extract the
+data, and C<Driver> is the name of the driver you want the code
+generated for (the driver name gets embedded into the output in
+many places).
+
+=head1 Generating a GetInfo package for a driver
+
+The C<write_getinfo_pm> in the DBI::DBD::Metadata module generates a
+DBD::Driver::GetInfo package on standard output.
+
+This method generates a DBD::Driver::GetInfo package from the data
+source you specified in the parameter list or in the environment
+variable DBI_DSN.
+DBD::Driver::GetInfo should help a DBD author implementing the DBI
+get_info() method.
+Because you are just creating this package, it's very unlikely that
+DBD::Driver already provides a good implementation for get_info().
+Thus you will probably connect via DBD::ODBC.
+
+Once you are sure that it is producing semi-sane data, you would
+typically redirect the standard output to lib/DBD/Driver/GetInfo.pm, and
+then hand edit the result.
+Do not forget to update your Makefile.PL and MANIFEST to include this as
+an extra PM file that should be installed.
+
+If you connect via DBD::ODBC, you should use version 0.38 or greater;
+
+Please take a critical look at the data returned!
+ODBC drivers vary dramatically in their quality.
+
+The generator assumes that most values are static and places these
+values directly in the %info hash.
+A few examples show the use of CODE references and the implementation
+via subroutines.
+It is very likely that you have to write additional subroutines for
+values depending on the session state or server version, e.g.
+SQL_DBMS_VER.
+
+A possible implementation of DBD::Driver::db::get_info() may look like:
+
+  sub get_info {
+    my($dbh, $info_type) = @_;
+    require DBD::Driver::GetInfo;
+    my $v = $DBD::Driver::GetInfo::info{int($info_type)};
+    $v = $v->($dbh) if ref $v eq 'CODE';
+    return $v;
+  }
+
+Please replace Driver (or "<foo>") with the name of your driver.
+Note that this stub function is generated for you by write_getinfo_pm
+function, but you must manually transfer the code to Driver.pm.
+
+=cut
+
+sub write_getinfo_pm
+{
+    my ($dsn, $user, $pass, $driver) = @_ ? @_ : @ARGV;
+    my $dbh = DBI->connect($dsn, $user, $pass, {RaiseError=>1});
+    $driver = "<foo>" unless defined $driver;
+
+    print <<PERL;
+
+# Transfer this to ${driver}.pm
+
+# The get_info function was automatically generated by
+# DBI::DBD::Metadata::write_getinfo_pm v$DBI::DBD::Metadata::VERSION.
+
+package DBD::${driver}::db;         # This line can be removed once transferred.
+
+    sub get_info {
+        my(\$dbh, \$info_type) = \@_;
+        require DBD::${driver}::GetInfo;
+        my \$v = \$DBD::${driver}::GetInfo::info{int(\$info_type)};
+        \$v = \$v->(\$dbh) if ref \$v eq 'CODE';
+        return \$v;
+    }
+
+# Transfer this to lib/DBD/${driver}/GetInfo.pm
+
+# The \%info hash was automatically generated by
+# DBI::DBD::Metadata::write_getinfo_pm v$DBI::DBD::Metadata::VERSION.
+
+package DBD::${driver}::GetInfo;
+
+use strict;
+use DBD::${driver};
+
+# Beware: not officially documented interfaces...
+# use DBI::Const::GetInfoType qw(\%GetInfoType);
+# use DBI::Const::GetInfoReturn qw(\%GetInfoReturnTypes \%GetInfoReturnValues);
+
+my \$sql_driver = '${driver}';
+my \$sql_ver_fmt = '%02d.%02d.%04d';   # ODBC version string: ##.##.#####
+my \$sql_driver_ver = sprintf \$sql_ver_fmt, split (/\\./, \$DBD::${driver}::VERSION);
+PERL
+
+my $kw_map = 0;
+{
+# Informix CLI (ODBC) v3.81.0000 does not return a list of keywords.
+    local $\ = "\n";
+    local $, = "\n";
+    my ($kw) = $dbh->get_info($GetInfoType{SQL_KEYWORDS});
+    if ($kw)
+    {
+        print "\nmy \@Keywords = qw(\n";
+        print sort split /,/, $kw;
+        print ");\n\n";
+        print "sub sql_keywords {\n";
+        print q%    return join ',', @Keywords;%;
+        print "\n}\n\n";
+        $kw_map = 1;
+    }
+}
+
+    print <<'PERL';
+
+sub sql_data_source_name {
+    my $dbh = shift;
+    return "dbi:$sql_driver:" . $dbh->{Name};
+}
+
+sub sql_user_name {
+    my $dbh = shift;
+    # CURRENT_USER is a non-standard attribute, probably undef
+    # Username is a standard DBI attribute
+    return $dbh->{CURRENT_USER} || $dbh->{Username};
+}
+
+PERL
+
+	print "\nour \%info = (\n";
+    foreach my $key (sort keys %GetInfoType)
+    {
+        my $num = $GetInfoType{$key};
+        my $val = eval { $dbh->get_info($num); };
+        if ($key eq 'SQL_DATA_SOURCE_NAME') {
+            $val = '\&sql_data_source_name';
+        }
+        elsif ($key eq 'SQL_KEYWORDS') {
+            $val = ($kw_map) ? '\&sql_keywords' : 'undef';
+        }
+        elsif ($key eq 'SQL_DRIVER_NAME') {
+            $val = "\$INC{'DBD/$driver.pm'}";
+        }
+        elsif ($key eq 'SQL_DRIVER_VER') {
+            $val = '$sql_driver_ver';
+        }
+        elsif ($key eq 'SQL_USER_NAME') {
+            $val = '\&sql_user_name';
+        }
+        elsif (not defined $val) {
+            $val = 'undef';
+        }
+        elsif ($val eq '') {
+            $val = "''";
+        }
+        elsif ($val =~ /\D/) {
+            $val =~ s/\\/\\\\/g;
+            $val =~ s/'/\\'/g;
+            $val = "'$val'";
+        }
+        printf "%s %5d => %-30s # %s\n", (($val eq 'undef') ? '#' : ' '), $num, "$val,", $key;
+    }
+	print ");\n\n1;\n\n__END__\n";
+}
+
+
+
+=head1 Generating a TypeInfo package for a driver
+
+The C<write_typeinfo_pm> function in the DBI::DBD::Metadata module generates
+on standard output the data needed for a driver's type_info_all method.
+It also provides default implementations of the type_info_all
+method for inclusion in the driver's main implementation file.
+
+The driver parameter is the name of the driver for which the methods
+will be generated; for the sake of examples, this will be "Driver".
+Typically, the dsn parameter will be of the form "dbi:ODBC:odbc_dsn",
+where the odbc_dsn is a DSN for one of the driver's databases.
+The user and pass parameters are the other optional connection
+parameters that will be provided to the DBI connect method.
+
+Once you are sure that it is producing semi-sane data, you would
+typically redirect the standard output to lib/DBD/Driver/TypeInfo.pm,
+and then hand edit the result if necessary.
+Do not forget to update your Makefile.PL and MANIFEST to include this as
+an extra PM file that should be installed.
+
+Please take a critical look at the data returned!
+ODBC drivers vary dramatically in their quality.
+
+The generator assumes that all the values are static and places these
+values directly in the %info hash.
+
+A possible implementation of DBD::Driver::type_info_all() may look like:
+
+  sub type_info_all {
+    my ($dbh) = @_;
+    require DBD::Driver::TypeInfo;
+    return [ @$DBD::Driver::TypeInfo::type_info_all ];
+  }
+
+Please replace Driver (or "<foo>") with the name of your driver.
+Note that this stub function is generated for you by the write_typeinfo_pm
+function, but you must manually transfer the code to Driver.pm.
+
+=cut
+
+
+# These two are used by fmt_value...
+my %dbi_inv;
+my %sql_type_inv;
+
+#-DEBUGGING-#
+#sub print_hash
+#{
+#   my ($name, %hash) = @_;
+#   print "Hash: $name\n";
+#   foreach my $key (keys %hash)
+#   {
+#       print "$key => $hash{$key}\n";
+#   }
+#}
+#-DEBUGGING-#
+
+sub inverse_hash
+{
+    my (%hash) = @_;
+    my (%inv);
+    foreach my $key (keys %hash)
+    {
+        my $val = $hash{$key};
+        die "Double mapping for key value $val ($inv{$val}, $key)!"
+            if (defined $inv{$val});
+        $inv{$val} = $key;
+    }
+    return %inv;
+}
+
+sub fmt_value
+{
+    my ($num, $val) = @_;
+    if (!defined $val)
+    {
+        $val = "undef";
+    }
+    elsif ($val !~ m/^[-+]?\d+$/)
+    {
+        # All the numbers in type_info_all are integers!
+        # Anything that isn't an integer is a string.
+        # Ensure that no double quotes screw things up.
+        $val =~ s/"/\\"/g if ($val =~ m/"/o);
+        $val = qq{"$val"};
+    }
+    elsif ($dbi_inv{$num} =~ m/^(SQL_)?DATA_TYPE$/)
+    {
+        # All numeric...
+        $val = $sql_type_inv{$val}
+            if (defined $sql_type_inv{$val});
+    }
+    return $val;
+}
+
+sub write_typeinfo_pm
+{
+    my ($dsn, $user, $pass, $driver) = @_ ? @_ : @ARGV;
+    my $dbh = DBI->connect($dsn, $user, $pass, {AutoCommit=>1, RaiseError=>1});
+    $driver = "<foo>" unless defined $driver;
+
+    print <<PERL;
+
+# Transfer this to ${driver}.pm
+
+# The type_info_all function was automatically generated by
+# DBI::DBD::Metadata::write_typeinfo_pm v$DBI::DBD::Metadata::VERSION.
+
+package DBD::${driver}::db;         # This line can be removed once transferred.
+
+    sub type_info_all
+    {
+        my (\$dbh) = \@_;
+        require DBD::${driver}::TypeInfo;
+        return [ \@\$DBD::${driver}::TypeInfo::type_info_all ];
+    }
+
+# Transfer this to lib/DBD/${driver}/TypeInfo.pm.
+# Don't forget to add version and intellectual property control information.
+
+# The \%type_info_all hash was automatically generated by
+# DBI::DBD::Metadata::write_typeinfo_pm v$DBI::DBD::Metadata::VERSION.
+
+package DBD::${driver}::TypeInfo;
+
+{
+    require Exporter;
+    require DynaLoader;
+    \@ISA = qw(Exporter DynaLoader);
+    \@EXPORT = qw(type_info_all);
+    use DBI qw(:sql_types);
+
+PERL
+
+    # Generate SQL type name mapping hashes.
+	# See code fragment in DBI specification.
+    my %sql_type_map;
+    foreach (@{$DBI::EXPORT_TAGS{sql_types}})
+    {
+        no strict 'refs';
+        $sql_type_map{$_} = &{"DBI::$_"}();
+        $sql_type_inv{$sql_type_map{$_}} = $_;
+    }
+    #-DEBUG-# print_hash("sql_type_map", %sql_type_map);
+    #-DEBUG-# print_hash("sql_type_inv", %sql_type_inv);
+
+    my %dbi_map =
+        (
+            TYPE_NAME          =>  0,
+            DATA_TYPE          =>  1,
+            COLUMN_SIZE        =>  2,
+            LITERAL_PREFIX     =>  3,
+            LITERAL_SUFFIX     =>  4,
+            CREATE_PARAMS      =>  5,
+            NULLABLE           =>  6,
+            CASE_SENSITIVE     =>  7,
+            SEARCHABLE         =>  8,
+            UNSIGNED_ATTRIBUTE =>  9,
+            FIXED_PREC_SCALE   => 10,
+            AUTO_UNIQUE_VALUE  => 11,
+            LOCAL_TYPE_NAME    => 12,
+            MINIMUM_SCALE      => 13,
+            MAXIMUM_SCALE      => 14,
+            SQL_DATA_TYPE      => 15,
+            SQL_DATETIME_SUB   => 16,
+            NUM_PREC_RADIX     => 17,
+            INTERVAL_PRECISION => 18,
+        );
+
+    #-DEBUG-# print_hash("dbi_map", %dbi_map);
+
+    %dbi_inv = inverse_hash(%dbi_map);
+
+    #-DEBUG-# print_hash("dbi_inv", %dbi_inv);
+
+    my $maxlen = 0;
+    foreach my $key (keys %dbi_map)
+    {
+        $maxlen = length($key) if length($key) > $maxlen;
+    }
+
+    # Print the name/value mapping entry in the type_info_all array;
+    my $fmt = "            \%-${maxlen}s => \%2d,\n";
+    my $numkey = 0;
+    my $maxkey = 0;
+    print "    \$type_info_all = [\n        {\n";
+    foreach my $i (sort { $a <=> $b } keys %dbi_inv)
+    {
+        printf($fmt, $dbi_inv{$i}, $i);
+        $numkey++;
+        $maxkey = $i;
+    }
+    print "        },\n";
+
+    print STDERR "### WARNING - Non-dense set of keys ($numkey keys, $maxkey max key)\n"
+        unless $numkey = $maxkey + 1;
+
+    my $h = $dbh->type_info_all;
+    my @tia = @$h;
+    my %odbc_map = map { uc $_ => $tia[0]->{$_} } keys %{$tia[0]};
+    shift @tia;     # Remove the mapping reference.
+    my $numtyp = $#tia;
+
+    #-DEBUG-# print_hash("odbc_map", %odbc_map);
+
+    # In theory, the key/number mapping sequence for %dbi_map
+    # should be the same as the one from the ODBC driver.  However, to
+    # prevent the possibility of mismatches, and to deal with older
+    # missing attributes or unexpected new ones, we chase back through
+    # the %dbi_inv and %odbc_map hashes, generating @dbi_to_odbc
+    # to map our new key number to the old one.
+    # Report if @dbi_to_odbc is not an identity mapping.
+    my @dbi_to_odbc;
+    foreach my $num (sort { $a <=> $b } keys %dbi_inv)
+    {
+        # Find the name in %dbi_inv that matches this index number.
+        my $dbi_key = $dbi_inv{$num};
+        #-DEBUG-# print "dbi_key = $dbi_key\n";
+        #-DEBUG-# print "odbc_key = $odbc_map{$dbi_key}\n";
+        # Find the index in %odbc_map that has this key.
+        $dbi_to_odbc[$num] = (defined $odbc_map{$dbi_key}) ? $odbc_map{$dbi_key} : undef;
+    }
+
+    # Determine the length of the longest formatted value in each field
+    my @len;
+    for (my $i = 0; $i <= $numtyp; $i++)
+    {
+        my @odbc_val = @{$tia[$i]};
+        for (my $num = 0; $num <= $maxkey; $num++)
+        {
+            # Find the value of the entry in the @odbc_val array.
+            my $val = (defined $dbi_to_odbc[$num]) ? $odbc_val[$dbi_to_odbc[$num]] : undef;
+            $val = fmt_value($num, $val);
+            #-DEBUG-# print "val = $val\n";
+            $val = "$val,";
+            $len[$num] = length($val) if !defined $len[$num] || length($val) > $len[$num];
+        }
+    }
+
+    # Generate format strings to left justify each string in maximum field width.
+    my @fmt;
+    for (my $i = 0; $i <= $maxkey; $i++)
+    {
+        $fmt[$i] = "%-$len[$i]s";
+        #-DEBUG-# print "fmt[$i] = $fmt[$i]\n";
+    }
+
+    # Format the data from type_info_all
+    for (my $i = 0; $i <= $numtyp; $i++)
+    {
+        my @odbc_val = @{$tia[$i]};
+        print "        [ ";
+        for (my $num = 0; $num <= $maxkey; $num++)
+        {
+            # Find the value of the entry in the @odbc_val array.
+            my $val = (defined $dbi_to_odbc[$num]) ? $odbc_val[$dbi_to_odbc[$num]] : undef;
+            $val = fmt_value($num, $val);
+            printf $fmt[$num], "$val,";
+        }
+        print " ],\n";
+    }
+
+    print "    ];\n\n    1;\n}\n\n__END__\n";
+
+}
+
+1;
+
+__END__
+
+=head1 AUTHORS
+
+Jonathan Leffler <jleffler@us.ibm.com> (previously <jleffler@informix.com>),
+Jochen Wiedmann <joe@ispsoft.de>,
+Steffen Goeldner <sgoeldner@cpan.org>,
+and Tim Bunce <dbi-users@perl.org>.
+
+=cut
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/FAQ.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/FAQ.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/FAQ.pm	(revision 14139)
@@ -0,0 +1,985 @@
+###
+### $Id$
+###
+### DBI Frequently Asked Questions POD
+###
+### Copyright section reproduced from below.
+###
+### This document is Copyright (c)1994-2000 Alligator Descartes, with portions
+### Copyright (c)1994-2000 their original authors. This module is released under
+### the 'Artistic' license which you can find in the perl distribution.
+### 
+### This document is Copyright (c)1997-2000 Alligator Descartes. All rights reserved.
+### Permission to distribute this document, in full or in part, via email,
+### Usenet, ftp archives or http is granted providing that no charges are involved,
+### reasonable attempt is made to use the most current version and all credits
+### and copyright notices are retained ( the I<AUTHOR> and I<COPYRIGHT> sections ).
+### Requests for other distribution rights, including incorporation into 
+### commercial products, such as books, magazine articles or CD-ROMs should be
+### made to Alligator Descartes <I<http://www.symbolstone.org/descarte/contact.html>>.
+### 
+### $Log$
+### Revision 1.1  2006/05/25 02:55:26  mdewsnip
+### Initial revision
+###
+# Revision 11.2  2001/08/24  22:10:44  timbo
+# *** empty log message ***
+#
+# Revision 10.8  2001/05/29  23:25:55  timbo
+# *** empty log message ***
+#
+# Revision 10.7  2001/03/28  14:52:07  timbo
+# Main checkin prior to 1.15 release
+#
+
+package DBI::FAQ;
+
+$VERSION = '0.38';
+
+=head1 NAME
+
+DBI::FAQ -- The Frequently Asked Questions for the Perl5 Database Interface
+
+=for html
+<BODY BGCOLOR="#ffffff" TEXT="#000000" LINK="#3a15ff" ALINK="#ff0000" VLINK="#ff282d">
+<!--#include virtual="/technology/perl/DBI/templatetop.html" -->
+<CENTER>
+<FONT SIZE="+2">
+DBI Frequently Asked Questions v.0.38
+</FONT>
+<BR>
+<FONT SIZE="-1">
+<I>Last updated: February 8th, 2000</I>
+</FONT>
+</CENTER>
+<P>
+
+=head1 SYNOPSIS
+
+    perldoc DBI::FAQ
+
+=head1 VERSION
+
+This document is currently at version I<0.38>, as of I<February 8th, 2000>.
+
+=head1 DESCRIPTION
+
+This document serves to answer the most frequently asked questions on both
+the DBI Mailing Lists and personally to members of the DBI development team.
+
+=head1 Basic Information & Information Sources
+
+=head2 1.1 What is DBI, DBperl, Oraperl and *perl?
+
+To quote Tim Bunce, the architect and author of DBI:
+
+    ``DBI is a database access Application Programming Interface (API)
+      for the Perl Language. The DBI API Specification defines a set
+      of functions, variables and conventions that provide a consistent
+      database interface independant of the actual database being used.''
+
+In simple language, the DBI interface allows users to access multiple database
+types transparently. So, if you connecting to an Oracle, Informix, mSQL, Sybase
+or whatever database, you don't need to know the underlying mechanics of the
+3GL layer. The API defined by DBI will work on I<all> these database types.
+
+A similar benefit is gained by the ability to connect to two I<different>
+databases of different vendor within the one perl script, I<ie>, I want
+to read data from an Oracle database and insert it back into an Informix
+database all within one program. The DBI layer allows you to do this simply
+and powerfully.
+
+
+=for html
+Here's a diagram that demonstrates the principle:
+<P>
+<CENTER>
+<IMG SRC="img/dbiarch.gif" WIDTH=451 HEIGHT=321 ALT="[ DBI Architecture ]">
+</CENTER>
+<P>
+
+I<DBperl> is the old name for the interface specification. It's usually
+now used to denote perlI<4> modules on database interfacing, such as,
+I<oraperl>, I<isqlperl>, I<ingperl> and so on. These interfaces
+didn't have a standard API and are generally I<not> supported.
+
+Here's a list of DBperl modules, their corresponding DBI counterparts and
+support information. I<Please note>, the author's listed here generally
+I<do not> maintain the DBI module for the same database. These email
+addresses are unverified and should only be used for queries concerning the
+perl4 modules listed below. DBI driver queries should be directed to the
+I<dbi-users> mailing list.
+
+    Module Name	Database Required   Author          DBI
+    -----------	-----------------   ------          ---
+    Sybperl     Sybase              Michael Peppler DBD::Sybase
+                                    <mpeppler@itf.ch>
+    Oraperl     Oracle 6 & 7        Kevin Stock     DBD::Oracle
+                                    <dbi-users@perl.org>
+    Ingperl     Ingres              Tim Bunce &     DBD::Ingres
+                                    Ted Lemon
+                                    <dbi-users@perl.org>
+    Interperl   Interbase           Buzz Moschetti  DBD::Interbase
+                                    <buzz@bear.com>
+    Uniperl     Unify 5.0           Rick Wargo      None
+                                    <rickers@coe.drexel.edu>
+    Pgperl      Postgres            Igor Metz       DBD::Pg
+                                    <metz@iam.unibe.ch>
+    Btreeperl   NDBM                John Conover    SDBM?
+                                    <john@johncon.com>
+    Ctreeperl   C-Tree              John Conover    None
+                                    <john@johncon.com>
+    Cisamperl   Informix C-ISAM     Mathias Koerber None
+                                    <mathias@unicorn.swi.com.sg>
+    Duaperl     X.500 Directory     Eric Douglas    None
+                User Agent
+
+However, some DBI modules have DBperl emulation layers, so, I<DBD::Oracle>
+comes with an Oraperl emulation layer, which allows you to run legacy oraperl
+scripts without modification. The emulation layer translates the oraperl API
+calls into DBI calls and executes them through the DBI switch.
+
+Here's a table of emulation layer information:
+
+    Module		    Emulation Layer     Status
+    ------          ---------------     ------
+    DBD::Oracle     Oraperl             Complete
+    DBD::Informix   Isqlperl            Under development
+    DBD::Ingres     Ingperl             Complete?
+    DBD::Sybase     Sybperl             Working? ( Needs verification )
+    DBD::mSQL       Msqlperl            Experimentally released with 
+                                        DBD::mSQL-0.61
+
+The I<Msqlperl> emulation is a special case. I<Msqlperl> is a perl5 driver
+for I<mSQL> databases, but does not conform to the DBI Specification. It's
+use is being deprecated in favour of I<DBD::mSQL>. I<Msqlperl> may be downloaded
+from CPAN I<via>:
+
+    http://www.perl.com/cgi-bin/cpan_mod?module=Msqlperl
+
+=head2 1.2. Where can I get it from?
+
+The Comprehensive Perl Archive Network
+resources should be used for retrieving up-to-date versions of the DBI
+and drivers. CPAN may be accessed I<via> Tom Christiansen's splendid 
+I<CPAN multiplexer> program located at:
+
+    http://www.perl.com/CPAN/
+
+For more specific version information and exact URLs of drivers, please see
+the DBI drivers list and the DBI module pages which can be found on:
+
+    http://dbi.perl.org/
+    http://www.symbolstone.org/technology/perl/DBI
+
+This list is automatically generated on a nightly basis from CPAN and should
+be up-to-date.
+
+=head2 1.3. Where can I get more information?
+
+There are a few information sources on DBI. 
+
+=over 4
+
+=item I<"Programming the Perl DBI">
+
+"Programming the Perl DBI" is the I<official> book on the DBI written by
+Alligator Descartes and Tim Bunce and published by O'Reilly & Associates.
+The book was released on February 9th, 2000.
+
+The table of contents is:
+
+    Preface
+    1. Introduction
+        From Mainframes to Workstations
+        Perl
+        DBI in the Real World
+        A Historical Interlude and Standing Stones
+    2. Basic Non-DBI Databases
+        Storage Managers and Layers
+        Query Languages and Data Functions
+        Standing Stones and the Sample Database
+        Flat-File Databases
+        Putting Complex Data into Flat Files
+        Concurrent Database Access and Locking
+        DBM Files and the Berkeley Database Manager
+        The MLDBM Module
+        Summary
+    3. SQL and Relational Databases
+        The Relational Database Methodology
+        Datatypes and NULL Values
+        Querying Data
+        Modifying Data Within Tables
+        Creating and Destroying Tables
+    4. Programming with the DBI
+        DBI Architecture
+        Handles
+        Data Source Names
+        Connection and Disconnection
+        Error Handling
+        Utility Methods and Functions
+    5. Interacting with the Database
+        Issuing Simple Queries
+        Executing Non-SELECT Statements
+        Binding Parameters to Statements
+        Binding Output Columns
+        do() Versus prepare()
+        Atomic and Batch Fetching
+    6. Advanced DBI
+        Handle Attributes and Metadata
+        Handling LONG/LOB Data
+        Transactions, Locking, and Isolation
+    7. ODBC and the DBI
+        ODBC -- Embraced and Extended
+        DBI -- Thrashed and Mutated
+        The Nuts and Bolts of ODBC
+        ODBC from Perl
+        The Marriage of DBI and ODBC
+        Questions and Choices
+        Moving Between Win32::ODBC and the DBI
+        And What About ADO?
+    8. DBI Shell and Database Proxying
+        dbish -- The DBI Shell
+        Database Proxying
+    A. DBI Specification
+    B. Driver and Database Characteristics
+    C. ASLaN Sacred Site Charter
+    Index
+
+The book should be available from all good bookshops and can be ordered online
+either <I>via</I> O'Reilly & Associates
+
+    http://www.oreilly.com/catalog/perldbi
+
+or Amazon
+
+    http://www.amazon.com/exec/obidos/ASIN/1565926994/dbi
+
+=item I<POD documentation>
+
+I<POD>s are chunks of documentation usually embedded within perl programs
+that document the code ``I<in place>'', providing a useful resource for
+programmers and users of modules. POD for DBI and drivers is beginning to 
+become more commonplace, and documentation for these modules can be read
+with the C<perldoc> program included with Perl.
+
+=over 4 
+
+=item The DBI Specification
+
+The POD for the DBI Specification can be read with the:
+
+    perldoc DBI
+
+command. The Specification also forms Appendix A of "Programming the Perl
+DBI".
+
+=item Oraperl
+
+Users of the Oraperl emulation layer bundled with I<DBD::Oracle>, may read
+up on how to program with the Oraperl interface by typing:
+
+    perldoc Oraperl
+
+This will produce an updated copy of the original oraperl man page written by
+Kevin Stock for perl4. The oraperl API is fully listed and described there.
+
+=item Drivers
+
+Users of the DBD modules may read about some of the private functions
+and quirks of that driver by typing:
+
+    perldoc <driver>
+
+For example, the I<DBD::mSQL> driver is bundled with driver-specific 
+documentation that can be accessed by typing
+
+    perldoc DBD::mSQL
+
+=item Frequently Asked Questions
+
+This document, the I<Frequently Asked Questions> is also available as POD
+documentation! You can read this on your own system by typing:
+
+    perldoc DBI::FAQ
+
+This may be more convenient to persons not permanently, or conveniently,
+connected to the Internet. The I<DBI::FAQ> module should be downloaded and
+installed for the more up-to-date version.
+
+The version of I<DBI::FAQ> shipped with the C<DBI> module may be slightly out
+of date.
+
+=item POD in general
+
+Information on writing POD, and on the philosophy of POD in general, can be
+read by typing:
+
+    perldoc perlpod
+
+Users with the Tk module installed may be interested to learn there is a
+Tk-based POD reader available called C<tkpod>, which formats POD in a convenient
+and readable way. This is available I<via> CPAN as the module called 
+I<Tk::POD> and is highly recommended.
+
+=back
+
+=item I<Driver and Database Characteristics>
+
+The driver summaries that were produced for Appendix B of "Programming the
+Perl DBI" are available online at:
+
+    http://dbi.perl.org/
+    http://www.symbolstone.org/technology/perl/DBI
+
+in the driver information table. These summaries contain standardised
+information on each driver and database which should aid you in selecting
+a database to use. It will also inform you quickly of any issues within
+drivers or whether a driver is not fully compliant with the DBI Specification.
+
+=item I<Rambles, Tidbits and Observations>
+
+    http://dbi.perl.org/tidbits
+    http://www.symbolstone.org/technology/perl/DBI/tidbits
+
+There are a series of occasional rambles from various people on the
+DBI mailing lists who, in an attempt to clear up a simple point, end up
+drafting fairly comprehensive documents. These are quite often varying in
+quality, but do provide some insights into the workings of the interfaces.
+
+=item I<Articles>
+
+A list of articles discussing the DBI can be found on the DBI WWW page at:
+
+    http://dbi.perl.org/
+    http://www.symbolstone.org/technology/perl/DBI
+
+These articles are of varying quality and age, from the original Perl Journal
+article written by Alligator and Tim, to more recent debacles published online
+from about.com.
+
+=item I<README files>
+
+The I<README> files included with each driver occasionally contains 
+some useful information ( no, really! ) that may be pertinent to the user.
+Please read them. It makes our worthless existences more bearable. These
+can all be read from the main DBI WWW page at:
+
+    http://dbi.perl.org/
+    http://www.symbolstone.org/technology/perl/DBI
+
+=item I<Mailing Lists>
+
+There are three mailing lists for DBI:
+
+    dbi-announce@perl.org     -- for announcements, very low traffic
+    dbi-users@perl.org        -- general user support
+    dbi-dev@perl.org          -- for driver developers (no user support)
+
+For information on how to subscribe, set digest mode etc, and unsubscribe,
+send an email message (the content will be ignored) to:
+
+    dbi-announce-help@perl.org
+    dbi-users-help@perl.org
+    dbi-dev-help@perl.org
+
+=item I<Mailing List Archives>
+
+=over 4
+
+=item I<US Mailing List Archives>
+
+    http://outside.organic.com/mail-archives/dbi-users/
+
+Searchable hypermail archives of the three mailing lists, and some of the
+much older traffic have been set up for users to browse.
+
+=item I<European Mailing List Archives>
+
+    http://www.rosat.mpe-garching.mpg.de/mailing-lists/PerlDB-Interest
+
+As per the US archive above.
+
+=back
+
+=back
+
+=head1 Compilation Problems
+
+=head2 2.1. Compilation problems or "It fails the test!"
+
+First off, consult the README for that driver in case there is useful 
+information about the problem. It may be a known problem for your given 
+architecture and operating system or database. You can check the README
+files for each driver in advance online at:
+
+    http://dbi.perl.org/
+    http://www.symbolstone.org/technology/perl/DBI
+
+If it's a known problem, you'll probably have to wait till it gets fixed. If 
+you're I<really> needing it fixed, try the following:
+
+=over 4
+
+=item I<Attempt to fix it yourself>
+
+This technique is generally I<not> recommended to the faint-hearted.
+If you do think you have managed to fix it, then, send a patch file
+( context diff ) to the author with an explanation of:
+
+=over 4
+
+=item *
+
+What the problem was, and test cases, if possible.
+
+=item *
+
+What you needed to do to fix it. Please make sure you mention everything.
+
+=item *
+
+Platform information, database version, perl version, module version and 
+DBI version.
+
+=back
+
+=item I<Email the author> Do I<NOT> whinge!
+
+Please email the address listed in the WWW pages for whichever driver you
+are having problems with. Do I<not> directly email the author at a
+known address unless it corresponds with the one listed.
+
+We tend to have real jobs to do, and we do read the mailing lists for
+problems. Besides, we may not have access to <I<insert your
+favourite brain-damaged platform here>> and couldn't be of any
+assistance anyway! Apologies for sounding harsh, but that's the way of it!
+
+However, you might catch one of these creative genii at 3am when we're
+doing this sort of stuff anyway, and get a patch within 5 minutes. The
+atmosphere in the DBI circle is that we I<do> appreciate the users'
+problems, since we work in similar environments.
+
+If you are planning to email the author, please furnish as much information
+as possible, I<ie>:
+
+=over 4
+
+=item *
+
+I<ALL> the information asked for in the README file in
+the problematic module. And we mean I<ALL> of it. We don't
+put lines like that in documentation for the good of our health, or
+to meet obscure README file standards of length.
+
+=item *
+
+If you have a core dump, try the I<Devel::CoreStack> module for
+generating a stack trace from the core dump. Send us that too.
+I<Devel::CoreStack> can be found on CPAN at:
+
+    http://www.perl.com/cgi-bin/cpan_mod?module=Devel::CoreStack
+
+=item *
+
+Module versions, perl version, test cases, operating system versions
+and I<any other pertinent information>.
+
+=back
+
+Remember, the more information you send us, the quicker we can track 
+problems down. If you send us no useful information, expect nothing back.
+
+Finally, please be aware that some authors, including Tim Bunce, specifically
+request that you do I<not> mail them directly. Please respect their wishes and
+use the email addresses listed in the appropriate module C<README> file.
+
+=item I<Email the dbi-users Mailing List>
+
+It's usually a fairly intelligent idea to I<cc> the mailing list
+anyway with problems. The authors all read the lists, so you lose nothing
+by mailing there.
+
+=back
+
+=head1 Platform and Driver Issues
+
+=head2 3.1 What's the difference between ODBC and DBI?
+
+In terms of architecture - not much: Both define programming
+interfaces. Both allow multiple drivers to be loaded to do the
+actual work.
+
+In terms of ease of use - much: The DBI is a 'high level' interface
+that, like Perl itself, strives to make the simple things easy while
+still making the hard things possible. The ODBC is a 'low level'
+interface. All nuts-bolts-knobs-and-dials.
+
+Now there's an ODBC driver for the DBI (DBD::ODBC) the "What's the
+difference" question is more usefully rephrased as:
+
+Chapter 7 of "Programming the Perl DBI" covers this topic in far more
+detail and should be consulted.
+
+=head2 3.2 What's the difference between Win32::ODBC and DBD::ODBC?
+
+The DBI, and thus DBD::ODBC, has a different philosophy from the
+Win32::ODBC module:
+
+The Win32::ODBC module is a 'thin' layer over the low-level ODBC API.
+The DBI defines a simpler 'higher level' interface.
+
+The Win32::ODBC module gives you access to more of the ODBC API.
+The DBI and DBD::ODBC give you access to only the essentials.
+(But, unlike Win32::ODBC, the DBI and DBD::ODBC do support parameter
+binding and multiple prepared statements which reduces the load on
+the database server and can dramatically increase performance.)
+
+The Win32::ODBC module only works on Win32 systems.
+The DBI and DBD::ODBC are very portable and work on Win32 and Unix.
+
+The DBI and DBD::ODBC modules are supplied as a standard part of the
+Perl 5.004 binary distribution for Win32 (they don't work with the
+older, non-standard, ActiveState port).
+
+Scripts written with the DBI and DBD::ODBC are faster than Win32::ODBC
+on Win32 and are trivially portable to other supported database types.
+  
+The DBI offers optional automatic printing or die()ing on errors which
+makes applications simpler and more robust.
+  
+The current DBD::ODBC driver version 0.16 is new and not yet fully stable.
+A new release is due soon [relative to the date of the next TPJ issue :-]
+and will be much improved and offer more ODBC functionality.
+
+To summarise: The Win32::ODBC module is your best choice if you need
+access to more of the ODBC API than the DBI gives you. Otherwise, the
+DBI and DBD::ODBC combination may be your best bet.
+
+Chapter 7 of "Programming the Perl DBI" covers this topic in far more
+detail and should be consulted.
+
+=head2 3.3 Is DBI supported under Windows 95 / NT platforms?
+
+Finally, yes! Jeff Urlwin has been working diligently on building
+I<DBI> and I<DBD::ODBC> under these platforms, and, with the
+advent of a stabler perl and a port of I<MakeMaker>, the project has
+come on by great leaps and bounds.
+
+The I<DBI> and I<DBD::Oracle> Win32 ports are now a standard part of DBI,
+so, downloading I<DBI> of version higher than I<0.81> should work fine as 
+should using the most recent I<DBD::Oracle> version.
+
+=head2 3.4 Can I access Microsoft Access or SQL-Server databases with DBI?
+
+Yes, use the I<DBD::ODBC> driver.
+
+=head2 3.5 Is the a DBD for <I<insert favourite database here>>?
+
+Is is listed on the DBI drivers page?
+
+    http://dbi.perl.org/
+    http://www.symbolstone.org/technology/perl/DBI
+
+If not, no. A complete absence of a given database driver from that
+page means that no-one has announced any intention to work on it, not that
+such a driver is impossible to write.
+
+A corollary of the above statement implies that if you see an announcement
+for a driver I<not> on the above page, there's a good chance it's not
+actually a I<DBI> driver, and may not conform to the specifications. Therefore,
+questions concerning problems with that code should I<not> really be addressed
+to the DBI Mailing Lists.
+
+=head2 3.6 What's DBM? And why should I use DBI instead?
+
+Extracted from ``I<DBI - The Database Interface for Perl 5>'':
+
+    ``UNIX was originally blessed with simple file-based ``databases'', namely
+    the dbm system. dbm lets you store data in files, and retrieve
+    that data quickly. However, it also has serious drawbacks.
+
+        File Locking
+
+        The dbm systems did not allow particularly robust file locking
+        capabilities, nor any capability for correcting problems arising through
+        simultaneous writes [ to the database ].
+
+        Arbitrary Data Structures
+
+        The dbm systems only allows a single fixed data structure:
+        key-value pairs. That value could be a complex object, such as a
+        [ C ] struct, but the key had to be unique. This was a large
+        limitation on the usefulness of dbm systems.
+
+    However, dbm systems still provide a useful function for users with
+    simple datasets and limited resources, since they are fast, robust and 
+    extremely well-tested. Perl modules to access dbm systems have now
+    been integrated into the core Perl distribution via the
+    AnyDBM_File module.''
+
+To sum up, DBM is a perfectly satisfactory solution for essentially read-only
+databases, or small and simple datasets. However, for more 
+scaleable dataset handling, not to mention robust transactional locking, 
+users are recommended to use a more powerful database engine I<via> I<DBI>.
+
+Chapter 2 of "Programming the Perl DBI" discusses DBM files in detail.
+
+=head2 3.7 What database do you recommend me using?
+
+This is a particularly thorny area in which an objective answer is difficult
+to come by, since each dataset, proposed usage and system configuration
+differs from person to person.
+
+From the current author's point of view, if the dataset is relatively
+small, being tables of less than 1 million rows, and less than 1000 tables
+in a given database, then I<mSQL> is a perfectly acceptable solution
+to your problem. This database is extremely cheap, is wonderfully robust
+and has excellent support. More information is available on the Hughes
+Technology WWW site at:
+
+    http://www.hughes.com.au
+
+You may also wish to look at MySQL which is a more powerful database engine
+that has a similar feel to mSQL.
+
+    http://www.tcx.se
+
+If the dataset is larger than 1 million row tables or 1000 tables, or if you
+have either more money, or larger machines, I would recommend I<Oracle RDBMS>.
+Oracle's WWW site is an excellent source of more information.
+
+    http://www.oracle.com
+
+I<Informix> is another high-end RDBMS that is worth considering. There are
+several differences between Oracle and Informix which are too complex for
+this document to detail. Information on Informix can be found on their
+WWW site at:
+
+    http://www.informix.com
+
+In the case of WWW fronted applications, I<mSQL> may be a better option
+due to slow connection times between a CGI script and the Oracle RDBMS and
+also the amount of resource each Oracle connection will consume. I<mSQL>
+is lighter resource-wise and faster.
+
+These views are not necessarily representative of anyone else's opinions,
+and do not reflect any corporate sponsorship or views. They are provided
+I<as-is>.
+
+=head2 3.8 Is <I<insert feature here>> supported in DBI?
+
+Given that we're making the assumption that the feature you have requested
+is a non-standard database-specific feature, then the answer will be I<no>.
+
+DBI reflects a I<generic> API that will work for most databases, and has
+no database-specific functionality.
+
+However, driver authors may, if they so desire, include hooks to database-specific
+functionality through the C<func()> method defined in the DBI API.
+Script developers should note that use of functionality provided I<via>
+the C<func()> methods is very unlikely to be portable across databases.
+
+=head1 Programming Questions
+
+=head2 4.1 Is DBI any use for CGI programming?
+
+In a word, yes! DBI is hugely useful for CGI programming! In fact, I would
+tentatively say that CGI programming is one of two top uses for DBI.
+
+DBI confers the ability to CGI programmers to power WWW-fronted databases
+to their users, which provides users with vast quantities of ordered
+data to play with. DBI also provides the possibility that, if a site is
+receiving far too much traffic than their database server can cope with, they
+can upgrade the database server behind the scenes with no alterations to
+the CGI scripts.
+
+=head2 4.2 How do I get faster connection times with DBD::Oracle and CGI?
+
+    Contributed by John D. Groenveld
+
+The Apache C<httpd> maintains a pool of C<httpd> children to service client 
+requests.
+
+Using the Apache I<mod_perl> module by I<Doug MacEachern>, the perl 
+interpreter is embedded with the C<httpd> children. The CGI, DBI, and your 
+other favorite modules can be loaded at the startup of each child. These 
+modules will not be reloaded unless changed on disk.
+
+For more information on Apache, see the Apache Project's WWW site:
+
+    http://www.apache.org
+
+The I<mod_perl> module can be downloaded from CPAN I<via>:
+
+    http://www.perl.com/cgi-bin/cpan_mod?module=Apache
+
+=head2 4.3 How do I get persistent connections with DBI and CGI?
+
+    Contributed by John D. Groenveld
+
+Using Edmund Mergl's I<Apache::DBI> module, database logins are stored in a 
+hash with each of these C<httpd> child. If your application is based on a 
+single database user, this connection can be started with each child. 
+Currently, database connections cannot be shared between C<httpd> children.
+
+I<Apache::DBI> can be downloaded from CPAN I<via>:
+
+    http://www.perl.com/cgi-bin/cpan_mod?module=Apache::DBI
+
+=head2 4.4 ``When I run a perl script from the command line, it works, but, when I run it under the C<httpd>, it fails!'' Why?
+
+Basically, a good chance this is occurring is due to the fact that the user
+that you ran it from the command line as has a correctly configured set of
+environment variables, in the case of I<DBD::Oracle>, variables like
+C<ORACLE_HOME>, C<ORACLE_SID> or C<TWO_TASK>.
+
+The C<httpd> process usually runs under the user id of C<nobody>,
+which implies there is no configured environment. Any scripts attempting to
+execute in this situation will correctly fail.
+
+One way to solve this problem is to set the environment for your database in a
+C<BEGIN { }> block at the top of your script. Another technique is to configure
+your WWW server to pass-through certain environment variables to your CGI 
+scripts.
+
+Similarly, you should check your C<httpd> error logfile for any clues,
+as well as the ``Idiot's Guide To Solving Perl / CGI Problems'' and
+``Perl CGI Programming FAQ'' for further information. It is
+unlikely the problem is DBI-related.
+
+The ``Idiot's Guide To Solving Perl / CGI Problems'' can be located at:
+
+    http://www.perl.com/perl/faq/index.html
+
+as can the ``Perl CGI Programming FAQ''. Read I<BOTH> these documents 
+carefully!
+
+=head2 4.5 How do I get the number of rows returned from a C<SELECT> statement?
+
+Count them. Read the DBI docs for the C<rows()> method.
+
+=head1 Miscellaneous Questions
+
+=head2 5.1 Can I do multi-threading with DBI?
+
+Perl version 5.005 and later can be built to support multi-threading.
+The DBI, as of version 1.02, does not yet support multi-threading
+so it would be unsafe to let more than one thread enter the DBI at
+the same time.
+
+It is expected that some future version of the DBI will at least be
+thread-safe (but not thread-hot) by automatically blocking threads
+intering the DBI while it's already in use.
+
+For some OCI example code for Oracle that has multi-threaded C<SELECT>
+statements, see:
+
+    http://www.symbolstone.org/technology/oracle/oci/orathreads.tar.gz
+
+=head2 5.2 How do I handle BLOB data with DBI?
+
+Handling BLOB data with the DBI is very straight-forward. BLOB columns are
+specified in a SELECT statement as per normal columns. However, you also
+need to specify a maximum BLOB size that the <I>database handle</I> can
+fetch using the C<LongReadLen> attribute.
+
+For example:
+
+    ### $dbh is a connected database handle
+    $sth = $dbh->prepare( "SELECT blob_column FROM blobby_table" );
+    $sth->execute;
+
+would fail.
+
+    ### $dbh is a connected database handle
+    ### Set the maximum BLOB size...
+    $dbh->{LongReadLen} = 16384;        ### 16Kb...Not much of a BLOB!
+
+    $sth = $dbh->prepare( "..." );
+
+would succeed <I>provided no column values were larger than the specified
+value</I>.
+
+If the BLOB data is longer than the value of C<LongReadLen>, then an
+error will occur. However, the DBI provides an additional piece of
+functionality that will automatically truncate the fetched BLOB to the
+size of C<LongReadLen> if it is longer. This does not cause an error to
+occur, but may make your fetched BLOB data useless.
+
+This behaviour is regulated by the C<LongTruncOk> attribute which is 
+defaultly set to a false value ( thus making overlong BLOB fetches fail ).
+
+    ### Set BLOB handling such that it's 16Kb and can be truncated
+    $dbh->{LongReadLen} = 16384;
+    $dbh->{LongTruncOk} = 1;
+
+Truncation of BLOB data may not be a big deal in cases where the BLOB
+contains run-length encoded data, but data containing checksums at the end,
+for example, a ZIP file, would be rendered useless.
+  
+=head2 5.3 How can I invoke stored procedures with DBI?
+
+The DBI does not define a database-independent way of calling stored procedures.
+
+However, most database that support them also provide a way to call
+them from SQL statements - and the DBI certainly supports that.
+
+So, assuming that you have created a stored procedure within the target
+database, I<eg>, an Oracle database, you can use C<$dbh>->C<do()> to
+immediately execute the procedure. For example,
+
+    $dbh->do( "BEGIN someProcedure; END;" );   # Oracle-specific
+
+You should also be able to C<prepare> and C<execute>, which is
+the recommended way if you'll be calling the procedure often.
+
+=head2 5.4 How can I get return values from stored procedures with DBI?
+
+    Contributed by Jeff Urlwin
+
+    $sth = $dbh->prepare( "BEGIN foo(:1, :2, :3); END;" );
+    $sth->bind_param(1, $a);
+    $sth->bind_param_inout(2, \$path, 2000);
+    $sth->bind_param_inout(3, \$success, 2000);
+    $sth->execute;
+
+Remember to perform error checking, though! ( Or use the C<RaiseError>
+attribute ).
+
+=head2 5.5 How can I create or drop a database with DBI?
+
+Database creation and deletion are concepts that are entirely too abstract
+to be adequately supported by DBI. For example, Oracle does not support the
+concept of dropping a database at all! Also, in Oracle, the database
+I<server> essentially I<is> the database, whereas in mSQL, the
+server process runs happily without any databases created in it. The
+problem is too disparate to attack in a worthwhile way.
+
+Some drivers, therefore, support database creation and deletion through
+the private C<func()> methods. You should check the documentation for
+the drivers you are using to see if they support this mechanism.
+
+=head2 5.6 How can I C<commit> or C<rollback> a statement with DBI?
+
+See the C<commit()> and C<rollback()> methods in the DBI Specification.
+
+Chapter 6 of "Programming the Perl DBI" discusses transaction handling within
+the context of DBI in more detail.
+
+=head2 5.7 How are C<NULL> values handled by DBI?
+
+C<NULL> values in DBI are specified to be treated as the value C<undef>.
+C<NULL>s can be inserted into databases as C<NULL>, for example:
+
+    $rv = $dbh->do( "INSERT INTO table VALUES( NULL )" );
+
+but when queried back, the C<NULL>s should be tested against C<undef>.
+This is standard across all drivers.
+
+=head2 5.8 What are these C<func()> methods all about?
+
+The C<func()> method is defined within DBI as being an entry point
+for database-specific functionality, I<eg>, the ability to create or
+drop databases. Invoking these driver-specific methods is simple, for example,
+to invoke a C<createDatabase> method that has one argument, we would
+write:
+
+    $rv =$dbh->func( 'argument', 'createDatabase' );
+
+Software developers should note that the C<func()> methods are
+non-portable between databases.
+
+=head2 5.9 Is DBI Year 2000 Compliant?
+
+DBI has no knowledge of understanding of what dates are. Therefore, DBI
+itself does not have a Year 2000 problem. Individual drivers may use date
+handling code internally and therefore be potentially susceptible to the
+Year 2000 problem, but this is unlikely.
+
+You may also wish to read the ``Does Perl have a Year 2000 problem?'' section
+of the Perl FAQ at:
+
+    http://www.perl.com/CPAN/doc/FAQs/FAQ/PerlFAQ.html
+
+=head1 Support and Training
+
+The Perl5 Database Interface is I<FREE> software. IT COMES WITHOUT WARRANTY
+OF ANY KIND. See the DBI README for more details.
+
+However, some organizations are providing either technical support or
+training programs on DBI. The present author has no knowledge as
+to the quality of these services. The links are included for reference
+purposes only and should not be regarded as recommendations in any way.
+I<Caveat emptor>.
+
+=head2 Commercial Support
+
+=over 4
+
+=item The Perl Clinic
+
+The Perl Clinic provides commercial support for I<Perl> and Perl
+related problems, including the I<DBI> and its drivers.  Support is
+provided by the company with whom Tim Bunce, author of I<DBI> and
+I<DBD::Oracle>, works and ActiveState. For more information on their
+services, please see:
+
+    http://www.perlclinic.com
+
+=back
+
+=head2 Training
+
+=over 4
+
+=item Westlake Solutions
+
+A hands-on class for experienced Perl CGI developers that teaches
+how to write database-connected CGI scripts using Perl and DBI.pm.  This
+course, along with four other courses on CGI scripting with Perl, is
+taught in Washington, DC; Arlington, Virginia; and on-site worldwide upon
+request.
+
+See:
+
+    http://www.westlake.com/training
+
+for more details.
+
+=back
+
+=head1 Other References
+
+In this section, we present some miscellaneous WWW links that may be of
+some interest to DBI users. These are not verified and may result in
+unknown sites or missing documents.
+
+    http://www-ccs.cs.umass.edu/db.html
+    http://www.odmg.org/odmg93/updates_dbarry.html
+    http://www.jcc.com/sql_stnd.html
+
+=head1 AUTHOR
+
+Alligator Descartes <I<http://www.symbolstone.org/descarte/contact.html>>. 
+Portions are Copyright their original stated authors.
+
+=head1 COPYRIGHT
+
+This document is Copyright (c)1994-2000 Alligator Descartes, with portions
+Copyright (c)1994-2000 their original authors. This module is released under
+the 'Artistic' license which you can find in the perl distribution.
+
+This document is Copyright (c)1997-2000 Alligator Descartes. All rights reserved.
+Permission to distribute this document, in full or in part, via email,
+Usenet, ftp archives or http is granted providing that no charges are involved,
+reasonable attempt is made to use the most current version and all credits
+and copyright notices are retained ( the I<AUTHOR> and I<COPYRIGHT> sections ).
+Requests for other distribution rights, including incorporation into 
+commercial products, such as books, magazine articles or CD-ROMs should be
+made to Alligator Descartes <I<http://www.symbolstone.org/descarte/contact.html>>.
+
+=for html
+<!--#include virtual="/technology/perl/DBI/templatebottom.html" -->
+</BODY>
+</HTML>
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/Profile.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/Profile.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/Profile.pm	(revision 14139)
@@ -0,0 +1,662 @@
+package DBI::Profile;
+
+=head1 NAME
+
+DBI::Profile - Performance profiling and benchmarking for the DBI
+
+=head1 SYNOPSIS
+
+The easiest way to enable DBI profiling is to set the DBI_PROFILE
+environment variable to 2 and then run your code as usual:
+
+  DBI_PROFILE=2 prog.pl
+
+This will profile your program and then output a textual summary
+grouped by query.  You can also enable profiling by setting the
+Profile attribute of any DBI handle:
+
+  $dbh->{Profile} = 2;
+
+Other values are possible - see L<"ENABLING A PROFILE"> below.
+
+=head1 DESCRIPTION
+
+DBI::Profile is new and experimental and subject to change.
+
+The DBI::Profile module provides a simple interface to collect and
+report performance and benchmarking data from the DBI.
+
+For a more elaborate interface, suitable for larger programs, see
+L<DBI::ProfileDumper|DBI::ProfileDumper> and L<dbiprof|dbiprof>.
+For Apache/mod_perl applications see
+L<DBI::ProfileDumper::Apache|DBI::ProfileDumper::Apache>.
+
+=head1 OVERVIEW
+
+Performance data collection for the DBI is built around several
+concepts which are important to understand clearly.
+
+=over 4
+
+=item Method Dispatch
+
+Every method call on a DBI handle passes through a single 'dispatch'
+function which manages all the common aspects of DBI method calls,
+such as handling the RaiseError attribute.
+
+=item Data Collection
+
+If profiling is enabled for a handle then the dispatch code takes
+a high-resolution timestamp soon after it is entered. Then, after
+calling the appropriate method and just before returning, it takes
+another high-resolution timestamp and calls a function to record
+the information.  That function is passed the two timestamps
+plus the DBI handle and the name of the method that was called.
+That information about a single DBI method call is called the
+I<profile sample> data.
+
+=item Data Filtering
+
+If the method call was invoked by the DBI or by a driver then the
+call is currently ignored for profiling because the time spent will
+be accounted for by the original 'outermost' call.
+
+For example, the calls that the selectrow_arrayref() method makes
+to prepare() and execute() etc. are not counted individually
+because the time spent in those methods is going to be allocated
+to the selectrow_arrayref() method when it returns. If this was not
+done then it would be very easy to double count time spent inside
+the DBI.
+
+In future releases it may be possible to alter this behaviour.
+
+=item Data Storage Tree
+
+The profile data is stored as 'leaves on a tree'. The 'path' through
+the branches of the tree to the particular leaf that will store the
+profile sample data for a profiled call is determined dynamically.
+This is a powerful feature.
+
+For example, if the Path is
+
+  [ 'foo', 'bar', 'baz' ]
+
+then the new profile sample data will be I<merged> into the tree at
+
+  $h->{Profile}->{Data}->{foo}->{bar}->{baz}
+
+It wouldn't be very useful to merge all the call data into one leaf
+node (except to get an overall 'time spent inside the DBI' total).
+It's more common to want the Path to include the current statement
+text and/or the name of the method called to show what the time
+spent inside the DBI was for.
+
+The Path can contain some 'magic cookie' values that are automatically
+replaced by corresponding dynamic values when they're used.
+For example DBIprofile_Statement (exported by DBI::profile) is
+automatically replaced by value of the C<Statement> attribute of
+the handle. For example, is the Path was:
+
+  [ 'foo', DBIprofile_Statement, 'bar' ]
+
+and the value of $h->{Statement} was:
+
+  SELECT * FROM tablename
+
+then the profile data will be merged into the tree at:
+
+  $h->{Profile}->{Data}->{foo}->{SELECT * FROM tablename}->{bar}
+
+The default Path is just C<[ DBIprofile_Statement ]> and so by
+default the profile data is aggregated per distinct Statement string.
+
+For statement handles this is always simply the string that was
+given to prepare() when the handle was created.  For database handles
+this is the statement that was last prepared or executed on that
+database handle. That can lead to a little 'fuzzyness' because, for
+example, calls to the quote() method to build a new statement will
+typically be associated with the previous statement. In practice
+this isn't a significant issue and the dynamic Path mechanism can
+be used to setup your own rules.
+
+=item Profile Data
+
+Profile data is stored at the 'leaves' of the tree as references
+to an array of numeric values. For example:
+
+    [
+      106,                    # count
+      0.0312958955764771,     # total duration
+      0.000490069389343262,   # first duration
+      0.000176072120666504,   # shortest duration
+      0.00140702724456787,    # longest duration
+      1023115819.83019,       # time of first event
+      1023115819.86576,       # time of last event
+    ]
+
+=back
+
+=head1 ENABLING A PROFILE
+
+Profiling is enabled for a handle by assigning to the Profile
+attribute. For example:
+
+  $h->{Profile} = DBI::Profile->new();
+
+The Profile attribute holds a blessed reference to a hash object
+that contains the profile data and attributes relating to it.
+The class the Profile object is blessed into is expected to
+provide at least a DESTROY method which will dump the profile data
+to the DBI trace file handle (STDERR by default).
+
+All these examples have the same effect as the first:
+
+  $h->{Profile} = {};
+  $h->{Profile} = "DBI::Profile";
+  $h->{Profile} = "2/DBI::Profile";
+  $h->{Profile} = 2;
+
+If a non-blessed hash reference is given then the DBI::Profile
+module is automatically C<require>'d and the reference is blessed
+into that class.
+
+If a string is given then it is split on 'C</>' characters and the
+first value is used to select the Path to be used (see below).
+The second value, if present, is used as the name of a module which
+will be loaded and it's C<new> method called. If not present it
+defaults to DBI::Profile. Any other values are passed as arguments
+to the C<new> method. For example: "C<2/DBIx::OtherProfile/Foo/42>".
+
+Various common sequences for Path can be selected by simply assigning
+an integer value to Profile. The simplest way to explain how the
+values are interpreted is to show the code:
+
+    push @Path, "DBI"                       if $path & 0x01;
+    push @Path, DBIprofile_Statement        if $path & 0x02;
+    push @Path, DBIprofile_MethodName       if $path & 0x04;
+    push @Path, DBIprofile_MethodClass      if $path & 0x08;
+
+So using the value "C<1>" causes all profile data to be merged into
+a single leaf of the tree. That's useful when you just want a total.
+
+Using "C<2>" causes profile sample data to be merged grouped by
+the corresponding Statement text. This is the most frequently used.
+
+Using "C<4>" causes profile sample data to be merged grouped by
+the method name ('FETCH', 'prepare' etc.). Using "C<8>" is similar
+but gives the fully qualified 'glob name' of the method called. For
+example: '*DBD::Driver::db::prepare', '*DBD::_::st::fetchrow_hashref'.
+
+The values can be added together to create deeper paths. The most
+useful being 6 (statement then method name) or 10 (statement then
+method name with class).  Using a negative number will reverse the
+path. Thus -6 will group by method name then statement.
+
+The spliting and parsing of string values assigned to the Profile
+attribute may seem a little odd, but there's a good reason for it.
+Remember that attributes can be embedded in the Data Source Name
+string which can be passed in to a script as a parameter. For
+example:
+
+    dbi:DriverName(RaiseError=>1,Profile=>2):dbname
+
+And also, if the C<DBI_PROFILE> environment variable is set then
+The DBI arranges for every driver handle to share the same profile
+object. When perl exits a single profile summary will be generated
+that reflects (as nearly as practical) the total use of the DBI by
+the application.
+
+
+=head1 THE PROFILE OBJECT
+
+The DBI core expects the Profile attribute value to be a hash
+reference and if the following values don't exist it will create
+them as needed:
+
+=head2 Data
+
+A reference to a hash containing the collected profile data.
+
+=head2 Path
+
+The Path value is used to control where the profile for a method
+call will be merged into the collected profile data.  Whenever
+profile data is to be stored the current value for Path is used.
+
+The value can be one of:
+
+=over 4
+
+=item Array Reference
+
+Each element of the array defines an element of the path to use to
+store the profile data into the C<Data> hash.
+
+=item Undefined value (the default)
+
+Treated the same as C<[ $DBI::Profile::DBIprofile_Statement ]>.
+
+=item Subroutine Reference B<NOT YET IMPLEMENTED>
+
+The subroutine is passed the DBI method name and the handle it was
+called on.  It should return a list of values to uses as the path.
+If it returns an empty list then the method call is not profiled.
+
+=back
+
+The following 'magic cookie' values can be included in the Path and will be
+
+=over 4
+
+=item DBIprofile_Statement
+
+Replaced with the current value of the Statement attribute for the
+handle the method was called with. If that value is undefined then
+an empty string is used.
+
+=item DBIprofile_MethodName
+
+Replaced with the name of the DBI method that the profile sample
+relates to.
+
+=item DBIprofile_MethodClass
+
+Replaced with the fully qualified name of the DBI method, including
+the package, that the profile sample relates to. This shows you
+where the method was implemented. For example:
+
+  'DBD::_::db::selectrow_arrayref' =>
+      0.022902s
+  'DBD::mysql::db::selectrow_arrayref' =>
+      2.244521s / 99 = 0.022445s avg (first 0.022813s, min 0.022051s, max 0.028932s)
+
+The "DBD::_::db::selectrow_arrayref" shows that the driver has
+inherited the selectrow_arrayref method provided by the DBI.
+
+But you'll note that there is only one call to
+DBD::_::db::selectrow_arrayref but another 99 to
+DBD::mysql::db::selectrow_arrayref. That's because after the first
+call Perl has cached the method to speed up method calls.
+You may also see some names begin with an asterix ('C<*>').
+Both of these effects are subject to change in later releases.
+
+
+=back
+
+Other magic cookie values may be added in the future.
+
+
+=head1 REPORTING
+
+=head2 Report Format
+
+The current profile data can be formatted and output using
+
+    print $h->{Profile}->format;
+
+To discard the profile data and start collecting fresh data
+you can do:
+
+    $h->{Profile}->{Data} = undef;
+
+
+The default results format looks like this:
+
+  DBI::Profile: 0.001015s (5 calls) programname @ YYYY-MM-DD HH:MM:SS
+  '' =>
+      0.000024s / 2 = 0.000012s avg (first 0.000015s, min 0.000009s, max 0.000015s)
+  'SELECT mode,size,name FROM table' =>
+      0.000991s / 3 = 0.000330s avg (first 0.000678s, min 0.000009s, max 0.000678s)
+
+Which shows the total time spent inside the DBI, with a count of
+the total number of method calls and the name of the script being
+run, then a formated version of the profile data tree.
+
+If the results are being formated when the perl process is exiting
+(which is usually the case when the DBI_PROFILE environment variable
+is used) then the percentage of time the process spent inside the
+DBI is also shown.
+
+In the example above the paths in the tree are only one level deep and
+use the Statement text as the value (that's the default behaviour).
+
+The merged profile data at the 'leaves' of the tree are presented
+as total time spent, count, average time spent (which is simply total
+time divided by the count), then the time spent on the first call,
+the time spent on the fastest call, and finally the time spent on
+the slowest call.
+
+The 'avg', 'first', 'min' and 'max' times are not particularly
+useful when the profile data path only contains the statement text.
+Here's an extract of a more detailed example using both statement
+text and method name in the path:
+
+  'SELECT mode,size,name FROM table' =>
+      'FETCH' =>
+          0.000076s
+      'fetchrow_hashref' =>
+          0.036203s / 108 = 0.000335s avg (first 0.000490s, min 0.000152s, max 0.002786s)
+
+Here you can see the 'avg', 'first', 'min' and 'max' for the
+108 calls to fetchrow_hashref() become rather more interesting.
+Also the data for FETCH just shows a time value because it was only
+called once.
+
+Currently the profile data is output sorted by branch names. That
+may change in a later version so the leaf nodes are sorted by total
+time per leaf node.
+
+
+=head2 Report Destination
+
+The default method of reporting is for the DESTROY method of the
+Profile object to format the results and write them using:
+
+    DBI->trace_msg($results, 0);  # see $ON_DESTROY_DUMP below
+
+to write them to the DBI trace() filehandle (which defaults to
+STDERR). To direct the DBI trace filehandle to write to a file
+without enabling tracing the trace() method can be called with a
+trace level of 0. For example:
+
+    DBI->trace(0, $filename);
+
+The same effect can be achieved without changing the code by
+setting the C<DBI_TRACE> environment variable to C<0=filename>.
+
+The $DBI::Profile::ON_DESTROY_DUMP variable holds a code ref
+that's called to perform the output of the formatted results.
+The default value is:
+
+  $ON_DESTROY_DUMP = sub { DBI->trace_msg($results, 0) };
+
+Apart from making it easy to send the dump elsewhere, it can also
+be useful as a simple way to disable dumping results.
+
+=head1 CHILD HANDLES
+
+Child handles inherit a reference to the Profile attribute value
+of their parent.  So if profiling is enabled for a database handle
+then by default the statement handles created from it all contribute
+to the same merged profile data tree.
+
+
+=head1 CUSTOM DATA COLLECTION
+
+=head2 Using The Path Attribute
+
+  XXX example to be added later using a selectall_arrayref call
+  XXX nested inside a fetch loop where the first column of the
+  XXX outer loop is bound to the profile Path using
+  XXX bind_column(1, \${ $dbh->{Profile}->{Path}->[0] })
+  XXX so you end up with separate profiles for each loop
+  XXX (patches welcome to add this to the docs :)
+
+=head2 Adding Your Own Samples
+
+The dbi_profile() function can be used to add extra sample data
+into the profile data tree. For example:
+
+    use DBI;
+    use DBI::Profile (dbi_profile dbi_time);
+
+    my $t1 = dbi_time(); # floating point high-resolution time
+
+    ... execute code you want to profile here ...
+
+    my $t2 = dbi_time();
+    dbi_profile($h, $statement, $method, $t1, $t2);
+
+The $h parameter is the handle the extra profile sample should be
+associated with. The $statement parameter is the string to use where
+the Path specifies DBIprofile_Statement. If $statement is undef
+then $h->{Statement} will be used. Similarly $method is the string
+to use if the Path specifies DBIprofile_MethodName. There is no
+default value for $method.
+
+The $h->{Profile}{Path} attribute is processed by dbi_profile() in
+the usual way.
+
+It is recommended that you keep these extra data samples separate
+from the DBI profile data samples by using values for $statement
+and $method that are distinct from any that are likely to appear
+in the profile data normally.
+
+
+=head1 SUBCLASSING
+
+Alternate profile modules must subclass DBI::Profile to help ensure
+they work with future versions of the DBI.
+
+
+=head1 CAVEATS
+
+Applications which generate many different statement strings
+(typically because they don't use placeholders) and profile with
+DBIprofile_Statement in the Path (the default) will consume memory
+in the Profile Data structure for each statement.
+
+If a method throws an exception itself (not via RaiseError) then
+it won't be counted in the profile.
+
+If a HandleError subroutine throws an exception (rather than returning
+0 and letting RaiseError do it) then the method call won't be counted
+in the profile.
+
+Time spent in DESTROY is added to the profile of the parent handle.
+
+Time spent in DBI->*() methods is not counted. The time spent in
+the driver connect method, $drh->connect(), when it's called by
+DBI->connect is counted if the DBI_PROFILE environment variable is set.
+
+Time spent fetching tied variables, $DBI::errstr, is counted.
+
+DBI::PurePerl does not support profiling (though it could in theory).
+
+A few platforms don't support the gettimeofday() high resolution
+time function used by the DBI (and available via the dbi_time() function).
+In which case you'll get integer resolution time which is mostly useless.
+
+On Windows platforms the dbi_time() function is limited to millisecond
+resolution. Which isn't sufficiently fine for our needs, but still
+much better than integer resolution. This limited resolution means
+that fast method calls will often register as taking 0 time. And
+timings in general will have much more 'jitter' depending on where
+within the 'current millisecond' the start and and timing was taken.
+
+This documentation could be more clear. Probably needs to be reordered
+to start with several examples and build from there.  Trying to
+explain the concepts first seems painful and to lead to just as
+many forward references.  (Patches welcome!)
+
+=cut
+
+
+use strict;
+use vars qw(@ISA @EXPORT @EXPORT_OK $VERSION $ON_DESTROY_DUMP);
+use Exporter ();
+use UNIVERSAL ();
+use Carp;
+
+use DBI qw(dbi_time dbi_profile dbi_profile_merge);
+
+$VERSION = sprintf "%d.%02d", '$Revision$ ' =~ /(\d+)\.(\d+)/;
+
+@ISA = qw(Exporter);
+@EXPORT = qw(
+    DBIprofile_Statement
+    DBIprofile_MethodName
+    DBIprofile_MethodClass
+    dbi_profile
+    dbi_profile_merge
+    dbi_time
+);
+@EXPORT_OK = qw(
+    format_profile_thingy
+);
+
+use constant DBIprofile_Statement	=> -2100000001;
+use constant DBIprofile_MethodName	=> -2100000002;
+use constant DBIprofile_MethodClass	=> -2100000003;
+
+$ON_DESTROY_DUMP = sub { DBI->trace_msg(shift, 0) };
+
+sub new {
+    my $class = shift;
+    my $profile = { @_ };
+    return bless $profile => $class;
+}
+
+
+sub _auto_new {
+    my $class = shift;
+    my ($arg) = @_;
+
+    # This sub is called by DBI internals when a non-hash-ref is
+    # assigned to the Profile attribute. For example
+    #	dbi:mysql(RaiseError=>1,Profile=>4/DBIx::MyProfile):dbname
+    # This sub works out what to do and returns a suitable hash ref.
+    
+    my ($path, $module, @args);
+
+    # parse args
+    if ($arg =~ m!/!) {
+        # it's a path/module/arg/arg/arg list
+        ($path, $module, @args) = split /\s*\/\s*/, $arg, -1;
+    } elsif ($arg =~ /^\d+$/) {
+        # it's a numeric path selector
+        $path = $arg;
+    } else {
+        # it's a module name
+        $module = $arg;
+    }
+
+    my @Path;
+    if ($path) {
+	my $reverse = ($path < 0) ? ($path=-$path, 1) : 0;
+	push @Path, "DBI"			if $path & 0x01;
+	push @Path, DBIprofile_Statement	if $path & 0x02;
+	push @Path, DBIprofile_MethodName	if $path & 0x04;
+	push @Path, DBIprofile_MethodClass	if $path & 0x08;
+	@Path = reverse @Path if $reverse;
+    } else {
+        # default Path
+        push @Path, DBIprofile_Statement;
+    }
+
+    if ($module) {
+	if (eval "require $module") {
+	  $class = $module;
+	}
+	else {
+	    carp "Can't use $module for DBI profile: $@";
+	}
+    }
+
+    return $class->new(Path => \@Path, @args);
+}
+
+
+sub format {
+    my $self = shift;
+    my $class = ref($self) || $self;
+    
+    my $prologue = "$class: ";
+    my $detail = $self->format_profile_thingy(
+	$self->{Data}, 0, "    ",
+	my $path = [],
+	my $leaves = [],
+    )."\n";
+
+    if (@$leaves) {
+	dbi_profile_merge(my $totals=[], @$leaves);
+	my ($count, $dbi_time) = @$totals;
+	(my $progname = $0) =~ s:.*/::;
+	if ($count) {
+	    $prologue .= sprintf "%fs ", $dbi_time;
+	    my $perl_time = dbi_time() - $^T;
+	    $prologue .= sprintf "%.2f%% ", $dbi_time/$perl_time*100
+		if $DBI::PERL_ENDING && $perl_time;
+	    my @lt = localtime(time);
+	    my $ts = sprintf "%d-%02d-%02d %02d:%02d:%02d",
+		1900+$lt[5], $lt[4]+1, @lt[3,2,1,0];
+	    $prologue .= sprintf "(%d calls) $progname \@ $ts\n", $count;
+	}
+
+	if (@$leaves == 1 && $self->{Data}->{DBI}) {
+	    $detail = "";	# hide it
+	}
+    }
+    return ($prologue, $detail) if wantarray;
+    return $prologue.$detail;
+}
+
+
+sub format_profile_leaf {
+    my ($self, $thingy, $depth, $pad, $path, $leaves) = @_;
+    croak "format_profile_leaf called on non-leaf ($thingy)"
+	unless UNIVERSAL::isa($thingy,'ARRAY');
+
+    push @$leaves, $thingy if $leaves;
+    if (0) {
+	use Data::Dumper;
+	return Dumper($thingy);
+    }
+    my ($count, $total_time, $first_time, $min, $max, $first_called, $last_called) = @$thingy;
+    return sprintf "%s%fs\n", ($pad x $depth), $total_time
+	if $count <= 1;
+    return sprintf "%s%fs / %d = %fs avg (first %fs, min %fs, max %fs)\n",
+	($pad x $depth), $total_time, $count, $count ? $total_time/$count : 0,
+	$first_time, $min, $max;
+}
+
+
+sub format_profile_branch {
+    my ($self, $thingy, $depth, $pad, $path, $leaves) = @_;
+    croak "format_profile_branch called on non-branch ($thingy)"
+	unless UNIVERSAL::isa($thingy,'HASH');
+    my @chunk;
+    my @keys = sort keys %$thingy;
+    while ( @keys ) {
+	my $k = shift @keys;
+	my $v = $thingy->{$k};
+	push @$path, $k;
+	push @chunk, sprintf "%s'%s' =>\n%s",
+	    ($pad x $depth), $k,
+	    $self->format_profile_thingy($v, $depth+1, $pad, $path, $leaves);
+	pop @$path;
+    }
+    return join "", @chunk;
+}
+
+
+sub format_profile_thingy {
+    my ($self, $thingy, $depth, $pad, $path, $leaves) = @_;
+    return $self->format_profile_leaf(  $thingy, $depth, $pad, $path, $leaves)
+	if UNIVERSAL::isa($thingy,'ARRAY');
+    return $self->format_profile_branch($thingy, $depth, $pad, $path, $leaves)
+	if UNIVERSAL::isa($thingy,'HASH');
+    return "$thingy\n";
+}
+
+
+sub on_destroy {
+    my $self = shift;
+    return unless $ON_DESTROY_DUMP;
+    return unless $self->{Data};
+    my $detail = $self->format();
+    $ON_DESTROY_DUMP->($detail) if $detail;
+}
+
+sub DESTROY {
+    my $self = shift;
+    local $@;
+    eval { $self->on_destroy };
+    if ($@) {
+        my $class = ref($self) || $self;
+        DBI->trace_msg("$class on_destroy failed: $@", 0);
+    }
+}
+
+1;
+
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/ProfileData.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/ProfileData.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/ProfileData.pm	(revision 14139)
@@ -0,0 +1,641 @@
+package DBI::ProfileData;
+use strict;
+
+=head1 NAME
+
+DBI::ProfileData - manipulate DBI::ProfileDumper data dumps
+
+=head1 SYNOPSIS
+
+The easiest way to use this module is through the dbiprof frontend
+(see L<dbiprof> for details):
+
+  dbiprof --number 15 --sort count
+
+This module can also be used to roll your own profile analysis:
+
+  # load data from dbi.prof
+  $prof = DBI::ProfileData->new(File => "dbi.prof");
+
+  # get a count of the records in the data set
+  $count = $prof->count();
+
+  # sort by longest overall time
+  $prof->sort(field => "longest");
+
+  # sort by longest overall time, least to greatest
+  $prof->sort(field => "longest", reverse => 1);
+
+  # exclude records with key2 eq 'disconnect'
+  $prof->exclude(key2 => 'disconnect');
+
+  # exclude records with key1 matching /^UPDATE/i
+  $prof->exclude(key1 => qr/^UPDATE/i);
+
+  # remove all records except those where key1 matches /^SELECT/i
+  $prof->match(key1 => qr/^SELECT/i);
+
+  # produce a formatted report with the given number of items
+  $report = $prof->report(number => 10); 
+
+  # clone the profile data set
+  $clone = $prof->clone();
+
+  # get access to hash of header values
+  $header = $prof->header();
+
+  # get access to sorted array of nodes
+  $nodes = $prof->nodes();
+
+  # format a single node in the same style as report()
+  $text = $prof->format($nodes->[0]);
+
+  # get access to Data hash in DBI::Profile format
+  $Data = $prof->Data();
+
+=head1 DESCRIPTION
+
+This module offers the ability to read, manipulate and format
+DBI::ProfileDumper profile data.  
+
+Conceptually, a profile consists of a series of records, or nodes,
+each of each has a set of statistics and set of keys.  Each record
+must have a unique set of keys, but there is no requirement that every
+record have the same number of keys.
+
+=head1 METHODS
+
+The following methods are supported by DBI::ProfileData objects.
+
+=over 4
+
+=cut
+
+use vars qw($VERSION);
+$VERSION = "1.0";
+
+use Carp qw(croak);
+use Symbol;
+
+use DBI::Profile qw(dbi_profile_merge);
+
+# some constants for use with node data arrays
+sub COUNT     () { 0 };
+sub TOTAL     () { 1 };
+sub FIRST     () { 2 };
+sub SHORTEST  () { 3 };
+sub LONGEST   () { 4 };
+sub FIRST_AT  () { 5 };
+sub LAST_AT   () { 6 };
+sub PATH      () { 7 };
+
+=item $prof = DBI::ProfileData->new(File => "dbi.prof")
+
+=item $prof = DBI::ProfileData->new(Files => [ "dbi.prof.1", "dbi.prof.2" ])
+
+Creates a a new DBI::ProfileData object.  Takes either a single file
+through the File option or a list of Files in an array ref.  If
+multiple files are specified then the header data from the first file
+is used.
+
+=cut
+
+sub new {
+    my $pkg = shift;
+    my $self = {                
+                Files        => [ "dbi.prof" ],
+                _header      => {},
+                _nodes       => [],
+                _node_lookup => {},
+                @_
+               };
+    bless $self, $pkg;
+    
+    # File overrides Files
+    $self->{Files} = [ $self->{File} ] if exists $self->{File};
+
+    $self->_read_files();
+    return $self;
+}
+
+# read files into _header and _nodes
+sub _read_files {
+    my $self = shift;
+    my $files = $self->{Files};
+    my $read_header = 0;
+    
+    foreach my $filename (@$files) {
+        my $fh = gensym;
+        open($fh, $filename)
+          or croak("Unable to read profile file '$filename': $!");
+        
+        $self->_read_header($fh, $filename, $read_header ? 0 : 1);
+        $read_header = 1;
+        $self->_read_body($fh, $filename);
+        close($fh);
+    }
+    
+    # discard node_lookup now that all files are read
+    delete $self->{_node_lookup};
+}
+
+# read the header from the given $fh named $filename.  Discards the
+# data unless $keep.
+sub _read_header {
+    my ($self, $fh, $filename, $keep) = @_;
+
+    # get profiler module id
+    my $first = <$fh>;
+    chomp $first;
+    $self->{_profiler} = $first if $keep;
+
+    # collect variables from the header
+    while (<$fh>) {
+        chomp;
+        last unless length $_;
+        /^(\S+)\s*=\s*(.*)/
+          or croak("Syntax error in header in $filename line $.: $_");
+        $self->{_header}{$1} = $2 if $keep;
+    }
+}
+
+# reads the body of the profile data
+sub _read_body {
+    my ($self, $fh, $filename) = @_;
+    my $nodes = $self->{_nodes};
+    my $lookup = $self->{_node_lookup};
+
+    # build up node array
+    my @path = ("");
+    my (@data, $index, $key, $path_key);
+    while (<$fh>) {
+        chomp;
+        if (/^\+\s+(\d+)\s?(.*)/) {
+            # it's a key
+            ($key, $index) = ($2, $1 - 1);
+
+            # unmangle key
+            $key =~ s/(?<!\\)\\n/\n/g; # expand \n, unless it's a \\n
+            $key =~ s/(?<!\\)\\r/\r/g; # expand \r, unless it's a \\r
+            $key =~ s/\\\\/\\/g;       # \\ to \
+
+            $#path = $index;      # truncate path to new length
+            $path[$index] = $key; # place new key at end
+
+        }
+	elsif (/^=/) {
+            # it's data - file in the node array with the path in index 0
+            @data = /^=\s+(\d+)
+                       \s+(\d+\.?\d*)
+                       \s+(\d+\.?\d*)
+                       \s+(\d+\.?\d*)
+                       \s+(\d+\.?\d*)
+                       \s+(\d+\.?\d*)
+                       \s+(\d+\.?\d*)
+                       \s*$/x;
+
+            # no data?
+            croak("Invalid data syntax format in $filename line $.: $_") unless @data;
+
+            # elements of @path can't have NULLs in them, so this
+            # forms a unique string per @path.  If there's some way I
+            # can get this without arbitrarily stripping out a
+            # character I'd be happy to hear it!
+            $path_key = join("\0",@path);
+
+            # look for previous entry
+            if (exists $lookup->{$path_key}) {
+                # merge in the new data
+		dbi_profile_merge($nodes->[$lookup->{$path_key}], \@data);
+            } else {
+                # insert a new node - nodes are arrays with data in 0-6
+                # and path data after that
+                push(@$nodes, [ @data, @path ]);
+
+                # record node in %seen
+                $lookup->{$path_key} = $#$nodes;
+            }
+        }
+	else {
+            croak("Invalid line type syntax error in $filename line $.: $_");
+	}
+    }
+}
+
+# takes an existing node and merges in new data points
+sub _merge_data {	# XXX use dbi_profile_merge instead
+    my ($self, $node, $data) = @_;
+
+    # add counts and total duration
+    $node->[COUNT] += $data->[COUNT];
+    $node->[TOTAL] += $data->[TOTAL];
+    
+    # first duration untouched
+
+    # take new shortest duration if shorter
+    $node->[SHORTEST] = $data->[SHORTEST]
+      if $data->[SHORTEST] < $node->[SHORTEST];
+
+    # take new longest duration if longer
+    $node->[LONGEST] = $data->[LONGEST]
+      if $data->[LONGEST] > $node->[LONGEST];
+
+    # time of first event untouched
+
+    # take time of last event
+    $node->[LAST_AT] = $data->[LAST_AT];
+}
+
+
+
+=item $copy = $prof->clone();
+
+Clone a profile data set creating a new object.
+
+=cut
+
+sub clone {
+    my $self = shift;
+
+    # start with a simple copy
+    my $clone = bless { %$self }, ref($self);
+
+    # deep copy nodes
+    $clone->{_nodes}  = [ map { [ @$_ ] } @{$self->{_nodes}} ];
+
+    # deep copy header
+    $clone->{_header} = { %{$self->{_header}} };
+
+    return $clone;
+}
+
+=item $header = $prof->header();
+
+Returns a reference to a hash of header values.  These are the key
+value pairs included in the header section of the DBI::ProfileDumper
+data format.  For example:
+
+  $header = {
+              Path    => '[ DBIprofile_Statement, DBIprofile_MethodName ]',
+              Program => 't/42profile_data.t',
+            };
+
+Note that modifying this hash will modify the header data stored
+inside the profile object.
+
+=cut
+
+sub header { shift->{_header} }
+
+
+=item $nodes = $prof->nodes()
+
+Returns a reference the sorted nodes array.  Each element in the array
+is a single record in the data set.  The first seven elements are the
+same as the elements provided by DBI::Profile.  After that each key is
+in a separate element.  For example:
+
+ $nodes = [
+            [
+              2,                      # 0, count
+              0.0312958955764771,     # 1, total duration
+              0.000490069389343262,   # 2, first duration
+              0.000176072120666504,   # 3, shortest duration
+              0.00140702724456787,    # 4, longest duration
+              1023115819.83019,       # 5, time of first event
+              1023115819.86576,       # 6, time of last event
+              'SELECT foo FROM bar'   # 7, key1
+              'execute'               # 8, key2
+                                      # 6+N, keyN
+            ],
+                                      # ...
+          ];
+
+Note that modifying this array will modify the node data stored inside
+the profile object.
+
+=cut
+
+sub nodes { shift->{_nodes} }
+
+=item $count = $prof->count()
+
+Returns the number of items in the profile data set.
+
+=cut
+
+sub count { scalar @{shift->{_nodes}} }
+
+=item $prof->sort(field => "field")
+
+=item $prof->sort(field => "field", reverse => 1)
+
+Sorts data by the given field.  Available fields are:
+
+  longest
+  total
+  count
+  shortest
+
+The default sort is greatest to smallest, which is the opposite of the
+normal Perl meaning.  This, however, matches the expected behavior of
+the dbiprof frontend.
+
+=cut
+
+
+# sorts data by one of the available fields
+{
+    my %FIELDS = (
+                  longest  => LONGEST,
+                  total    => TOTAL,
+                  count    => COUNT,
+                  shortest => SHORTEST,
+                 );
+    sub sort {
+        my $self = shift;
+        my $nodes = $self->{_nodes};
+        my %opt = @_;
+        
+        croak("Missing required field option.") unless $opt{field};
+
+        my $index = $FIELDS{$opt{field}};
+        
+        croak("Unrecognized sort field '$opt{field}'.")
+          unless defined $index;
+
+        # sort over index
+        if ($opt{reverse}) {
+            @$nodes = sort { 
+                $a->[$index] <=> $b->[$index] 
+            } @$nodes;
+        } else {
+            @$nodes = sort { 
+                $b->[$index] <=> $a->[$index] 
+            } @$nodes;
+        }
+
+        # remember how we're sorted
+        $self->{_sort} = $opt{field};
+
+        return $self;
+    }
+}
+
+=item $count = $prof->exclude(key2 => "disconnect")
+
+=item $count = $prof->exclude(key2 => "disconnect", case_sensitive => 1)
+
+=item $count = $prof->exclude(key1 => qr/^SELECT/i)
+
+Removes records from the data set that match the given string or
+regular expression.  This method modifies the data in a permanent
+fashion - use clone() first to maintain the original data after
+exclude().  Returns the number of nodes left in the profile data set.
+
+=cut
+
+sub exclude {
+    my $self = shift;
+    my $nodes = $self->{_nodes};
+    my %opt = @_;
+
+    # find key index number
+    my ($index, $val);
+    foreach (keys %opt) {
+        if (/^key(\d+)$/) {
+            $index   = PATH + $1 - 1;
+            $val     = $opt{$_};
+            last;
+        }
+    }
+    croak("Missing required keyN option.") unless $index;
+
+    if (UNIVERSAL::isa($val,"Regexp")) {
+        # regex match
+        @$nodes = grep {
+            $#$_ < $index or $_->[$index] !~ /$val/ 
+        } @$nodes;
+    } else {
+        if ($opt{case_sensitive}) {
+            @$nodes = grep { 
+                $#$_ < $index or $_->[$index] ne $val;
+            } @$nodes;
+        } else {
+            $val = lc $val;
+            @$nodes = grep { 
+                $#$_ < $index or lc($_->[$index]) ne $val;
+            } @$nodes;
+        }
+    }
+
+    return scalar @$nodes;
+}
+
+
+=item $count = $prof->match(key2 => "disconnect")
+
+=item $count = $prof->match(key2 => "disconnect", case_sensitive => 1)
+
+=item $count = $prof->match(key1 => qr/^SELECT/i)
+
+Removes records from the data set that do not match the given string
+or regular expression.  This method modifies the data in a permanent
+fashion - use clone() first to maintain the original data after
+match().  Returns the number of nodes left in the profile data set.
+
+=cut
+
+sub match {
+    my $self = shift;
+    my $nodes = $self->{_nodes};
+    my %opt = @_;
+
+    # find key index number
+    my ($index, $val);
+    foreach (keys %opt) {
+        if (/^key(\d+)$/) {
+            $index   = PATH + $1 - 1;
+            $val     = $opt{$_};
+            last;
+        }
+    }
+    croak("Missing required keyN option.") unless $index;
+
+    if (UNIVERSAL::isa($val,"Regexp")) {
+        # regex match
+        @$nodes = grep {
+            $#$_ >= $index and $_->[$index] =~ /$val/ 
+        } @$nodes;
+    } else {
+        if ($opt{case_sensitive}) {
+            @$nodes = grep { 
+                $#$_ >= $index and $_->[$index] eq $val;
+            } @$nodes;
+        } else {
+            $val = lc $val;
+            @$nodes = grep { 
+                $#$_ >= $index and lc($_->[$index]) eq $val;
+            } @$nodes;
+        }
+    }
+
+    return scalar @$nodes;
+}
+
+=item $Data = $prof->Data()
+
+Returns the same Data hash structure as seen in DBI::Profile.  This
+structure is not sorted.  The nodes() structure probably makes more
+sense for most analysis.
+
+=cut
+
+sub Data {
+    my $self = shift;
+    my (%Data, @data, $ptr);
+
+    foreach my $node (@{$self->{_nodes}}) {
+        # traverse to key location
+        $ptr = \%Data;
+        foreach my $key (@{$node}[PATH .. $#$node - 1]) {
+            $ptr->{$key} = {} unless exists $ptr->{$key};
+            $ptr = $ptr->{$key};
+        }
+
+        # slice out node data
+        $ptr->{$node->[-1]} = [ @{$node}[0 .. 6] ];
+    }
+
+    return \%Data;
+}
+
+=item $text = $prof->format($nodes->[0])
+
+Formats a single node into a human-readable block of text.
+
+=cut
+
+sub format {
+    my ($self, $node) = @_;
+    my $format;
+    
+    # setup keys
+    my $keys = "";
+    for (my $i = PATH; $i <= $#$node; $i++) {
+        my $key = $node->[$i];
+        
+        # remove leading and trailing space
+        $key =~ s/^\s+//;
+        $key =~ s/\s+$//;
+
+        # if key has newlines or is long take special precautions
+        if (length($key) > 72 or $key =~ /\n/) {
+            $keys .= "  Key " . ($i - PATH + 1) . "         :\n\n$key\n\n";
+        } else {
+            $keys .= "  Key " . ($i - PATH + 1) . "         : $key\n";
+        }
+    }
+
+    # nodes with multiple runs get the long entry format, nodes with
+    # just one run get a single count.
+    if ($node->[COUNT] > 1) {
+        $format = <<END;
+  Count         : %d
+  Total Time    : %3.6f seconds
+  Longest Time  : %3.6f seconds
+  Shortest Time : %3.6f seconds
+  Average Time  : %3.6f seconds
+END
+        return sprintf($format, @{$node}[COUNT,TOTAL,LONGEST,SHORTEST], 
+                       $node->[TOTAL] / $node->[COUNT]) . $keys;
+    } else {
+        $format = <<END;
+  Count         : %d
+  Time          : %3.6f seconds
+END
+
+        return sprintf($format, @{$node}[COUNT,TOTAL]) . $keys;
+
+    }
+}
+
+=item $text = $prof->report(number => 10)
+
+Produces a report with the given number of items.
+
+=cut
+
+sub report {
+    my $self  = shift;
+    my $nodes = $self->{_nodes};
+    my %opt   = @_;
+
+    croak("Missing required number option") unless exists $opt{number};
+
+    $opt{number} = @$nodes if @$nodes < $opt{number};
+
+    my $report = $self->_report_header($opt{number});
+    for (0 .. $opt{number} - 1) {
+        $report .= sprintf("#" x 5  . "[ %d ]". "#" x 59 . "\n", 
+                           $_ + 1);
+        $report .= $self->format($nodes->[$_]);
+        $report .= "\n";
+    }
+    return $report;
+}
+
+# format the header for report()
+sub _report_header {
+    my ($self, $number) = @_;
+    my $nodes = $self->{_nodes};
+    my $node_count = @$nodes;
+
+    # find total runtime and method count
+    my ($time, $count) = (0,0);
+    foreach my $node (@$nodes) {
+        $time  += $node->[TOTAL];
+        $count += $node->[COUNT];
+    }
+
+    my $header = <<END;
+
+DBI Profile Data ($self->{_profiler})
+
+END
+
+    # output header fields
+    while (my ($key, $value) = each %{$self->{_header}}) {
+        $header .= sprintf("  %-13s : %s\n", $key, $value);
+    }
+
+    # output summary data fields
+    $header .= sprintf(<<END, $node_count, $number, $self->{_sort}, $count, $time);
+  Total Records : %d (showing %d, sorted by %s)
+  Total Count   : %d
+  Total Runtime : %3.6f seconds  
+
+END
+
+    return $header;
+}
+
+
+1;
+
+__END__
+
+=back
+
+=head1 AUTHOR
+
+Sam Tregar <sam@tregar.com>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2002 Sam Tregar
+
+This program is free software; you can redistribute it and/or modify
+it under the same terms as Perl 5 itself.
+
+=cut
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/ProfileDumper.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/ProfileDumper.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/ProfileDumper.pm	(revision 14139)
@@ -0,0 +1,271 @@
+package DBI::ProfileDumper;
+use strict;
+
+=head1 NAME
+
+DBI::ProfileDumper - profile DBI usage and output data to a file
+
+=head1 SYNOPSIS
+
+To profile an existing program using DBI::ProfileDumper, set the
+DBI_PROFILE environment variable and run your program as usual.  For
+example, using bash:
+
+  DBI_PROFILE=DBI::ProfileDumper program.pl
+
+Then analyze the generated file (F<dbi.prof>) with L<dbiprof|dbiprof>:
+
+  dbiprof
+
+You can also activate DBI::ProfileDumper from within your code:
+
+  use DBI;
+
+  # profile with default path (2) and output file (dbi.prof)
+  $dbh->{Profile} = "DBI::ProfileDumper";
+
+  # same thing, spelled out
+  $dbh->{Profile} = "2/DBI::ProfileDumper/File/dbi.prof";
+
+  # another way to say it
+  use DBI::Profile qw(DBIprofile_Statement);
+  $dbh->{Profile} = DBI::ProfileDumper->new(
+                        Path => [ DBIprofile_Statement ]
+                        File => 'dbi.prof' );
+
+  # using a custom path
+  $dbh->{Profile} = DBI::ProfileDumper->new( Path => [ "foo", "bar" ],
+                                             File => 'dbi.prof' );
+
+
+=head1 DESCRIPTION
+
+DBI::ProfileDumper is a subclass of L<DBI::Profile|DBI::Profile> which
+dumps profile data to disk instead of printing a summary to your
+screen.  You can then use L<dbiprof|dbiprof> to analyze the data in
+a number of interesting ways, or you can roll your own analysis using
+L<DBI::ProfileData|DBI::ProfileData>.
+
+B<NOTE:> For Apache/mod_perl applications, use
+L<DBI::ProfileDumper::Apache|DBI::ProfileDumper::Apache>.
+
+=head1 USAGE
+
+One way to use this module is just to enable it in your C<$dbh>:
+
+  $dbh->{Profile} = "DBI::ProfileDumper";
+
+This will write out profile data by statement into a file called
+F<dbi.prof>.  If you want to modify either of these properties, you
+can construct the DBI::ProfileDumper object yourself:
+
+  use DBI::Profile qw(DBIprofile_Statement);
+  $dbh->{Profile} = DBI::ProfileDumper->new(
+                        Path => [ DBIprofile_Statement ]
+                        File => 'dbi.prof' );
+
+The C<Path> option takes the same values as in
+L<DBI::Profile>.  The C<File> option gives the name of the
+file where results will be collected.  If it already exists it will be
+overwritten.
+
+You can also activate this module by setting the DBI_PROFILE
+environment variable:
+
+  $ENV{DBI_PROFILE} = "DBI::ProfileDumper";
+
+This will cause all DBI handles to share the same profiling object.
+
+=head1 METHODS
+
+The following methods are available to be called using the profile
+object.  You can get access to the profile object from the Profile key
+in any DBI handle:
+
+  my $profile = $dbh->{Profile};
+
+=over 4
+
+=item $profile->flush_to_disk()
+
+Flushes all collected profile data to disk and empties the Data hash.
+This method may be called multiple times during a program run.
+
+=item $profile->empty()
+
+Clears the Data hash without writing to disk.
+
+=back
+
+=head1 DATA FORMAT
+
+The data format written by DBI::ProfileDumper starts with a header
+containing the version number of the module used to generate it.  Then
+a block of variable declarations describes the profile.  After two
+newlines, the profile data forms the body of the file.  For example:
+
+  DBI::ProfileDumper 1.0
+  Path = [ DBIprofile_Statement, DBIprofile_MethodName ]
+  Program = t/42profile_data.t
+
+  + 1 SELECT name FROM users WHERE id = ?
+  + 2 prepare
+  = 1 0.0312958955764771 0.000490069389343262 0.000176072120666504 0.00140702724456787 1023115819.83019 1023115819.86576
+  + 2 execute
+  1 0.0312958955764771 0.000490069389343262 0.000176072120666504 0.00140702724456787 1023115819.83019 1023115819.86576
+  + 2 fetchrow_hashref
+  = 1 0.0312958955764771 0.000490069389343262 0.000176072120666504 0.00140702724456787 1023115819.83019 1023115819.86576
+  + 1 UPDATE users SET name = ? WHERE id = ?
+  + 2 prepare
+  = 1 0.0312958955764771 0.000490069389343262 0.000176072120666504 0.00140702724456787 1023115819.83019 1023115819.86576
+  + 2 execute
+  = 1 0.0312958955764771 0.000490069389343262 0.000176072120666504 0.00140702724456787 1023115819.83019 1023115819.86576
+
+The lines beginning with C<+> signs signify keys.  The number after
+the C<+> sign shows the nesting level of the key.  Lines beginning
+with C<=> are the actual profile data, in the same order as
+in DBI::Profile.
+
+Note that the same path may be present multiple times in the data file
+since C<format()> may be called more than once.  When read by
+DBI::ProfileData the data points will be merged to produce a single
+data set for each distinct path.
+
+The key strings are transformed in three ways.  First, all backslashes
+are doubled.  Then all newlines and carriage-returns are transformed
+into C<\n> and C<\r> respectively.  Finally, any NULL bytes (C<\0>)
+are entirely removed.  When DBI::ProfileData reads the file the first
+two transformations will be reversed, but NULL bytes will not be
+restored.
+
+=head1 AUTHOR
+
+Sam Tregar <sam@tregar.com>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2002 Sam Tregar
+
+This program is free software; you can redistribute it and/or modify
+it under the same terms as Perl 5 itself.
+
+=cut
+
+# inherit from DBI::Profile
+use DBI::Profile;
+use vars qw(@ISA $VERSION);
+@ISA = ("DBI::Profile");
+$VERSION = "1.0";
+
+use Carp qw(croak);
+use Symbol;
+
+# validate params and setup default
+sub new {
+    my $pkg = shift;
+    my $self = $pkg->SUPER::new(@_);
+
+    # File defaults to dbi.prof
+    $self->{File} = "dbi.prof" unless exists $self->{File};
+
+    return $self;
+}
+
+# flush available data to disk
+sub flush_to_disk {
+    my $self = shift;
+    my $data = $self->{Data};
+
+    my $fh = gensym;
+    if ($self->{_wrote_header}) {
+        # append more data to the file
+        open($fh, ">>$self->{File}") 
+          or croak("Unable to open '$self->{File}' for profile output: $!");
+    } else {
+        # create new file and write the header
+        open($fh, ">$self->{File}") 
+          or croak("Unable to open '$self->{File}' for profile output: $!");
+        $self->write_header($fh);
+        $self->{_wrote_header} = 1;
+    }
+
+    $self->write_data($fh, $self->{Data}, 1);
+
+    close($fh) or croak("Unable to close '$self->{File}': $!");
+
+    $self->empty();
+}
+
+# empty out profile data
+sub empty {
+    shift->{Data} = {};
+}
+
+# write header to a filehandle
+sub write_header {
+    my ($self, $fh) = @_;
+
+    # module name and version number
+    print $fh ref($self), " ", $self->VERSION, "\n";
+
+    # print out Path
+    my @path_words;
+    foreach (@{$self->{Path}}) {
+        if ($_ eq DBI::Profile::DBIprofile_Statement) {
+            push @path_words, "DBIprofile_Statement";
+        } elsif ($_ eq DBI::Profile::DBIprofile_MethodName) {
+            push @path_words, "DBIprofile_MethodName";
+        } elsif ($_ eq DBI::Profile::DBIprofile_MethodClass) {
+            push @path_words, "DBIprofile_MethodClass";
+        } else {
+            push @path_words, $_;
+        }
+    }
+    print $fh "Path = [ ", join(', ', @path_words), " ]\n";
+
+    # print out $0 and @ARGV
+    print $fh "Program = $0";
+    print $fh " ", join(", ", @ARGV) if @ARGV;
+    print $fh "\n";
+
+    # all done
+    print $fh "\n";
+}
+
+# write data in the proscribed format
+sub write_data {
+    my ($self, $fh, $data, $level) = @_;
+
+    # produce an empty profile for invalid $data
+    return unless $data and UNIVERSAL::isa($data,'HASH');
+    
+    while (my ($key, $value) = each(%$data)) {
+        # output a key
+        print $fh "+ ", $level, " ", quote_key($key), "\n";
+        if (UNIVERSAL::isa($value,'ARRAY')) {
+            # output a data set for a leaf node
+            printf $fh "= %4d %.6f %.6f %.6f %.6f %.6f %.6f\n", @$value;
+        } else {
+            # recurse through keys - this could be rewritten to use a
+            # stack for some small performance gain
+            $self->write_data($fh, $value, $level + 1);
+        }
+    }
+}
+
+# quote a key for output
+sub quote_key {
+    my $key = shift;
+    $key =~ s!\\!\\\\!g;
+    $key =~ s!\n!\\n!g;
+    $key =~ s!\r!\\r!g;
+    $key =~ s!\0!!g;
+    return $key;
+}
+
+# flush data to disk when profile object goes out of scope
+sub on_destroy {
+    shift->flush_to_disk();
+}
+
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/ProfileDumper/Apache.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/ProfileDumper/Apache.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/ProfileDumper/Apache.pm	(revision 14139)
@@ -0,0 +1,135 @@
+package DBI::ProfileDumper::Apache;
+
+=head1 NAME
+
+DBI::ProfileDumper::Apache - capture DBI profiling data from Apache/mod_perl
+
+=head1 SYNOPSIS
+
+Add this line to your F<httpd.conf>:
+
+  PerlSetEnv DBI_PROFILE DBI::ProfileDumper::Apache
+
+Then restart your server.  Access the code you wish to test using a
+web browser, then shutdown your server.  This will create a set of
+F<dbi.prof.*> files in your Apache log directory.  Get a profiling
+report with L<dbiprof|dbiprof>:
+
+  dbiprof /usr/local/apache/logs/dbi.prof.*
+
+When you're ready to perform another profiling run, delete the old
+files
+
+  rm /usr/local/apache/logs/dbi.prof.*
+
+and start again.
+
+=head1 DESCRIPTION
+
+This module interfaces DBI::ProfileDumper to Apache/mod_perl.  Using
+this module you can collect profiling data from mod_perl applications.
+It works by creating a DBI::ProfileDumper data file for each Apache
+process.  These files are created in your Apache log directory.  You
+can then use dbiprof to analyze the profile files.
+
+=head1 USAGE
+
+=head2 LOADING THE MODULE
+
+The easiest way to use this module is just to set the DBI_PROFILE
+environment variable in your F<httpd.conf>:
+
+  PerlSetEnv DBI_PROFILE DBI::ProfileDumper::Apache
+
+If you want to use one of DBI::Profile's other Path settings, you can
+use a string like:
+
+  PerlSetEnv DBI_PROFILE 2/DBI::ProfileDumper::Apache
+
+It's also possible to use this module by setting the Profile attribute
+of any DBI handle:
+
+  $dbh->{Profile} = "DBI::ProfileDumper::Apache";
+
+See L<DBI::ProfileDumper> for more possibilities.
+
+=head2 GATHERING PROFILE DATA
+
+Once you have the module loaded, use your application as you normally
+would.  Stop the webserver when your tests are complete.  Profile data
+files will be produced when Apache exits and you'll see something like
+this in your error_log:
+
+  DBI::ProfileDumper::Apache writing to /usr/local/apache/logs/dbi.prof.2619
+
+Now you can use dbiprof to examine the data:
+
+  dbiprof /usr/local/apache/logs/dbi.prof.*
+
+By passing dbiprof a list of all generated files, dbiprof will
+automatically merge them into one result set.  You can also pass
+dbiprof sorting and querying options, see L<dbiprof> for details.
+
+=head2 CLEANING UP
+
+Once you've made some code changes, you're ready to start again.
+First, delete the old profile data files:
+
+  rm /usr/local/apache/logs/dbi.prof.* 
+
+Then restart your server and get back to work.
+
+=head1 MEMORY USAGE
+
+DBI::Profile can use a lot of memory for very active applications.  It
+collects profiling data in memory for each distinct query your
+application runs.  You can avoid this problem with a call like this:
+
+  $dbh->{Profile}->flush_to_disk() if $dbh->{Profile};
+
+Calling C<flush_to_disk()> will clear out the profile data and write
+it to disk.  Put this someplace where it will run on every request,
+like a CleanupHandler, and your memory troubles should go away.  Well,
+at least the ones caused by DBI::Profile anyway.
+
+=head1 AUTHOR
+
+Sam Tregar <sam@tregar.com>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2002 Sam Tregar
+
+This program is free software; you can redistribute it and/or modify
+it under the same terms as Perl 5 itself.
+
+=cut
+
+use vars qw($VERSION @ISA);
+$VERSION = "1.0";
+@ISA = qw(DBI::ProfileDumper);
+use DBI::ProfileDumper;
+use Apache;
+use File::Spec;
+
+# Override flush_to_disk() to setup File just in time for output.
+# Overriding new() would work unless the user creates a DBI handle
+# during server startup, in which case all the children would try to
+# write to the same file.
+sub flush_to_disk {
+    my $self = shift;
+    
+    # setup File per process
+    my $path = Apache->server_root_relative("logs/");
+    my $old_file = $self->{File};
+    $self->{File} = File::Spec->catfile($path, "$old_file.$$");
+
+    # write out to disk
+    print STDERR "DBI::ProfileDumper::Apache writing to $self->{File}\n";
+    $self->SUPER::flush_to_disk(@_);
+   
+    # reset File to previous setting
+    $self->{File} = $old_file;    
+}
+
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/ProxyServer.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/ProxyServer.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/ProxyServer.pm	(revision 14139)
@@ -0,0 +1,881 @@
+#	$Header$
+# -*- perl -*-
+#
+#   DBI::ProxyServer - a proxy server for DBI drivers
+#
+#   Copyright (c) 1997  Jochen Wiedmann
+#
+#   The DBD::Proxy module is free software; you can redistribute it and/or
+#   modify it under the same terms as Perl itself. In particular permission
+#   is granted to Tim Bunce for distributing this as a part of the DBI.
+#
+#
+#   Author: Jochen Wiedmann
+#           Am Eisteich 9
+#           72555 Metzingen
+#           Germany
+#
+#           Email: joe@ispsoft.de
+#           Phone: +49 7123 14881
+#
+#
+##############################################################################
+
+
+require 5.004;
+use strict;
+
+use RPC::PlServer 0.2001;
+# require DBI; # deferred till AcceptVersion() to aid threading
+require Config;
+
+
+package DBI::ProxyServer;
+
+
+
+############################################################################
+#
+#   Constants
+#
+############################################################################
+
+use vars qw($VERSION @ISA);
+
+$VERSION = "0.3005";
+@ISA = qw(RPC::PlServer DBI);
+
+
+# Most of the options below are set to default values, we note them here
+# just for the sake of documentation.
+my %DEFAULT_SERVER_OPTIONS;
+{
+    my $o = \%DEFAULT_SERVER_OPTIONS;
+    $o->{'chroot'}     = undef,		# To be used in the initfile,
+    					# after loading the required
+    					# DBI drivers.
+    $o->{'clients'} =
+	[ { 'mask' => '.*',
+	    'accept' => 1,
+	    'cipher' => undef
+	    }
+	  ];
+    $o->{'configfile'} = '/etc/dbiproxy.conf' if -f '/etc/dbiproxy.conf';
+    $o->{'debug'}      = 0;
+    $o->{'facility'}   = 'daemon';
+    $o->{'group'}      = undef;
+    $o->{'localaddr'}  = undef;		# Bind to any local IP number
+    $o->{'localport'}  = undef;         # Must set port number on the
+					# command line.
+    $o->{'logfile'}    = undef;         # Use syslog or EventLog.
+    $o->{'methods'}    = {
+	'DBI::ProxyServer' => {
+	    'Version' => 1,
+	    'NewHandle' => 1,
+	    'CallMethod' => 1,
+	    'DestroyHandle' => 1
+	    },
+	'DBI::ProxyServer::db' => {
+	    'prepare' => 1,
+	    'commit' => 1,
+	    'rollback' => 1,
+	    'STORE' => 1,
+	    'FETCH' => 1,
+	    'func' => 1,
+	    'quote' => 1,
+	    'type_info_all' => 1,
+	    'table_info' => 1,
+	    'disconnect' => 1,
+	    },
+	'DBI::ProxyServer::st' => {
+	    'execute' => 1,
+	    'STORE' => 1,
+	    'FETCH' => 1,
+	    'func' => 1,
+	    'fetch' => 1,
+	    'finish' => 1
+	    }
+    };
+    if ($Config::Config{'usethreads'} eq 'define') {
+	$o->{'mode'} = 'threads';
+    } elsif ($Config::Config{'d_fork'} eq 'define') {
+	$o->{'mode'} = 'fork';
+    } else {
+	$o->{'mode'} = 'single';
+    }
+    # No pidfile by default, configuration must provide one if needed
+    $o->{'pidfile'}    = 'none';
+    $o->{'user'}       = undef;
+};
+
+
+############################################################################
+#
+#   Name:    Version
+#
+#   Purpose: Return version string
+#
+#   Inputs:  $class - This class
+#
+#   Result:  Version string; suitable for printing by "--version"
+#
+############################################################################
+
+sub Version {
+    my $version = $DBI::ProxyServer::VERSION;
+    "DBI::ProxyServer $version, Copyright (C) 1998, Jochen Wiedmann";
+}
+
+
+############################################################################
+#
+#   Name:    AcceptApplication
+#
+#   Purpose: Verify DBI DSN
+#
+#   Inputs:  $self - This instance
+#            $dsn - DBI dsn
+#
+#   Returns: TRUE for a valid DSN, FALSE otherwise
+#
+############################################################################
+
+sub AcceptApplication {
+    my $self = shift; my $dsn = shift;
+    $dsn =~ /^dbi:\w+:/i;
+}
+
+
+############################################################################
+#
+#   Name:    AcceptVersion
+#
+#   Purpose: Verify requested DBI version
+#
+#   Inputs:  $self - Instance
+#            $version - DBI version being requested
+#
+#   Returns: TRUE for ok, FALSE otherwise
+#
+############################################################################
+
+sub AcceptVersion {
+    my $self = shift; my $version = shift;
+    require DBI;
+    DBI::ProxyServer->init_rootclass();
+    $DBI::VERSION >= $version;
+}
+
+
+############################################################################
+#
+#   Name:    AcceptUser
+#
+#   Purpose: Verify user and password by connecting to the client and
+#            creating a database connection
+#
+#   Inputs:  $self - Instance
+#            $user - User name
+#            $password - Password
+#
+############################################################################
+
+sub AcceptUser {
+    my $self = shift; my $user = shift; my $password = shift;
+    return 0 if (!$self->SUPER::AcceptUser($user, $password));
+    my $dsn = $self->{'application'};
+    $self->Debug("Connecting to $dsn as $user");
+    local $ENV{DBI_AUTOPROXY} = ''; # :-)
+    $self->{'dbh'} = eval {
+        DBI::ProxyServer->connect($dsn, $user, $password,
+				  { 'PrintError' => 0, 
+				    'Warn' => 0,
+				    'RaiseError' => 1,
+				    'HandleError' => sub {
+				        my $err = $_[1]->err;
+					my $state = $_[1]->state || '';
+					$_[0] .= " [err=$err,state=$state]";
+					return 0;
+				    } })
+    };
+    if ($@) {
+	$self->Error("Error while connecting to $dsn as $user: $@");
+	return 0;
+    }
+    [1, $self->StoreHandle($self->{'dbh'}) ];
+}
+
+
+sub CallMethod {
+    my $server = shift;
+    my $dbh = $server->{'dbh'};
+    # We could store the private_server attribute permanently in
+    # $dbh. However, we'd have a reference loop in that case and
+    # I would be concerned about garbage collection. :-(
+    $dbh->{'private_server'} = $server;
+    $server->Debug("CallMethod: => " . join(",", @_));
+    my @result = eval { $server->SUPER::CallMethod(@_) };
+    my $msg = $@;
+    undef $dbh->{'private_server'};
+    if ($msg) {
+	$server->Debug("CallMethod died with: $@");
+	die $msg;
+    } else {
+	$server->Debug("CallMethod: <= " . join(",", @result));
+    }
+    @result;
+}
+
+
+sub main {
+    my $server = DBI::ProxyServer->new(\%DEFAULT_SERVER_OPTIONS, \@_);
+    $server->Bind();
+}
+
+
+############################################################################
+#
+#   The DBI part of the proxyserver is implemented as a DBI subclass.
+#   Thus we can reuse some of the DBI methods and overwrite only
+#   those that need additional handling.
+#
+############################################################################
+
+package DBI::ProxyServer::dr;
+
+@DBI::ProxyServer::dr::ISA = qw(DBI::dr);
+
+
+package DBI::ProxyServer::db;
+
+@DBI::ProxyServer::db::ISA = qw(DBI::db);
+
+sub prepare {
+    my($dbh, $statement, $attr, $params, $proto_ver) = @_;
+    my $server = $dbh->{'private_server'};
+    if (my $client = $server->{'client'}) {
+	if ($client->{'sql'}) {
+	    if ($statement =~ /^\s*(\S+)/) {
+		my $st = $1;
+		if (!($statement = $client->{'sql'}->{$st})) {
+		    die "Unknown SQL query: $st";
+		}
+	    } else {
+		die "Cannot parse restricted SQL statement: $statement";
+	    }
+	}
+    }
+    my $sth = $dbh->SUPER::prepare($statement, $attr);
+    my $handle = $server->StoreHandle($sth);
+
+    if ( $proto_ver and $proto_ver > 1 ) {
+      $sth->{private_proxyserver_described} = 0;
+      return $handle;
+
+    } else {
+      # The difference between the usual prepare and ours is that we implement
+      # a combined prepare/execute. The DBD::Proxy driver doesn't call us for
+      # prepare. Only if an execute happens, then we are called with method
+      # "prepare". Further execute's are called as "execute".
+      my @result = $sth->execute($params);
+      my ($NAME, $TYPE);
+      my $NUM_OF_FIELDS = $sth->{NUM_OF_FIELDS};
+      if ($NUM_OF_FIELDS) {	# is a SELECT
+	$NAME = $sth->{NAME};
+	$TYPE = $sth->{TYPE};
+      }
+      ($handle, $NUM_OF_FIELDS, $sth->{'NUM_OF_PARAMS'},
+       $NAME, $TYPE, @result);
+    }
+}
+
+sub table_info {
+    my $dbh = shift;
+    my $sth = $dbh->SUPER::table_info();
+    my $numFields = $sth->{'NUM_OF_FIELDS'};
+    my $names = $sth->{'NAME'};
+    my $types = $sth->{'TYPE'};
+
+    # We wouldn't need to send all the rows at this point, instead we could
+    # make use of $rsth->fetch() on the client as usual.
+    # The problem is that some drivers (namely DBD::ExampleP, DBD::mysql and
+    # DBD::mSQL) are returning foreign sth's here, thus an instance of
+    # DBI::st and not DBI::ProxyServer::st. We could fix this by permitting
+    # the client to execute method DBI::st, but I don't like this.
+    my @rows;
+    while (my ($row) = $sth->fetch()) {
+        last unless defined $row;
+	push(@rows, [@$row]);
+    }
+    ($numFields, $names, $types, @rows);
+}
+
+
+package DBI::ProxyServer::st;
+
+@DBI::ProxyServer::st::ISA = qw(DBI::st);
+
+sub execute {
+    my $sth = shift; my $params = shift; my $proto_ver = shift;
+    my @outParams;
+    if ($params) {
+	for (my $i = 0;  $i < @$params;) {
+	    my $param = $params->[$i++];
+	    if (!ref($param)) {
+		$sth->bind_param($i, $param);
+	    }
+	    else {	
+		if (!ref(@$param[0])) {#It's not a reference
+		    $sth->bind_param($i, @$param);
+		}
+		else {
+		    $sth->bind_param_inout($i, @$param);
+		    my $ref = shift @$param;
+		    push(@outParams, $ref);
+		}
+	    }
+	}
+    }
+    my $rows = $sth->SUPER::execute();
+    if ( $proto_ver and $proto_ver > 1 and not $sth->{private_proxyserver_described} ) {
+      my ($NAME, $TYPE);
+      my $NUM_OF_FIELDS = $sth->{NUM_OF_FIELDS};
+      if ($NUM_OF_FIELDS) {	# is a SELECT
+	$NAME = $sth->{NAME};
+	$TYPE = $sth->{TYPE};
+      }
+      $sth->{private_proxyserver_described} = 1;
+      # First execution, we ship back description.
+      return ($rows, $NUM_OF_FIELDS, $sth->{'NUM_OF_PARAMS'}, $NAME, $TYPE, @outParams);
+    }
+    ($rows, @outParams);
+}
+
+sub fetch {
+    my $sth = shift; my $numRows = shift || 1;
+    my($ref, @rows);
+    while ($numRows--  &&  ($ref = $sth->SUPER::fetch())) {
+	push(@rows, [@$ref]);
+    }
+    @rows;
+}
+
+
+1;
+
+
+__END__
+
+=head1 NAME
+
+DBI::ProxyServer - a server for the DBD::Proxy driver
+
+=head1 SYNOPSIS
+
+    use DBI::ProxyServer;
+    DBI::ProxyServer::main(@ARGV);
+
+=head1 DESCRIPTION
+
+DBI::Proxy Server is a module for implementing a proxy for the DBI proxy
+driver, DBD::Proxy. It allows access to databases over the network if the
+DBMS does not offer networked operations. But the proxy server might be
+usefull for you, even if you have a DBMS with integrated network
+functionality: It can be used as a DBI proxy in a firewalled environment.
+
+DBI::ProxyServer runs as a daemon on the machine with the DBMS or on the
+firewall. The client connects to the agent using the DBI driver DBD::Proxy,
+thus in the exactly same way than using DBD::mysql, DBD::mSQL or any other
+DBI driver.
+
+The agent is implemented as a RPC::PlServer application. Thus you have
+access to all the possibilities of this module, in particular encryption
+and a similar configuration file. DBI::ProxyServer adds the possibility of
+query restrictions: You can define a set of queries that a client may
+execute and restrict access to those. (Requires a DBI driver that supports
+parameter binding.) See L</CONFIGURATION FILE>.
+
+The provided driver script, L<dbiproxy>, may either be used as it is or
+used as the basis for a local version modified to meet your needs.
+
+=head1 OPTIONS
+
+When calling the DBI::ProxyServer::main() function, you supply an
+array of options. These options are parsed by the Getopt::Long module.
+The ProxyServer inherits all of RPC::PlServer's and hence Net::Daemon's
+options and option handling, in particular the ability to read
+options from either the command line or a config file. See
+L<RPC::PlServer>. See L<Net::Daemon>. Available options include
+
+=over 4
+
+=item I<chroot> (B<--chroot=dir>)
+
+(UNIX only)  After doing a bind(), change root directory to the given
+directory by doing a chroot(). This is usefull for security, but it
+restricts the environment a lot. For example, you need to load DBI
+drivers in the config file or you have to create hard links to Unix
+sockets, if your drivers are using them. For example, with MySQL, a
+config file might contain the following lines:
+
+    my $rootdir = '/var/dbiproxy';
+    my $unixsockdir = '/tmp';
+    my $unixsockfile = 'mysql.sock';
+    foreach $dir ($rootdir, "$rootdir$unixsockdir") {
+	mkdir 0755, $dir;
+    }
+    link("$unixsockdir/$unixsockfile",
+	 "$rootdir$unixsockdir/$unixsockfile");
+    require DBD::mysql;
+
+    {
+	'chroot' => $rootdir,
+	...
+    }
+
+If you don't know chroot(), think of an FTP server where you can see a
+certain directory tree only after logging in. See also the --group and
+--user options.
+
+=item I<clients>
+
+An array ref with a list of clients. Clients are hash refs, the attributes
+I<accept> (0 for denying access and 1 for permitting) and I<mask>, a Perl
+regular expression for the clients IP number or its host name.
+
+=item I<configfile> (B<--configfile=file>)
+
+Config files are assumed to return a single hash ref that overrides the
+arguments of the new method. However, command line arguments in turn take
+precedence over the config file. See the L<"CONFIGURATION FILE"> section
+below for details on the config file.
+
+=item I<debug> (B<--debug>)
+
+Turn debugging mode on. Mainly this asserts that logging messages of
+level "debug" are created.
+
+=item I<facility> (B<--facility=mode>)
+
+(UNIX only) Facility to use for L<Sys::Syslog>. The default is
+B<daemon>.
+
+=item I<group> (B<--group=gid>)
+
+After doing a bind(), change the real and effective GID to the given.
+This is usefull, if you want your server to bind to a privileged port
+(<1024), but don't want the server to execute as root. See also
+the --user option.
+
+GID's can be passed as group names or numeric values.
+
+=item I<localaddr> (B<--localaddr=ip>)
+
+By default a daemon is listening to any IP number that a machine
+has. This attribute allows to restrict the server to the given
+IP number.
+
+=item I<localport> (B<--localport=port>)
+
+This attribute sets the port on which the daemon is listening. It
+must be given somehow, as there's no default.
+
+=item I<logfile> (B<--logfile=file>)
+
+Be default logging messages will be written to the syslog (Unix) or
+to the event log (Windows NT). On other operating systems you need to
+specify a log file. The special value "STDERR" forces logging to
+stderr. See L<Net::Daemon::Log> for details.
+
+=item I<mode> (B<--mode=modename>)
+
+The server can run in three different modes, depending on the environment.
+
+If you are running Perl 5.005 and did compile it for threads, then the
+server will create a new thread for each connection. The thread will
+execute the server's Run() method and then terminate. This mode is the
+default, you can force it with "--mode=threads".
+
+If threads are not available, but you have a working fork(), then the
+server will behave similar by creating a new process for each connection.
+This mode will be used automatically in the absence of threads or if
+you use the "--mode=fork" option.
+
+Finally there's a single-connection mode: If the server has accepted a
+connection, he will enter the Run() method. No other connections are
+accepted until the Run() method returns (if the client disconnects).
+This operation mode is usefull if you have neither threads nor fork(),
+for example on the Macintosh. For debugging purposes you can force this
+mode with "--mode=single".
+
+=item I<pidfile> (B<--pidfile=file>)
+
+(UNIX only) If this option is present, a PID file will be created at the
+given location. Default is to not create a pidfile.
+
+=item I<user> (B<--user=uid>)
+
+After doing a bind(), change the real and effective UID to the given.
+This is usefull, if you want your server to bind to a privileged port
+(<1024), but don't want the server to execute as root. See also
+the --group and the --chroot options.
+
+UID's can be passed as group names or numeric values.
+
+=item I<version> (B<--version>)
+
+Supresses startup of the server; instead the version string will
+be printed and the program exits immediately.
+
+=back
+
+
+=head1 CONFIGURATION FILE
+
+The configuration file is just that of I<RPC::PlServer> or I<Net::Daemon>
+with some additional attributes in the client list.
+
+The config file is a Perl script. At the top of the file you may include
+arbitraty Perl source, for example load drivers at the start (usefull
+to enhance performance), prepare a chroot environment and so on.
+
+The important thing is that you finally return a hash ref of option
+name/value pairs. The possible options are listed above.
+
+All possibilities of Net::Daemon and RPC::PlServer apply, in particular
+
+=over 4
+
+=item Host and/or User dependent access control
+
+=item Host and/or User dependent encryption
+
+=item Changing UID and/or GID after binding to the port
+
+=item Running in a chroot() environment
+
+=back
+
+Additionally the server offers you query restrictions. Suggest the
+following client list:
+
+    'clients' => [
+	{ 'mask' => '^admin\.company\.com$',
+          'accept' => 1,
+          'users' => [ 'root', 'wwwrun' ],
+        },
+        {
+	  'mask' => '^admin\.company\.com$',
+          'accept' => 1,
+          'users' => [ 'root', 'wwwrun' ],
+          'sql' => {
+               'select' => 'SELECT * FROM foo',
+               'insert' => 'INSERT INTO foo VALUES (?, ?, ?)'
+               }
+        }
+
+then only the users root and wwwrun may connect from admin.company.com,
+executing arbitrary queries, but only wwwrun may connect from other
+hosts and is restricted to
+
+    $sth->prepare("select");
+
+or
+
+    $sth->prepare("insert");
+
+which in fact are "SELECT * FROM foo" or "INSERT INTO foo VALUES (?, ?, ?)".
+
+
+=head1 Proxyserver Configuration file (bigger example)
+
+This section tells you how to restrict a DBI-Proxy: Not every user from
+every workstation shall be able to execute every query.
+
+There is a perl program "dbiproxy" which runs on a machine which is able
+to connect to all the databases we wish to reach. All Perl-DBD-drivers must
+be installed on this machine. You can also reach databases for which drivers 
+are not available on the machine where you run the programm querying the 
+database, e.g. ask MS-Access-database from Linux.
+
+Create a configuration file "proxy_oracle.cfg" at the dbproxy-server:
+
+    {
+	# This shall run in a shell or a DOS-window 
+	# facility => 'daemon',
+	pidfile => 'your_dbiproxy.pid',
+	logfile => 1,
+	debug => 0,
+	mode => 'single',
+	localport => '12400',
+
+	# Access control, the first match in this list wins!
+	# So the order is important
+	clients => [
+		# hint to organize:
+		# the most specialized rules for single machines/users are 1st
+		# then the denying rules
+		# the the rules about whole networks
+
+		# rule: internal_webserver
+		# desc: to get statistical information
+		{
+			# this IP-address only is meant
+			mask => '^10\.95\.81\.243$',
+			# accept (not defer) connections like this
+			accept => 1,
+			# only users from this list 
+			# are allowed to log on
+			users => [ 'informationdesk' ],
+			# only this statistical query is allowed
+			# to get results for a web-query
+			sql => {
+				alive => 'select count(*) from dual',
+				statistic_area => 'select count(*) from e01admin.e01e203 where geb_bezei like ?',
+			}
+		},
+
+		# rule: internal_bad_guy_1
+		{
+			mask => '^10\.95\.81\.1$',
+			accept => 0,
+		},
+
+		# rule: employee_workplace
+		# desc: get detailled informations
+		{
+			# any IP-address is meant here
+			mask => '^10\.95\.81\.(\d+)$',
+			# accept (not defer) connections like this
+			accept => 1,
+			# only users from this list 
+			# are allowed to log on
+			users => [ 'informationdesk', 'lippmann' ],
+			# all these queries are allowed:
+			sql => {
+				search_city => 'select ort_nr, plz, ort from e01admin.e01e200 where plz like ?',
+				search_area => 'select gebiettyp, geb_bezei from e01admin.e01e203 where geb_bezei like ? or geb_bezei like ?',
+			}
+		},
+
+		# rule: internal_bad_guy_2 
+		# This does NOT work, because rule "employee_workplace" hits
+		# with its ip-address-mask of the whole network
+		{
+			# don't accept connection from this ip-address
+			mask => '^10\.95\.81\.5$',
+			accept => 0,
+		}
+	]
+    }
+
+Start the proxyserver like this:
+
+	rem well-set Oracle_home needed for Oracle
+	set ORACLE_HOME=d:\oracle\ora81
+	dbiproxy --configfile proxy_oracle.cfg
+
+
+=head2 Testing the connection from a remote machine
+
+Call a programm "dbish" from your commandline. I take the machine from rule "internal_webserver"
+
+	dbish "dbi:Proxy:hostname=oracle.zdf;port=12400;dsn=dbi:Oracle:e01" informationdesk xxx
+
+There will be a shell-prompt:
+
+	informationdesk@dbi...> alive
+
+	Current statement buffer (enter '/'...):
+	alive
+
+	informationdesk@dbi...> /
+	COUNT(*)
+	'1'
+	[1 rows of 1 fields returned]
+
+
+=head2 Testing the connection with a perl-script
+
+Create a perl-script like this:
+
+	# file: oratest.pl
+	# call me like this: perl oratest.pl user password
+
+	use strict;
+	use DBI;
+
+	my $user = shift || die "Usage: $0 user password";
+	my $pass = shift || die "Usage: $0 user password";
+	my $config = {
+		dsn_at_proxy => "dbi:Oracle:e01",
+		proxy => "hostname=oechsle.zdf;port=12400",
+	};
+	my $dsn = sprintf "dbi:Proxy:%s;dsn=%s",
+		$config->{proxy},
+		$config->{dsn_at_proxy};
+
+	my $dbh = DBI->connect( $dsn, $user, $pass )
+		|| die "connect did not work: $DBI::errstr";
+
+	my $sql = "search_city";
+	printf "%s\n%s\n%s\n", "="x40, $sql, "="x40;
+	my $cur = $dbh->prepare($sql);
+	$cur->bind_param(1,'905%');
+	&show_result ($cur);
+
+	my $sql = "search_area";
+	printf "%s\n%s\n%s\n", "="x40, $sql, "="x40;
+	my $cur = $dbh->prepare($sql);
+	$cur->bind_param(1,'Pfarr%');
+	$cur->bind_param(2,'Bronnamberg%');
+	&show_result ($cur);
+
+	my $sql = "statistic_area";
+	printf "%s\n%s\n%s\n", "="x40, $sql, "="x40;
+	my $cur = $dbh->prepare($sql);
+	$cur->bind_param(1,'Pfarr%');
+	&show_result ($cur);
+
+	$dbh->disconnect;
+	exit;
+
+
+	sub show_result {
+		my $cur = shift;
+		unless ($cur->execute()) {
+			print "Could not execute\n"; 
+			return; 
+		}
+
+		my $rownum = 0;
+		while (my @row = $cur->fetchrow_array()) {
+			printf "Row is: %s\n", join(", ",@row);
+			if ($rownum++ > 5) {
+				print "... and so on\n";
+				last;
+			}	
+		}
+		$cur->finish;
+	}
+
+The result
+
+	C:\>perl oratest.pl informationdesk xxx
+	========================================
+	search_city
+	========================================
+	Row is: 3322, 9050, Chemnitz
+	Row is: 3678, 9051, Chemnitz
+	Row is: 10447, 9051, Chemnitz
+	Row is: 12128, 9051, Chemnitz
+	Row is: 10954, 90513, Zirndorf
+	Row is: 5808, 90513, Zirndorf
+	Row is: 5715, 90513, Zirndorf
+	... and so on
+	========================================
+	search_area
+	========================================
+	Row is: 101, Bronnamberg
+	Row is: 400, Pfarramt Zirndorf
+	Row is: 400, Pfarramt Rosstal
+	Row is: 400, Pfarramt Oberasbach
+	Row is: 401, Pfarramt Zirndorf
+	Row is: 401, Pfarramt Rosstal
+	========================================
+	statistic_area
+	========================================
+	DBD::Proxy::st execute failed: Server returned error: Failed to execute method CallMethod: Unknown SQL query: statistic_area at E:/Perl/site/lib/DBI/ProxyServer.pm line 258.
+	Could not execute
+
+
+=head2 How the configuration works
+
+The most important section to control access to your dbi-proxy is "client=>"
+in the file "proxy_oracle.cfg":
+
+Controlling which person at which machine is allowed to access
+
+=over 4
+
+=item * "mask" is a perl regular expression against the plain ip-address of the machine which wishes to connect _or_ the reverse-lookup from a nameserver.
+
+=item * "accept" tells the dbiproxy-server wether ip-adresse like in "mask" are allowed to connect or not (0/1)
+
+=item * "users" is a reference to a list of usernames which must be matched, this is NOT a regular expression.
+
+=back
+
+Controlling which SQL-statements are allowed
+
+You can put every SQL-statement you like in simply ommiting "sql => ...", but the more important thing is to restrict the connection so that only allowed queries are possible.
+
+If you include an sql-section in your config-file like this:
+
+	sql => {
+		alive => 'select count(*) from dual',
+		statistic_area => 'select count(*) from e01admin.e01e203 where geb_bezei like ?',
+	}
+
+The user is allowed to put two queries against the dbi-proxy. The queries are _not_ "select count(*)...", the queries are "alive" and "statistic_area"! These keywords are replaced by the real query. So you can run a query for "alive":
+
+	my $sql = "alive";
+	my $cur = $dbh->prepare($sql);
+	...
+
+The flexibility is that you can put parameters in the where-part of the query so the query are not static. Simply replace a value in the where-part of the query through a question mark and bind it as a parameter to the query. 
+
+	my $sql = "statistic_area";
+	my $cur = $dbh->prepare($sql);
+	$cur->bind_param(1,'905%');
+	# A second parameter would be called like this:
+	# $cur->bind_param(2,'98%');
+
+The result is this query:
+
+	select count(*) from e01admin.e01e203 
+	where geb_bezei like '905%'
+
+Don't try to put parameters into the sql-query like this:
+
+	# Does not work like you think.
+	# Only the first word of the query is parsed,
+	# so it's changed to "statistic_area", the rest is omitted.
+	# You _have_ to work with $cur->bind_param.
+	my $sql = "statistic_area 905%";
+	my $cur = $dbh->prepare($sql);
+	...
+
+
+=head2 Problems
+
+=over 4
+
+=item * I don't know how to restrict users to special databases.
+
+=item * I don't know how to pass query-parameters via dbish
+
+=back
+
+
+=head1 AUTHOR
+
+    Copyright (c) 1997    Jochen Wiedmann
+                          Am Eisteich 9
+                          72555 Metzingen
+                          Germany
+
+                          Email: joe@ispsoft.de
+                          Phone: +49 7123 14881
+
+The DBI::ProxyServer module is free software; you can redistribute it
+and/or modify it under the same terms as Perl itself. In particular
+permission is granted to Tim Bunce for distributing this as a part of
+the DBI.
+
+
+=head1 SEE ALSO
+
+L<dbiproxy>, L<DBD::Proxy>, L<DBI>, L<RPC::PlServer>,
+L<RPC::PlClient>, L<Net::Daemon>, L<Net::Daemon::Log>,
+L<Sys::Syslog>, L<Win32::EventLog>, L<syslog>
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/PurePerl.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/PurePerl.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/PurePerl.pm	(revision 14139)
@@ -0,0 +1,1014 @@
+########################################################################
+package		# hide from PAUSE
+	DBI;
+# vim: ts=8:sw=4
+########################################################################
+#
+# Copyright (c) 2002,2003  Tim Bunce  Ireland.
+#
+# See COPYRIGHT section in DBI.pm for usage and distribution rights.
+#
+########################################################################
+#
+# Please send patches and bug reports to
+#
+# Jeff Zucker <jeff@vpservices.com>  with cc to <dbi-dev@perl.org>
+#
+########################################################################
+
+# TODO:
+#	recheck code against DBI
+
+use strict;
+use Carp;
+require Symbol;
+
+require utf8;
+*utf8::is_utf8 = sub { # hack for perl 5.6
+    require bytes;
+    return unless defined $_[0];
+    return !(length($_[0]) == bytes::length($_[0]))
+} unless defined &utf8::is_utf8;
+
+$DBI::PurePerl = $ENV{DBI_PUREPERL} || 1;
+$DBI::PurePerl::VERSION = sprintf "%d.%02d", '$Revision$ ' =~ /(\d+)\.(\d+)/;
+$DBI::neat_maxlen ||= 400;
+
+$DBI::tfh = Symbol::gensym();
+open $DBI::tfh, ">&STDERR" or warn "Can't dup STDERR: $!";
+select( (select($DBI::tfh), $| = 1)[0] );  # autoflush
+
+
+%DBI::last_method_except = map { $_=>1 } qw(DESTROY _set_fbav set_err);
+
+use constant SQL_ALL_TYPES => 0;
+use constant SQL_ARRAY => 50;
+use constant SQL_ARRAY_LOCATOR => 51;
+use constant SQL_BINARY => (-2);
+use constant SQL_BIT => (-7);
+use constant SQL_BLOB => 30;
+use constant SQL_BLOB_LOCATOR => 31;
+use constant SQL_BOOLEAN => 16;
+use constant SQL_CHAR => 1;
+use constant SQL_CLOB => 40;
+use constant SQL_CLOB_LOCATOR => 41;
+use constant SQL_DATE => 9;
+use constant SQL_DATETIME => 9;
+use constant SQL_DECIMAL => 3;
+use constant SQL_DOUBLE => 8;
+use constant SQL_FLOAT => 6;
+use constant SQL_GUID => (-11);
+use constant SQL_INTEGER => 4;
+use constant SQL_INTERVAL => 10;
+use constant SQL_INTERVAL_DAY => 103;
+use constant SQL_INTERVAL_DAY_TO_HOUR => 108;
+use constant SQL_INTERVAL_DAY_TO_MINUTE => 109;
+use constant SQL_INTERVAL_DAY_TO_SECOND => 110;
+use constant SQL_INTERVAL_HOUR => 104;
+use constant SQL_INTERVAL_HOUR_TO_MINUTE => 111;
+use constant SQL_INTERVAL_HOUR_TO_SECOND => 112;
+use constant SQL_INTERVAL_MINUTE => 105;
+use constant SQL_INTERVAL_MINUTE_TO_SECOND => 113;
+use constant SQL_INTERVAL_MONTH => 102;
+use constant SQL_INTERVAL_SECOND => 106;
+use constant SQL_INTERVAL_YEAR => 101;
+use constant SQL_INTERVAL_YEAR_TO_MONTH => 107;
+use constant SQL_LONGVARBINARY => (-4);
+use constant SQL_LONGVARCHAR => (-1);
+use constant SQL_MULTISET => 55;
+use constant SQL_MULTISET_LOCATOR => 56;
+use constant SQL_NUMERIC => 2;
+use constant SQL_REAL => 7;
+use constant SQL_REF => 20;
+use constant SQL_ROW => 19;
+use constant SQL_SMALLINT => 5;
+use constant SQL_TIME => 10;
+use constant SQL_TIMESTAMP => 11;
+use constant SQL_TINYINT => (-6);
+use constant SQL_TYPE_DATE => 91;
+use constant SQL_TYPE_TIME => 92;
+use constant SQL_TYPE_TIMESTAMP => 93;
+use constant SQL_TYPE_TIMESTAMP_WITH_TIMEZONE => 95;
+use constant SQL_TYPE_TIME_WITH_TIMEZONE => 94;
+use constant SQL_UDT => 17;
+use constant SQL_UDT_LOCATOR => 18;
+use constant SQL_UNKNOWN_TYPE => 0;
+use constant SQL_VARBINARY => (-3);
+use constant SQL_VARCHAR => 12;
+use constant SQL_WCHAR => (-8);
+use constant SQL_WLONGVARCHAR => (-10);
+use constant SQL_WVARCHAR => (-9);
+
+# for Cursor types
+use constant SQL_CURSOR_FORWARD_ONLY  => 0;
+use constant SQL_CURSOR_KEYSET_DRIVEN => 1;
+use constant SQL_CURSOR_DYNAMIC       => 2;
+use constant SQL_CURSOR_STATIC        => 3;
+use constant SQL_CURSOR_TYPE_DEFAULT  => SQL_CURSOR_FORWARD_ONLY;
+
+use constant IMA_HAS_USAGE	=> 0x0001; #/* check parameter usage	*/
+use constant IMA_FUNC_REDIRECT	=> 0x0002; #/* is $h->func(..., "method")*/
+use constant IMA_KEEP_ERR	=> 0x0004; #/* don't reset err & errstr	*/
+use constant IMA_KEEP_ERR_SUB	=> 0x0008; #/*  '' if in nested call */
+use constant IMA_NO_TAINT_IN   	=> 0x0010; #/* don't check for tainted args*/
+use constant IMA_NO_TAINT_OUT   => 0x0020; #/* don't taint results	*/
+use constant IMA_COPY_STMT   	=> 0x0040; #/* copy sth Statement to dbh */
+use constant IMA_END_WORK	=> 0x0080; #/* set on commit & rollback	*/
+use constant IMA_STUB		=> 0x0100; #/* donothing eg $dbh->connected */
+#define IMA_CLEAR_STMT             0x0200  /* clear Statement before call  */
+#define IMA_PROF_EMPTY_STMT        0x0400  /* profile as empty Statement   */
+use constant IMA_NOT_FOUND_OKAY	=> 0x0800; #/* not error if not found */
+use constant IMA_EXECUTE	=> 0x1000; #/* do/execute: DBIcf_Executed   */
+
+my %is_flag_attribute = map {$_ =>1 } qw(
+	Active
+	AutoCommit
+	ChopBlanks
+	CompatMode
+	Executed
+	Taint
+	TaintIn
+	TaintOut
+	InactiveDestroy
+	LongTruncOk
+	MultiThread
+	PrintError
+	PrintWarn
+	RaiseError
+	ShowErrorStatement
+	Warn
+);
+my %is_valid_attribute = map {$_ =>1 } (keys %is_flag_attribute, qw(
+	ActiveKids
+	Attribution
+	BegunWork
+	CachedKids
+	CursorName
+	Database
+	DebugDispatch
+	Driver
+	ErrCount
+	FetchHashKeyName
+	HandleError
+	HandleSetErr
+	ImplementorClass
+	Kids
+	LongReadLen
+	NAME NAME_uc NAME_lc NAME_uc_hash NAME_lc_hash
+	NULLABLE
+	NUM_OF_FIELDS
+	NUM_OF_PARAMS
+	Name
+	PRECISION
+	ParamValues
+	Profile
+	Provider
+	RootClass
+	RowCacheSize
+	RowsInCache
+	SCALE
+	Statement
+	TYPE
+	TraceLevel
+	Username
+	Version
+));
+
+sub valid_attribute {
+    my $attr = shift;
+    return 1 if $is_valid_attribute{$attr};
+    return 1 if $attr =~ m/^[a-z]/; # starts with lowercase letter
+    return 0
+}
+
+my $initial_setup;
+sub initial_setup {
+    $initial_setup = 1;
+    print $DBI::tfh  __FILE__ . " version " . $DBI::PurePerl::VERSION . "\n"
+	if $DBI::dbi_debug & 0xF;
+    untie $DBI::err;
+    untie $DBI::errstr;
+    untie $DBI::state;
+    untie $DBI::rows;
+    #tie $DBI::lasth,  'DBI::var', '!lasth';  # special case: return boolean
+}
+
+sub  _install_method {
+    my ( $caller, $method, $from, $param_hash ) = @_;
+    initial_setup() unless $initial_setup;
+
+    my ($class, $method_name) = $method =~ /^[^:]+::(.+)::(.+)$/;
+    my $bitmask = $param_hash->{'O'} || 0;
+    my @pre_call_frag;
+
+    return if $method_name eq 'can';
+
+    push @pre_call_frag, q{
+	return if $h_inner; # ignore DESTROY for outer handle
+	# copy err/errstr/state up to driver so $DBI::err etc still work
+	if ($h->{err} and my $drh = $h->{Driver}) {
+	    $drh->{$_} = $h->{$_} for ('err','errstr','state');
+	}
+    } if $method_name eq 'DESTROY';
+
+    push @pre_call_frag, q{
+	return $h->{$_[0]} if exists $h->{$_[0]};
+    } if $method_name eq 'FETCH' && !exists $ENV{DBI_TRACE}; # XXX ?
+
+    push @pre_call_frag, "return;"
+	if IMA_STUB & $bitmask;
+
+    push @pre_call_frag, q{
+	#$method_name = $imp . '::' . pop @_;
+	$method_name = pop @_;
+    } if IMA_FUNC_REDIRECT & $bitmask;
+
+    push @pre_call_frag, q{
+	my $parent_dbh = $h->{Database};
+    } if (IMA_COPY_STMT|IMA_EXECUTE) & $bitmask;
+
+    push @pre_call_frag, q{
+	warn "No Database set for $h on $method_name!" unless $parent_dbh; # eg proxy problems
+	$parent_dbh->{Statement} = $h->{Statement} if $parent_dbh;
+    } if IMA_COPY_STMT & $bitmask;
+
+    push @pre_call_frag, q{
+	$h->{Executed} = 1;
+	$parent_dbh->{Executed} = 1 if $parent_dbh;
+    } if IMA_EXECUTE & $bitmask;
+
+    if (IMA_KEEP_ERR & $bitmask) {
+	push @pre_call_frag, q{
+	    my $keep_error = 1;
+	};
+    }
+    else {
+	my $ke_init = (IMA_KEEP_ERR_SUB & $bitmask)
+		? q{= $h->{_parent}->{_call_depth} }
+		: "";
+	push @pre_call_frag, qq{
+	    my \$keep_error $ke_init;
+	};
+	my $keep_error_code = q{
+	    #warn "$method_name cleared err";
+	    $h->{err}    = $DBI::err    = undef;
+	    $h->{errstr} = $DBI::errstr = undef;
+	    $h->{state}  = $DBI::state  = '';
+	};
+	$keep_error_code = q{
+	    printf $DBI::tfh "    !! %s: %s CLEARED by call to }.$method_name.q{ method\n".
+		    $h->{err}, $h->{err}
+		if defined $h->{err} && $DBI::dbi_debug & 0xF;
+	}. $keep_error_code
+	    if exists $ENV{DBI_TRACE};
+	push @pre_call_frag, ($ke_init)
+		? qq{ unless (\$keep_error) { $keep_error_code }}
+		: $keep_error_code
+	    unless $method_name eq 'set_err';
+    }
+
+    push @pre_call_frag, q{
+	my $ErrCount = $h->{ErrCount};
+    };
+
+    push @pre_call_frag, q{
+        if (($DBI::dbi_debug & 0xF) >= 2) {
+	    local $^W;
+	    my $args = join " ", map { DBI::neat($_) } ($h, @_);
+	    printf $DBI::tfh "    > $method_name in $imp ($args) [$@]\n";
+	}
+    } if exists $ENV{DBI_TRACE};	# note use of 'exists'
+
+    push @pre_call_frag, q{
+        $h->{'_last_method'} = $method_name;
+    } unless exists $DBI::last_method_except{$method_name};
+
+    # --- post method call code fragments ---
+    my @post_call_frag;
+
+    push @post_call_frag, q{
+        if (my $trace_level = ($DBI::dbi_debug & 0xF)) {
+	    if ($h->{err}) {
+		printf $DBI::tfh "    !! ERROR: %s %s\n", $h->{err}, $h->{errstr};
+	    }
+	    my $ret = join " ", map { DBI::neat($_) } @ret;
+	    my $msg = "    < $method_name= $ret";
+	    $msg = ($trace_level >= 2) ? Carp::shortmess($msg) : "$msg\n";
+	    print $DBI::tfh $msg;
+	}
+    } if exists $ENV{DBI_TRACE}; # note use of exists
+
+    push @post_call_frag, q{
+	$h->{Executed} = 0;
+	if ($h->{BegunWork}) {
+	    $h->{BegunWork}  = 0;
+	    $h->{AutoCommit} = 1;
+	}
+    } if IMA_END_WORK & $bitmask;
+
+    push @post_call_frag, q{
+	$keep_error = 0 if $keep_error && $h->{ErrCount} > $ErrCount;
+
+	$DBI::err    = $h->{err};
+	$DBI::errstr = $h->{errstr};
+	$DBI::state  = $h->{state};
+
+        if ( !$keep_error
+	&& defined(my $err = $h->{err})
+	&& ($call_depth <= 1 && !$h->{_parent}{_call_depth})
+	) {
+
+	    my($pe,$pw,$re,$he) = @{$h}{qw(PrintError PrintWarn RaiseError HandleError)};
+	    my $msg;
+
+	    if ($err && ($pe || $re || $he)	# error
+	    or (!$err && length($err) && $pw)	# warning
+	    ) {
+		my $last = ($DBI::last_method_except{$method_name})
+		    ? ($h->{'_last_method'}||$method_name) : $method_name;
+		my $errstr = $h->{errstr} || $DBI::errstr || $err || '';
+		my $msg = sprintf "%s %s %s: %s", $imp, $last,
+			($err eq "0") ? "warning" : "failed", $errstr;
+
+		if ($h->{'ShowErrorStatement'} and my $Statement = $h->{Statement}) {
+		    $msg .= ' for [``' . $Statement . "''";
+		    if (my $ParamValues = $h->FETCH('ParamValues')) {
+			my $pv_idx = 0;
+			$msg .= " with params: ";
+			while ( my($k,$v) = each %$ParamValues ) {
+			    $msg .= sprintf "%s%s=%s", ($pv_idx++==0) ? "" : ", ", $k, DBI::neat($v);
+			}
+		    }
+		    $msg .= "]";
+		}
+		if ($err eq "0") { # is 'warning' (not info)
+		    carp $msg if $pw;
+		}
+		else {
+		    my $do_croak = 1;
+		    if (my $subsub = $h->{'HandleError'}) {
+			$do_croak = 0 if &$subsub($msg,$h,$ret[0]);
+		    }
+		    if ($do_croak) {
+			printf $DBI::tfh "    $method_name has failed ($h->{PrintError},$h->{RaiseError})\n"
+				if ($DBI::dbi_debug & 0xF) >= 4;
+			carp  $msg if $pe;
+			die $msg if $h->{RaiseError};
+		    }
+		}
+	    }
+	}
+    };
+
+
+    my $method_code = q[
+      sub {
+        my $h = shift;
+	my $h_inner = tied(%$h);
+	$h = $h_inner if $h_inner;
+
+        my $imp;
+	if ($method_name eq 'DESTROY') {
+	    # during global destruction, $h->{...} can trigger "Can't call FETCH on an undef value"
+	    # implying that tied() above lied to us, so we need to use eval
+	    local $@;	 # protect $@
+	    $imp = eval { $h->{"ImplementorClass"} } or return; # probably global destruction
+	}
+	else {
+	    $imp = $h->{"ImplementorClass"} or return; # probably global destruction
+	}
+
+	] . join("\n", '', @pre_call_frag, '') . q[
+
+	my $call_depth = $h->{'_call_depth'} + 1;
+	local ($h->{'_call_depth'}) = $call_depth;
+
+	my @ret;
+        my $sub = $imp->can($method_name);
+	if ($sub) {
+	    (wantarray) ? (@ret = &$sub($h,@_)) : (@ret = scalar &$sub($h,@_));
+	}
+	else {
+	    # XXX could try explicit fallback to $imp->can('AUTOLOAD') etc
+	    # which would then let Multiplex pass PurePerl tests, but some
+	    # hook into install_method may be better.
+	    croak "Can't find DBI method $method_name for $h (via $imp)"
+		if ] . ((IMA_NOT_FOUND_OKAY & $bitmask) ? 0 : 1) . q[;
+	}
+
+	] . join("\n", '', @post_call_frag, '') . q[
+
+	return (wantarray) ? @ret : $ret[0];
+      }
+    ];
+    no strict qw(refs);
+    my $code_ref = eval qq{#line 1 "$method"\n$method_code};
+    warn "$@\n$method_code\n" if $@;
+    die "$@\n$method_code\n" if $@;
+    *$method = $code_ref;
+    if (0 && $method =~ /do/) { # debuging tool
+	my $l=0; # show line-numbered code for method
+	warn "*$method = ".join("\n", map { ++$l.": $_" } split/\n/,$method_code);
+    }
+}
+
+sub _setup_handle {
+    my($h, $imp_class, $parent, $imp_data) = @_;
+    my $h_inner = tied(%$h) || $h;
+    if (($DBI::dbi_debug & 0xF) >= 4) {
+	local $^W;
+	print $DBI::tfh "      _setup_handle(@_)\n";
+    }
+    $h_inner->{"imp_data"} = $imp_data;
+    $h_inner->{"ImplementorClass"} = $imp_class;
+    $h_inner->{"Kids"} = $h_inner->{"ActiveKids"} = 0;	# XXX not maintained
+    if ($parent) {
+	foreach (qw(
+	    RaiseError PrintError PrintWarn HandleError HandleSetErr
+	    Warn LongTruncOk ChopBlanks AutoCommit
+	    ShowErrorStatement FetchHashKeyName LongReadLen CompatMode
+	)) {
+	    $h_inner->{$_} = $parent->{$_}
+		if exists $parent->{$_} && !exists $h_inner->{$_};
+	}
+	if (ref($parent) =~ /::db$/) {
+	    $h_inner->{Database} = $parent;
+	    $parent->{Statement} = $h_inner->{Statement};
+	    $h_inner->{NUM_OF_PARAMS} = 0;
+	}
+	elsif (ref($parent) =~ /::dr$/){
+	    $h_inner->{Driver} = $parent;
+	}
+	$h_inner->{_parent} = $parent;
+    }
+    else {	# setting up a driver handle
+        $h_inner->{Warn}		= 1;
+        $h_inner->{PrintWarn}		= $^W;
+        $h_inner->{AutoCommit}		= 1;
+        $h_inner->{TraceLevel}		= 0;
+        $h_inner->{CompatMode}		= (1==0);
+	$h_inner->{FetchHashKeyName}	||= 'NAME';
+	$h_inner->{LongReadLen}		||= 80;
+    }
+    $h_inner->{"_call_depth"} = 0;
+    $h_inner->{ErrCount} = 0;
+    $h_inner->{Active} = 1;
+}
+sub constant {
+    warn "constant @_"; return;
+}
+sub trace {
+    my ($h, $level, $file) = @_;
+    $level = $h->parse_trace_flags($level)
+	if defined $level and !DBI::looks_like_number($level);
+    my $old_level = $DBI::dbi_debug;
+    _set_trace_file($file);
+    if (defined $level) {
+	$DBI::dbi_debug = $level;
+	print $DBI::tfh "    DBI $DBI::VERSION (PurePerl) "
+                . "dispatch trace level set to $DBI::dbi_debug\n"
+		if $DBI::dbi_debug & 0xF;
+        if ($level==0 and fileno($DBI::tfh)) {
+	    _set_trace_file("");
+        }
+    }
+    return $old_level;
+}
+sub _set_trace_file {
+    my ($file) = @_;
+    return unless defined $file;
+    if (!$file || $file eq 'STDERR') {
+	open $DBI::tfh, ">&STDERR" or warn "Can't dup STDERR: $!";
+	return 1;
+    }
+    if ($file eq 'STDOUT') {
+	open $DBI::tfh, ">&STDOUT" or warn "Can't dup STDOUT: $!";
+	return 1;
+    }
+    open $DBI::tfh, ">>$file" or carp "Can't open $file: $!";
+    select((select($DBI::tfh), $| = 1)[0]);
+    return 1;
+}
+sub _get_imp_data {  shift->{"imp_data"}; }
+sub _svdump       { }
+sub dump_handle   {
+    my ($h,$msg,$level) = @_;
+    $msg||="dump_handle $h";
+    print $DBI::tfh "$msg:\n";
+    for my $attrib (sort keys %$h) {
+	print $DBI::tfh "\t$attrib => ".DBI::neat($h->{$attrib})."\n";
+    }
+}
+
+sub _handles {
+    my $h = shift;
+    my $h_inner = tied %$h;
+    if ($h_inner) {	# this is okay
+	return $h unless wantarray;
+	return ($h, $h_inner);
+    }
+    # XXX this isn't okay... we have an inner handle but
+    # currently have no way to get at its outer handle,
+    # so we just warn and return the inner one for both...
+    Carp::carp("Can't return outer handle from inner handle using DBI::PurePerl");
+    return $h unless wantarray;
+    return ($h,$h);
+}
+
+sub hash {
+    my ($key, $type) = @_;
+    my ($hash);
+    if (!$type) {
+        $hash = 0;
+        # XXX The C version uses the "char" type, which could be either
+        # signed or unsigned.  I use signed because so do the two
+        # compilers on my system.
+        for my $char (unpack ("c*", $key)) {
+            $hash = $hash * 33 + $char;
+        }
+        $hash &= 0x7FFFFFFF;    # limit to 31 bits
+        $hash |= 0x40000000;    # set bit 31
+        return -$hash;          # return negative int
+    }
+    elsif ($type == 1) {	# Fowler/Noll/Vo hash
+        # see http://www.isthe.com/chongo/tech/comp/fnv/
+        require Math::BigInt;   # feel free to reimplement w/o BigInt!
+	(my $version = $Math::BigInt::VERSION || 0) =~ s/_.*//; # eg "1.70_01"
+	if ($version >= 1.56) {
+	    $hash = Math::BigInt->new(0x811c9dc5);
+	    for my $uchar (unpack ("C*", $key)) {
+		# multiply by the 32 bit FNV magic prime mod 2^64
+		$hash = ($hash * 0x01000193) & 0xffffffff;
+		# xor the bottom with the current octet
+		$hash ^= $uchar;
+	    }
+	    # cast to int
+	    return unpack "i", pack "i", $hash;
+	}
+	croak("DBI::PurePerl doesn't support hash type 1 without Math::BigInt >= 1.56 (available on CPAN)");
+    }
+    else {
+        croak("bad hash type $type");
+    }
+}
+sub looks_like_number {
+    my @new = ();
+    for my $thing(@_) {
+        if (!defined $thing or $thing eq '') {
+            push @new, undef;
+        }
+        else {
+            push @new, ($thing =~ /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/) ? 1 : 0;
+        }
+    }
+    return (@_ >1) ? @new : $new[0];
+}
+
+sub neat {
+    my $v = shift;
+    return "undef" unless defined $v;
+    return $v if (($v & ~ $v) eq "0"); # is SvNIOK
+    my $quote = utf8::is_utf8($v) ? '"' : "'";
+    my $maxlen = shift || $DBI::neat_maxlen;
+    if ($maxlen && $maxlen < length($v) + 2) {
+	$v = substr($v,0,$maxlen-5);
+	$v .= '...';
+    }
+    return "$quote$v$quote";
+}
+
+package
+	DBI::var;
+
+sub FETCH {
+    my($key)=shift;
+    return $DBI::err     if $$key eq '*err';
+    return $DBI::errstr  if $$key eq '&errstr';
+    Carp::confess("FETCH $key not supported when using DBI::PurePerl");
+}
+
+package
+	DBD::_::common;
+
+sub swap_inner_handle {
+    my ($h1, $h2) = @_;
+    # can't make this work till we can get the outer handle from the inner one
+    # probably via a WeakRef
+    return $h1->set_err(1, "swap_inner_handle not currently supported by DBI::PurePerl");
+}
+
+sub trace {	# XXX should set per-handle level, not global
+    my ($h, $level, $file) = @_;
+    $level = $h->parse_trace_flags($level)
+	if defined $level and !DBI::looks_like_number($level);
+    my $old_level = $DBI::dbi_debug;
+    DBI::_set_trace_file($file) if defined $file;
+    if (defined $level) {
+	$DBI::dbi_debug = $level;
+	if ($DBI::dbi_debug) {
+	    printf $DBI::tfh
+		"    %s trace level set to %d in DBI $DBI::VERSION (PurePerl)\n",
+		$h, $DBI::dbi_debug;
+	    print $DBI::tfh "    Full trace not available because DBI_TRACE is not in environment\n"
+		unless exists $ENV{DBI_TRACE};
+	}
+    }
+    return $old_level;
+}
+*debug = \&trace; *debug = \&trace; # twice to avoid typo warning
+
+sub FETCH {
+    my($h,$key)= @_;
+    my $v = $h->{$key};
+#warn ((exists $h->{$key}) ? "$key=$v\n" : "$key NONEXISTANT\n");
+    return $v if defined $v;
+    if ($key =~ /^NAME_.c$/) {
+        my $cols = $h->FETCH('NAME');
+        return undef unless $cols;
+        my @lcols = map { lc $_ } @$cols;
+        $h->STORE('NAME_lc', \@lcols);
+        my @ucols = map { uc $_ } @$cols;
+        $h->STORE('NAME_uc',\@ucols);
+        return $h->FETCH($key);
+    }
+    if ($key =~ /^NAME.*_hash$/) {
+        my $i=0;
+        for my $c(@{$h->FETCH('NAME')||[]}) {
+            $h->{'NAME_hash'}->{$c}    = $i;
+            $h->{'NAME_lc_hash'}->{"\L$c"} = $i;
+            $h->{'NAME_uc_hash'}->{"\U$c"} = $i;
+            $i++;
+        }
+        return $h->{$key};
+    }
+    if (!defined $v && !exists $h->{$key}) {
+	return ($h->FETCH('TaintIn') && $h->FETCH('TaintOut')) if $key eq'Taint';
+	return (1==0) if $is_flag_attribute{$key}; # return perl-style sv_no, not undef
+	return $DBI::dbi_debug if $key eq 'TraceLevel';
+	if (!$is_valid_attribute{$key} and $key =~ m/^[A-Z]/) {
+	    local $^W; # hide undef warnings
+	    Carp::carp( sprintf "Can't get %s->{%s}: unrecognised attribute (@{[ %$h ]})",$h,$key )
+	}
+    }
+    return $v;
+}
+sub STORE {
+    my ($h,$key,$value) = @_;
+    if ($key eq 'AutoCommit') {
+	croak("DBD driver has not implemented the AutoCommit attribute")
+	    unless $value == -900 || $value == -901;
+	$value = ($value == -901);
+    }
+    elsif ($key =~ /^Taint/ ) {
+	Carp::croak(sprintf "Can't set %s->{%s}: Taint mode not supported by DBI::PurePerl",$h,$key)
+		if $value;
+    }
+    elsif ($key eq 'TraceLevel') {
+	$h->trace($value);
+	return 1;
+    }
+    elsif (!$is_valid_attribute{$key} && $key =~ /^[A-Z]/ && !exists $h->{$key}) {
+       Carp::carp(sprintf "Can't set %s->{%s}: unrecognised attribute or invalid value %s",
+	    $h,$key,$value);
+    }
+    $h->{$key} = $is_flag_attribute{$key} ? !!$value : $value;
+    return 1;
+}
+sub err    { return shift->{err}    }
+sub errstr { return shift->{errstr} }
+sub state  { return shift->{state}  }
+sub set_err {
+    my ($h, $errnum,$msg,$state, $method, $rv) = @_;
+    $h = tied(%$h) || $h;
+
+    if (my $hss = $h->{HandleSetErr}) {
+	return if $hss->($h, $errnum, $msg, $state, $method);
+    }
+
+    if (!defined $errnum) {
+	$h->{err}    = $DBI::err    = undef;
+	$h->{errstr} = $DBI::errstr = undef;
+	$h->{state}  = $DBI::state  = '';
+        return;
+    }
+
+    if ($h->{errstr}) {
+	$h->{errstr} .= sprintf " [err was %s now %s]", $h->{err}, $errnum
+		if $h->{err} && $errnum;
+	$h->{errstr} .= sprintf " [state was %s now %s]", $h->{state}, $state
+		if $h->{state} and $h->{state} ne "S1000" && $state;
+	$h->{errstr} .= "\n$msg";
+	$DBI::errstr = $h->{errstr};
+    }
+    else {
+	$h->{errstr} = $DBI::errstr = $msg;
+    }
+
+    # assign if higher priority: err > "0" > "" > undef
+    my $err_changed;
+    if ($errnum			# new error: so assign
+	or !defined $h->{err}	# no existing warn/info: so assign
+           # new warn ("0" len 1) > info ("" len 0): so assign
+	or defined $errnum && length($errnum) > length($h->{err})
+    ) {
+        $h->{err} = $DBI::err = $errnum;
+	++$h->{ErrCount} if $errnum;
+	++$err_changed;
+    }
+
+    if ($err_changed) {
+	$state ||= "S1000" if $DBI::err;
+	$h->{state} = $DBI::state = ($state eq "00000") ? "" : $state
+	    if $state;
+    }
+
+    if (my $p = $h->{Database}) { # just sth->dbh, not dbh->drh (see ::db::DESTROY)
+	$p->{err}    = $DBI::err;
+	$p->{errstr} = $DBI::errstr;
+	$p->{state}  = $DBI::state;
+    }
+
+    $h->{'_last_method'} = $method;
+    return $rv; # usually undef
+}
+sub trace_msg {
+    my ($h, $msg, $minlevel)=@_;
+    $minlevel = 1 unless $minlevel;
+    return unless $minlevel <= ($DBI::dbi_debug & 0xF);
+    print $DBI::tfh $msg;
+    return 1;
+}
+sub private_data {
+    warn "private_data @_";
+}
+sub take_imp_data {
+    undef;
+}
+sub rows {
+    return -1; # always returns -1 here, see DBD::_::st::rows below
+}
+sub DESTROY {
+}
+
+package
+	DBD::_::st;
+
+sub fetchrow_arrayref	{
+    my $h = shift;
+    # if we're here then driver hasn't implemented fetch/fetchrow_arrayref
+    # so we assume they've implemented fetchrow_array and call that instead
+    my @row = $h->fetchrow_array or return;
+    return $h->_set_fbav(\@row);
+}
+# twice to avoid typo warning
+*fetch = \&fetchrow_arrayref;  *fetch = \&fetchrow_arrayref;
+
+sub fetchrow_array	{
+    my $h = shift;
+    # if we're here then driver hasn't implemented fetchrow_array
+    # so we assume they've implemented fetch/fetchrow_arrayref
+    my $row = $h->fetch or return;
+    return @$row;
+}
+*fetchrow = \&fetchrow_array; *fetchrow = \&fetchrow_array;
+
+sub fetchrow_hashref {
+    my $h         = shift;
+    my $row       = $h->fetch or return;
+    my $FetchCase = shift;
+    my $FetchHashKeyName = $FetchCase || $h->{'FetchHashKeyName'} || 'NAME';
+    my $FetchHashKeys    = $h->FETCH($FetchHashKeyName);
+    my %rowhash;
+    @rowhash{ @$FetchHashKeys } = @$row;
+    return \%rowhash;
+}
+sub dbih_setup_fbav {
+    my $h = shift;
+    return $h->{'_fbav'} || do {
+        $DBI::rows = $h->{'_rows'} = 0;
+        my $fields = $h->{'NUM_OF_FIELDS'}
+                  or DBI::croak("NUM_OF_FIELDS not set");
+        my @row = (undef) x $fields;
+        \@row;
+    };
+}
+sub _get_fbav {
+    my $h = shift;
+    my $av = $h->{'_fbav'} ||= dbih_setup_fbav($h);
+    $DBI::rows = ++$h->{'_rows'};
+    return $av;
+}
+sub _set_fbav {
+    my $h = shift;
+    my $fbav = $h->{'_fbav'};
+    if ($fbav) {
+	$DBI::rows = ++$h->{'_rows'};
+    }
+    else {
+	$fbav = $h->_get_fbav;
+    }
+    my $row = shift;
+    if (my $bc = $h->{'_bound_cols'}) {
+        for my $i (0..@$row-1) {
+            my $bound = $bc->[$i];
+            $fbav->[$i] = ($bound) ? ($$bound = $row->[$i]) : $row->[$i];
+        }
+    }
+    else {
+        @$fbav = @$row;
+    }
+    return $fbav;
+}
+sub bind_col {
+    my ($h, $col, $value_ref,$from_bind_columns) = @_;
+    $col-- unless $from_bind_columns; # XXX fix later
+    DBI::croak("bind_col($col,$value_ref) needs a reference to a scalar")
+	unless ref $value_ref eq 'SCALAR';
+    my $fbav = $h->_get_fbav;
+    $h->{'_bound_cols'}->[$col] = $value_ref;
+    return 1;
+}
+sub finish {
+    my $h = shift;
+    $h->{'_fbav'} = undef;
+    $h->{'Active'} = 0;
+    return 1;
+}
+sub rows {
+    my $h = shift;
+    my $rows = $h->{'_rows'};
+    return -1 unless defined $rows;
+    return $rows;
+}
+
+1;
+__END__
+
+=pod
+
+=head1 NAME
+
+DBI::PurePerl -- a DBI emulation using pure perl (no C/XS compilation required)
+
+=head1 SYNOPSIS
+
+ BEGIN { $ENV{DBI_PUREPERL} = 2 }
+ use DBI;
+
+=head1 DESCRIPTION
+
+This is a pure perl emulation of the DBI internals.  In almost all
+cases you will be better off using standard DBI since the portions
+of the standard version written in C make it *much* faster.
+
+However, if you are in a situation where it isn't possible to install
+a compiled version of standard DBI, and you're using pure-perl DBD
+drivers, then this module allows you to use most common features
+of DBI without needing any changes in your scripts.
+
+=head1 EXPERIMENTAL STATUS
+
+DBI::PurePerl is new so please treat it as experimental pending
+more extensive testing.  So far it has passed all tests with DBD::CSV,
+DBD::AnyData, DBD::XBase, DBD::Sprite, DBD::mysqlPP.  Please send
+bug reports to Jeff Zucker at <jeff@vpservices.com> with a cc to
+<dbi-dev@perl.org>.
+
+=head1 USAGE
+
+The usage is the same as for standard DBI with the exception
+that you need to set the enviornment variable DBI_PUREPERL if
+you want to use the PurePerl version.
+
+ DBI_PUREPERL == 0 (the default) Always use compiled DBI, die
+                   if it isn't properly compiled & installed
+
+ DBI_PUREPERL == 1 Use compiled DBI if it is properly compiled
+                   & installed, otherwise use PurePerl
+
+ DBI_PUREPERL == 2 Always use PurePerl
+
+You may set the enviornment variable in your shell (e.g. with
+set or setenv or export, etc) or else set it in your script like
+this:
+
+ BEGIN { $ENV{DBI_PUREPERL}=2 }
+
+before you C<use DBI;>.
+
+=head1 INSTALLATION
+
+In most situations simply install DBI (see the DBI pod for details).
+
+In the situation in which you can not install DBI itself, you
+may manually copy DBI.pm and PurePerl.pm into the appropriate
+directories.
+
+For example:
+
+ cp DBI.pm      /usr/jdoe/mylibs/.
+ cp PurePerl.pm /usr/jdoe/mylibs/DBI/.
+
+Then add this to the top of scripts:
+
+ BEGIN {
+   $ENV{DBI_PUREPERL} = 1;	# or =2
+   unshift @INC, '/usr/jdoe/mylibs';
+ }
+
+(Or should we perhaps patch Makefile.PL so that if DBI_PUREPERL
+is set to 2 prior to make, the normal compile process is skipped
+and the files are installed automatically?)
+
+=head1 DIFFERENCES BETWEEN DBI AND DBI::PurePerl
+
+=head2 Attributes
+
+Boolean attributes still return boolean values but the actual values
+used may be different, i.e., 0 or undef instead of an empty string.
+
+Some handle attributes are either not supported or have very limited
+functionality:
+
+  ActiveKids
+  InactiveDestroy
+  Kids
+  Taint
+  TaintIn
+  TaintOut
+
+(and probably others)
+
+=head2 Tracing
+
+Trace functionality is more limited and the code to handle tracing is
+only embeded into DBI:PurePerl if the DBI_TRACE environment variable
+is defined.  To enable total tracing you can set the DBI_TRACE
+environment variable as usual.  But to enable individual handle
+tracing using the trace() method you also need to set the DBI_TRACE
+environment variable, but set it to 0.
+
+=head2 Parameter Usage Checking
+
+The DBI does some basic parameter count checking on method calls.
+DBI::PurePerl doesn't.
+
+=head2 Speed
+
+DBI::PurePerl is slower. Although, with some drivers in some
+contexts this may not be very significant for you.
+
+By way of example... the test.pl script in the DBI source
+distribution has a simple benchmark that just does:
+
+    my $null_dbh = DBI->connect('dbi:NullP:','','');
+    my $i = 10_000;
+    $null_dbh->prepare('') while $i--;
+
+In other words just prepares a statement, creating and destroying
+a statement handle, over and over again.  Using the real DBI this
+runs at ~4550 handles per second whereas DBI::PurePerl manages
+~2800 per second on the same machine (not too bad really).
+
+=head2 May not fully support hash()
+
+If you want to use type 1 hash, i.e., C<hash($string,1)> with
+DBI::PurePerl, you'll need version 1.56 or higher of Math::BigInt
+(available on CPAN).
+
+=head2 Doesn't support preparse()
+
+The DBI->preparse() method isn't supported in DBI::PurePerl.
+
+=head2 Doesn't support DBD::Proxy
+
+There's a subtle problem somewhere I've not been able to identify.
+DBI::ProxyServer seem to work fine with DBI::PurePerl but DBD::Proxy
+does not work 100% (which is sad because that would be far more useful :)
+Try re-enabling t/80proxy.t for DBI::PurePerl to see if the problem
+that remains will affect you're usage.
+
+=head2 Others
+
+  can() - doesn't have any special behaviour
+
+Please let us know if you find any other differences between DBI
+and DBI::PurePerl.
+
+=head1 AUTHORS
+
+Tim Bunce and Jeff Zucker.
+
+Tim provided the direction and basis for the code.  The original
+idea for the module and most of the brute force porting from C to
+Perl was by Jeff. Tim then reworked some core parts to boost the
+performance and accuracy of the emulation. Thanks also to Randal
+Schwartz and John Tobey for patches.
+
+=head1 COPYRIGHT
+
+Copyright (c) 2002  Tim Bunce  Ireland.
+
+See COPYRIGHT section in DBI.pm for usage and distribution rights.
+
+=cut
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/Roadmap.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/Roadmap.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/Roadmap.pm	(revision 14139)
@@ -0,0 +1,394 @@
+=head1 NAME
+
+DBI::Roadmap - Planned Enhancements for the DBI
+
+Tim Bunce - 12th November 2004
+
+=head1 SYNOPSIS
+
+This document gives a high level overview of the future of the Perl
+DBI module.
+
+The DBI module is the standard database interface for Perl applications.
+It is used worldwide in countless applications, in every kind of
+business, and on platforms from clustered super-computers to PDAs.
+Database interface drivers are available for all common databases
+and many not-so-common ones.
+
+The planned enhancements cover testing, performance, high availability
+and load balancing, batch statements, Unicode, database portability,
+and more.
+
+Addressing these issues together, in coordinated way, will help
+ensure maximum future functionality with minimal disruptive
+(incompatible) upgrades.
+
+=head1 SCOPE
+
+Broad categories of changes are outlined here along with some
+rationale, but implementation details and minor planned enhancements
+are omitted.  More details can be found in:
+L<http://svn.perl.org/modules/dbi/trunk/ToDo>
+
+
+=head1 CHANGES AND ENHANCEMENTS
+
+These are grouped into categories and are not listed in any particular order.
+
+=head2 Performance
+
+The DBI has always treated performance as a priority. Some parts
+of the implementation, however, remain unoptimized, especially in
+relation to threads.
+
+* When the DBI is used with a Perl built with thread support enabled
+(such as for Apache mod_perl 2, and some common Linux distributions)
+it runs significantly slower. There are two reasons for this and
+both can be fixed but require non-trivial changes to both the DBI
+and drivers.
+
+* Connection pooling in a threaded application, such as mod_perl,
+is difficult because DBI handles cannot be passed between threads.
+An alternative mechanism for passing connections between threads
+has been defined, and an experimental connection pool module
+implemented using it, but development has stalled.
+
+* The majority of DBI handle creation code is implemented in Perl.
+Moving most of this to C will speed up handle creation significantly.
+
+* The popular fetchrow_hashref() method is many times slower than
+fetchrow_arrayref(). It has to get the names of the columns, then
+create and load a new hash each time. A $h->{FetchHashReuse} attribute
+would allow the same hash to be reused each time making fetchrow_hashref()
+about the same speed as fetchrow_arrayref().
+
+* Support for asynchronous (non-blocking) DBI method calls would
+enable applications to continue processing in parallel with database
+activity.  This is also relevant for GUI and other event-driven
+applications.  The DBI needs to define a standard interface for
+this so drivers can implement it in a portable way, where possible.
+
+These changes would significantly enhance the performance of the
+DBI and many applications which use the DBI.
+
+
+=head2 Testing
+
+The DBI has a test suite. Every driver has a test suite.  Each is
+limited in its scope.  The driver test suite is testing for behavior
+that the driver author I<thinks> the DBI specifies, but may be
+subtly incorrect.  These test suites are poorly maintained because
+the return on investment for a single driver is too low to provide
+sufficient incentive.
+
+A common test suite that can be reused by all the drivers is needed.
+It would:
+
+* Improve the quality of the DBI and drivers.
+
+* Ensure all drivers conform to the DBI specification.  Easing the
+porting of applications between databases, and the implementation
+of database independent modules layered over the DBI.
+
+* Improve the DBI specification by clarifying unclear issues in
+order to implement test cases.
+
+* Encourage expansion of the test suite as driver authors and others
+will be motivated by the greater benefits of their contributions.
+
+* Detect and record optional functionality that a driver has not
+yet implemented.
+
+* Improve the testing of DBI subclassing, DBI::PurePerl and the
+various "transparent" drivers, such as DBD::Proxy and DBD::Multiplex,
+by automatically running the test suite through them.
+
+These changes would improve the quality of all applications using
+the DBI.
+
+
+=head2 High Availability and Load Balancing
+
+* The DBD::Multiplex driver provides a framework to enable a wide
+range of dynamic functionality, including support for high-availability,
+failover, load-balancing, caching, and access to distributed data.
+It is currently being enhanced but development has stalled.
+
+* The DBD::Proxy module is complex and relatively inefficient because
+it's trying to be a complete proxy for most DBI method calls.  For
+many applications a simpler proxy architecture that operates with
+a single round-trip to the server would be simpler, faster, and more
+flexible.
+
+New proxy client and server classes are needed, which could be
+subclassed to support specific client to server transport mechanisms
+(such as HTTP and Spread::Queue).  Apart from the efficiency gains,
+this would also enable the use of a load-balanced pool of stateless
+servers for greater scalability and reliability.
+
+* The DBI currently offers no support for distributed transactions.
+The most useful elements of the standard XA distributed transaction
+interface standard could be included in the DBI specification.
+Drivers for databases which support distributed transactions could
+then be extended to support it.
+
+These changes would enable new kinds of DBI applications for critical
+environments.
+
+
+=head2 Unicode
+
+Use of Unicode with the DBI is growing rapidly. The DBI should do
+more to help drivers support Unicode and help applications work
+with drivers that don't yet support Unicode directly.
+
+* Define expected behavior for fetching data and binding parameters.
+
+* Provide interfaces to support Unicode issues for XS and pure Perl
+drivers and applications.
+
+* Provide functions for applications to help diagnose inconsistencies
+between byte string contents and setting of the SvUTF8 flag.
+
+These changes would smooth the transition to Unicode for many
+applications and drivers.
+
+
+=head2 Batch Statements
+
+Batch statements are a sequence of SQL statements, or a stored
+procedure containing a sequence of SQL statements, which can be
+executed as a whole.
+
+Currently the DBI has no standard interface for dealing with multiple
+results from batch statements.  After considerable discussion, an
+interface design has been agreed upon with driver authors, but has
+not yet been implemented.
+
+These changes would enable greater application portability between
+databases, and greater performance for databases that directly
+support batch statements.
+
+
+=head2 Introspection
+
+* The methods of the DBI API are installed dynamically when the DBI
+is loaded.  The data structure used to define the methods and their
+dispatch behavior should be made part of the DBI API. This would
+enable more flexible and correct behavior by modules subclassing
+the DBI and by dynamic drivers such as DBD::Proxy and DBD::Multiplex.
+
+* Handle attribute information should also be made available, for
+the same reasons.
+
+* Currently is it not possible to discover all the child statement
+handles that belong to a database handle (or all database handles
+that belong to a driver handle).  This makes certain tasks more
+difficult, especially some debugging scenarios.  A cache of weak
+references to child handles would solve the problem without creating
+reference loops.
+
+* It is often useful to know which handle attributes have been
+changed since the handle was created (e.g., in mod_perl where a
+handle needs to be reset or cloned). This will become more important
+as developers start exploring use of the newly added
+$h1->swap_inner_handle($h2) method.
+
+These changes would simplify and improve the stability of many
+advanced uses of the DBI.
+
+
+=head2 Extensibility
+
+The DBI can be extended in three main dimensions: subclassing the
+DBI, subclassing a driver, and callback hooks. Each has different
+pros and cons, each is applicable in different situations, and
+all need enhancing.
+
+* Subclassing the DBI is functional but not well defined and some
+key elements are incomplete, particularly the DbTypeSubclass mechanism
+(that automatically subclasses to a class tree according to the
+type of database being used).  It also needs more thorough testing.
+
+* Subclassing a driver is undocumented, poorly tested and very
+probably incomplete. However it's a powerful way to embed certain
+kinds of functionality 'below' applications while avoiding some of
+the side-effects of subclassing the DBI (especially in relation to
+error handling).
+
+* Callbacks are currently limited to error handling (the HandleError
+and HandleSetError attributes).  Providing callback hooks for more
+events, such as a row being fetched, would enable utility modules,
+for example, to modify the behavior of a handle independent of any
+subclassing in use.
+
+These changes would enable cleaner and more powerful integration
+between applications, layered modules, and the DBI.
+
+
+=head2 Debugability
+
+* Enabling DBI trace output at a high level of detail causes a large
+volume of output, much of it probably unrelated to the problem being
+investigated. Trace output should be controlled by the new named-topic
+mechanism instead of just the trace level.
+
+* Calls to XS functions (such as many DBI and driver methods) don't
+normally appear in the call stack.  Optionally enabling that would
+enable more useful diagnostics to be produced.
+
+* Integration with the Perl debugger would make it simpler to perform
+actions on a per-handle basis (such as breakpoint on execute,
+breakpoint on error).
+
+These changes would enable more rapid application development and
+fault finding.
+
+
+=head2 Database Portability
+
+* The DBI has not yet addressed the issue of portability among SQL
+dialects.  This is the main hurdle limiting database portability
+for DBI applications.
+
+The goal is I<not> to fully parse the SQL and rewrite it in a
+different dialect.  That's well beyond the scope of the DBI and
+should be left to layered modules.  A simple token rewriting mechanism
+for five comment styles, two quoting styles, four placeholder styles,
+plus the ODBC "{foo ...}" escape syntax, is sufficient to significantly
+raise the level of SQL portability.
+
+* Another problem area is date/time formatting.  Since version 1.41
+the DBI has defined a way to express that dates should be fetched
+in SQL standard date format (YYYY-MM-DD).  This is one example of
+the more general case where bind_col() needs to be called with
+particular attributes on all columns of a particular type.
+
+A mechanism is needed whereby an application can specify default
+bind_col() attributes to be applied automatically for each column
+type. With a single step, all DATE type columns, for example, can
+be set to be returned in the standard format.
+
+These changes would enable greater database portability for
+applications and greater functionality for layered modules.
+
+
+=head2 Intellectual Property
+
+* Clarify current intellectual property status, including a review
+  of past contributions to ensure the DBI is unemcumbered.
+
+* Establish a procedure for vetting future contributions for any
+  intellectual property issues.
+
+These changes are important for companies taking a formal approach
+to assessing their risks in using Open Source software.
+
+
+=head2 Other Enhancements
+
+* Reduce the work needed to create new database interface drivers.
+
+* Definition of an interface to support scrollable cursors.
+
+
+=head2 Parrot and Perl 6
+
+The current DBI implementation in C code is unlikely to run on Perl 6.
+Perl 6 will target the Parrot virtual machine and so the internal
+architecture will be radically different from Perl 5.
+
+One of the goals of the Parrot project is to be a platform for many
+dynamic languages (including Python, PHP, Ruby, etc) and to enable
+those languages to reuse each others modules. A database interface
+for Parrot is also a database interface for any and all languages
+that run on Parrot.
+
+The Perl DBI would make an excellent base for a Parrot database
+interface because it has more functionality, and is more mature and
+extensible, than the database interfaces of the other dynamic
+languages.
+
+I plan to better define the API between the DBI and the drivers and
+use that API as the primary API for the 'raw' Parrot database
+interface.  This project is known a Parrot DBDI (for "DataBase
+Driver Interface").  The announcement can be read in
+<http://groups.google.com/groups?selm=20040127225639.GF38394@dansat.data-plan.com>
+
+The bulk of the work will be translating the DBI C and Perl base
+class code into Parrot PIR, or a suitable language that generates
+PIR.  The project stalled, due to Parrot not having key functionality
+at the time.  That has been resolved but the project has not yet
+restarted.
+
+Each language targeting Parrot would implement their own small
+'thin' language-specific method dispatcher (a "Perl6 DBI", "Python
+DBI", "PHP DBI" etc) layered over the common Parrot DBDI interface
+and drivers.
+
+The major benefit of the DBDI project is that a much wider community
+of developers share the same database drivers. There would be more
+developers maintaining less code so the benefits of the Open Source
+model are magnified.
+
+
+=head1 PRIORITIES
+
+=head2 Transition Drivers
+
+The first priority is to make all the infrastructure changes that
+impact drivers and make an alpha release available for driver authors.
+
+As far as possible, the changes will be implemented in a way that
+enables driver authors use the same code base for DBI v1 and DBI v2.
+
+The main changes required by driver authors are:
+
+* Code changes for PERL_NO_GET_CONTEXT, plus removing PERL_POLLUTE
+and DBIS
+
+* Code changes in DBI/DBD interface (new way to create handles, new
+callbacks etc)
+
+* Common test suite infrastructure (driver-specific test base class)
+
+=head2 Transition Applications
+
+A small set of incompatible changes that may impact some applications
+will also be made in v2.0. See http://svn.perl.org/modules/dbi/trunk/ToDo
+
+=head2 Incremental Developments
+
+Once DBI v2.0 is available, the other enhancements can be implemented
+incrementally on the updated foundations. Priorities for those
+changes have not been set.
+
+=head2 DBI v1 
+
+DBI v1 will continue to be maintained on a separate branch for
+bug fixes and any enhancements that ease the transition to DBI v2.
+
+=head1 RESOURCES AND CONTRIBUTIONS
+
+See L<http://dbi.perl.org/contributing> for I<how you can help>.
+
+If your company has benefited from the DBI, please consider if
+it could make a donation to The Perl Foundation "DBI Development"
+fund at L<http://dbi.perl.org/donate> to secure future development.
+
+Alternatively, if your company would benefit from a specific new
+DBI feature, please consider sponsoring its development through my
+consulting company, Data Plan Services. Work is performed rapidly
+on a fixed-price payment-on-delivery basis. Contact me for details.
+
+Using such targeted financing allows you to contribute to DBI
+development and rapidly get something specific and directly valuable
+to you in return.
+
+My company also offers annual support contracts for the DBI, which
+provide another way to support the DBI and get something specific
+in return. Contact me for details.
+
+Thank you.
+
+=cut
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/SQL/Nano.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/SQL/Nano.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/SQL/Nano.pm	(revision 14139)
@@ -0,0 +1,691 @@
+#######################################################################
+#
+#  DBI::SQL::Nano - a very tiny SQL engine
+#
+#  Copyright (c) 2004 by Jeff Zucker < jzucker AT cpan.org >
+#
+#  All rights reserved.
+#
+#  You may freely distribute and/or modify this  module under the terms
+#  of either the GNU  General Public License (GPL) or the Artistic License,
+#  as specified in the Perl README file.
+#
+#  See the pod at the bottom of this file for help information
+#
+#######################################################################
+
+#######################
+package DBI::SQL::Nano;
+#######################
+use strict;
+use warnings;
+require DBI; # for looks_like_number()
+use vars qw( $VERSION $versions );
+BEGIN {
+    $VERSION = '0.03';
+    $versions->{nano_version} = $VERSION;
+    if ($ENV{DBI_SQL_NANO} || !eval { require "SQL/Statement.pm" }) {
+        @DBI::SQL::Nano::Statement::ISA = qw(DBI::SQL::Nano::Statement_);
+        @DBI::SQL::Nano::Table::ISA     = qw(DBI::SQL::Nano::Table_);
+    }
+    else {
+        @DBI::SQL::Nano::Statement::ISA = qw( SQL::Statement );
+        @DBI::SQL::Nano::Table::ISA     = qw( SQL::Eval::Table);
+        $versions->{statement_version}  = $SQL::Statement::VERSION;
+    }
+}
+
+###################################
+package DBI::SQL::Nano::Statement_;
+###################################
+
+sub new {
+    my($class,$sql) = @_;
+    my $self = {};
+    bless $self, $class;
+    return $self->prepare($sql);
+}
+
+#####################################################################
+# PREPARE
+#####################################################################
+sub prepare {
+    my($self,$sql) = @_;
+    $sql =~ s/\s+$//;
+    for ($sql) {
+        /^\s*CREATE\s+TABLE\s+(.*?)\s*\((.+)\)\s*$/is
+            &&do{
+                $self->{command}      = 'CREATE';
+                $self->{table_name}   = $1;
+                $self->{column_names} = parse_coldef_list($2) if $2;
+                die "Can't find columns\n" unless $self->{column_names};
+            };
+        /^\s*DROP\s+TABLE\s+(IF\s+EXISTS\s+)?(.*?)\s*$/is
+            &&do{
+                $self->{command}      = 'DROP';
+                $self->{table_name}   = $2;
+                $self->{ignore_missing_table} = 1 if $1;
+            };
+        /^\s*SELECT\s+(.*?)\s+FROM\s+(\S+)((.*))?/is
+            &&do{
+                $self->{command}      = 'SELECT';
+                $self->{column_names} = parse_comma_list($1) if $1;
+                die "Can't find columns\n" unless $self->{column_names};
+                $self->{table_name}   = $2;
+                if ( my $clauses = $4) {
+		    if ($clauses =~ /^(.*)\s+ORDER\s+BY\s+(.*)$/is) {
+                        $clauses = $1;
+                        $self->{order_clause} = $self->parse_order_clause($2);
+		    }
+                    $self->{where_clause}=$self->parse_where_clause($clauses)
+                        if $clauses;
+		}
+            };
+        /^\s*INSERT\s+INTO\s+(\S+)\s*(\((.*?)\))?\s*VALUES\s*\((.+)\)/is
+            &&do{
+                $self->{command}      = 'INSERT';
+                $self->{table_name}   = $1;
+                $self->{column_names} = parse_comma_list($2) if $2;
+                $self->{values}       = $self->parse_values_list($4) if $4;
+                die "Can't parse values\n" unless $self->{values};
+            };
+        /^\s*DELETE\s+FROM\s+(\S+)((.*))?/is
+            &&do{
+                $self->{command}      = 'DELETE';
+                $self->{table_name}   = $1;
+                $self->{where_clause} = $self->parse_where_clause($3) if $3;
+            };
+        /^\s*UPDATE\s+(\S+)\s+SET\s+(.+)(\s+WHERE\s+.+)/is
+            &&do{
+                $self->{command}      = 'UPDATE';
+                $self->{table_name}   = $1;
+                $self->parse_set_clause($2) if $2;
+                $self->{where_clause} = $self->parse_where_clause($3) if $3;
+            };
+    }
+    die "Couldn't parse\n"
+	unless $self->{command} and $self->{table_name};
+    return $self;
+}
+sub parse_order_clause {
+    my($self,$str) = @_;
+    my @clause = split /\s+/,$str;
+    return { $clause[0] => 'ASC' } if @clause == 1;
+    die "Bad ORDER BY clause '$str'\n" if @clause > 2;
+    $clause[1] ||= '';
+    return { $clause[0] => uc $clause[1] } if $clause[1] =~ /^ASC$/i
+                                           or $clause[1] =~ /^DESC$/i;
+    die "Bad ORDER BY clause '$clause[1]'\n";
+}
+sub parse_coldef_list  {                # check column definitions
+    my @col_defs;
+    for ( split',',shift ) {
+        my $col = clean_parse_str($_);
+        if ( $col =~ /^(\S+?)\s+.+/ ) { # doesn't check what it is
+            $col = $1;                  # just checks if it exists
+	}
+        else {
+ 	    die "No column definition for '$_'\n";
+	}
+        push @col_defs,$col;
+    }
+    return \@col_defs;
+}
+sub parse_comma_list  {[map{clean_parse_str($_)} split(',',shift)]}
+sub clean_parse_str { $_ = shift; s/\(//;s/\)//;s/^\s+//; s/\s+$//; $_; }
+sub parse_values_list {
+    my($self,$str) = @_;
+    [map{$self->parse_value(clean_parse_str($_))}split(',',$str)]
+}
+sub parse_set_clause {
+    my $self = shift;
+    my @cols = split /,/, shift;
+    my $set_clause;
+    for my $col(@cols) {
+        my($col_name,$value)= $col =~ /^\s*(.+?)\s*=\s*(.+?)\s*$/s;
+        push @{$self->{column_names}}, $col_name;
+        push @{$self->{values}}, $self->parse_value($value);
+    }
+    die "Can't parse set clause\n"
+        unless $self->{column_names}
+           and $self->{values};
+}
+sub parse_value {
+    my($self,$str) = @_;
+    return undef unless defined $str;
+    $str =~ s/\s+$//;
+    $str =~ s/^\s+//;
+    if ($str =~ /^\?$/) {
+        push @{$self->{params}},'?';
+        return { value=>'?'  ,type=> 'placeholder' };
+    }
+    return { value=>undef,type=> 'NULL'   } if $str =~ /^NULL$/i;
+    return { value=>$1   ,type=> 'string' } if $str =~ /^'(.+)'$/s;
+    return { value=>$str ,type=> 'number' } if DBI::looks_like_number($str);
+    return { value=>$str ,type=> 'column' };
+}
+sub parse_where_clause {
+    my($self,$str) = @_;
+    $str =~ s/\s+$//;
+    if ($str =~ /^\s*WHERE\s+(.*)/i) {
+        $str = $1;
+    }
+    else {
+        die "Couldn't find WHERE clause in '$str'\n";
+    }
+    my($neg) = $str =~ s/^\s*(NOT)\s+//is;
+    my $opexp = '=|<>|<=|>=|<|>|LIKE|CLIKE|IS';
+    my($val1,$op,$val2) = $str =~ /^(.+?)\s*($opexp)\s*(.+)\s*$/iso;
+    die "Couldn't parse WHERE expression '$str'\n"
+       unless defined $val1 and defined $op and defined $val2;
+    return {
+        arg1 => $self->parse_value($val1),
+        arg2 => $self->parse_value($val2),
+        op   => $op,
+        neg  => $neg,
+    }
+}
+
+#####################################################################
+# EXECUTE
+#####################################################################
+sub execute {
+    my($self, $data, $params) = @_;
+    my $num_placeholders = $self->params;
+    my $num_params       = scalar @$params || 0;
+    die "Number of params '$num_params' does not match "
+      . "number of placeholders '$num_placeholders'\n"
+      unless $num_placeholders == $num_params;
+    if (scalar @$params) {
+        for my $i(0..$#{$self->{values}}) {
+            if ($self->{values}->[$i]->{type} eq 'placeholder') {
+                $self->{values}->[$i]->{value} = shift @$params;
+            }
+        }
+        if ($self->{where_clause}) {
+            if ($self->{where_clause}->{arg1}->{type} eq 'placeholder') {
+                $self->{where_clause}->{arg1}->{value} = shift @$params;
+            }
+            if ($self->{where_clause}->{arg2}->{type} eq 'placeholder') {
+                $self->{where_clause}->{arg2}->{value} = shift @$params;
+            }
+        }
+    }
+    my $command = $self->{command};
+    ( $self->{'NUM_OF_ROWS'},
+      $self->{'NUM_OF_FIELDS'},
+      $self->{'data'},
+    ) = $self->$command($data, $params);
+    $self->{NAME} ||= $self->{column_names};
+    $self->{'NUM_OF_ROWS'} || '0E0';
+}
+sub DROP ($$$) {
+    my($self, $data, $params) = @_;
+    my $table = $self->open_tables($data, 0, 0);
+    $table->drop($data);
+    (-1, 0);
+}
+sub CREATE ($$$) {
+    my($self, $data, $params) = @_;
+    my $table = $self->open_tables($data, 1, 1);
+    $table->push_names($data, $self->{column_names});
+    (0, 0);
+}
+sub INSERT ($$$) {
+    my($self, $data, $params) = @_;
+    my $table = $self->open_tables($data, 0, 1);
+    $self->verify_columns($table);
+    $table->seek($data, 0, 2);
+    my($array) = [];
+    my($val, $col, $i);
+    $self->{column_names}=$table->{col_names} unless $self->{column_names};
+    my $cNum = scalar(@{$self->{column_names}}) if $self->{column_names};
+    my $param_num = 0;
+    if ($cNum) {
+        for ($i = 0;  $i < $cNum;  $i++) {
+            $col = $self->{column_names}->[$i];
+            $array->[$self->column_nums($table,$col)] = $self->row_values($i);
+        }
+    } else {
+        die "Bad col names in INSERT";
+    }
+    $table->push_row($data, $array);
+    (1, 0);
+}
+sub DELETE ($$$) {
+    my($self, $data, $params) = @_;
+    my $table = $self->open_tables($data, 0, 1);
+    $self->verify_columns($table);
+    my($affected) = 0;
+    my(@rows, $array);
+    if ( $table->can('delete_one_row') ) {
+        while (my $array = $table->fetch_row($data)) {
+            if ($self->eval_where($table,$array)) {
+                ++$affected;
+                $array = $self->{fetched_value} if $self->{fetched_from_key};
+                $table->delete_one_row($data,$array);
+                return ($affected, 0) if $self->{fetched_from_key};
+            }
+        }
+        return ($affected, 0);
+    }
+    while ($array = $table->fetch_row($data)) {
+        if ($self->eval_where($table,$array)) {
+            ++$affected;
+        } else {
+            push(@rows, $array);
+        }
+    }
+    $table->seek($data, 0, 0);
+    foreach $array (@rows) {
+        $table->push_row($data, $array);
+    }
+    $table->truncate($data);
+    return ($affected, 0);
+}
+sub SELECT ($$$) {
+    my($self, $data, $params) = @_;
+    my $table = $self->open_tables($data, 0, 0);
+    $self->verify_columns($table);
+    my $tname = $self->{table_name};
+    my($affected) = 0;
+    my(@rows, $array, $val, $col, $i);
+    while ($array = $table->fetch_row($data)) {
+        if ($self->eval_where($table,$array)) {
+            $array = $self->{fetched_value} if $self->{fetched_from_key};
+            my $col_nums = $self->column_nums($table);
+            my %cols   = reverse %{ $col_nums };
+            my $rowhash;
+            for (sort keys %cols) {
+                $rowhash->{$cols{$_}} = $array->[$_];
+            }
+            my @newarray;
+            for ($i = 0;  $i < @{$self->{column_names}};  $i++) {
+               $col = $self->{column_names}->[$i];
+               push @newarray,$rowhash->{$col};
+            }
+            push(@rows, \@newarray);
+            return (scalar(@rows),scalar @{$self->{column_names}},\@rows)
+ 	        if $self->{fetched_from_key};
+        }
+    }
+    if ( $self->{order_clause} ) {
+        my( $sort_col, $desc ) = each %{$self->{order_clause}};
+        undef $desc unless $desc eq 'DESC';
+        my @sortCols = ( $self->column_nums($table,$sort_col,1) );
+        my($c, $d, $colNum);
+        my $sortFunc = sub {
+            my $result;
+            $i = 0;
+            do {
+                $colNum = $sortCols[$i++];
+                # $desc = $sortCols[$i++];
+                $c = $a->[$colNum];
+                $d = $b->[$colNum];
+                if (!defined($c)) {
+                    $result = defined $d ? -1 : 0;
+                } elsif (!defined($d)) {
+                    $result = 1;
+	        } elsif ( DBI::looks_like_number($c) && DBI::looks_like_number($d) ) {
+                    $result = ($c <=> $d);
+                } else {
+  		    if ($self->{"case_fold"}) {
+                        $result = lc $c cmp lc $d || $c cmp $d;
+		    }
+                    else {
+                        $result = $c cmp $d;
+		    }
+                }
+                if ($desc) {
+                    $result = -$result;
+                }
+            } while (!$result  &&  $i < @sortCols);
+            $result;
+        };
+        @rows = (sort $sortFunc @rows);
+    }
+    (scalar(@rows), scalar @{$self->{column_names}}, \@rows);
+}
+sub UPDATE ($$$) {
+    my($self, $data, $params) = @_;
+    my $table = $self->open_tables($data, 0, 1);
+    $self->verify_columns($table);
+    return undef unless $table;
+    my($affected) = 0;
+    my(@rows, $array, $f_array, $val, $col, $i);
+    while ($array = $table->fetch_row($data)) {
+        if ($self->eval_where($table,$array)) {
+            $array = $self->{fetched_value} if $self->{fetched_from_key}
+                                             and $table->can('update_one_row');
+            my $col_nums = $self->column_nums($table);
+            my %cols   = reverse %{ $col_nums };
+            my $rowhash;
+            for (sort keys %cols) {
+                $rowhash->{$cols{$_}} = $array->[$_];
+            }
+            for ($i = 0;  $i < @{$self->{column_names}};  $i++) {
+               $col = $self->{column_names}->[$i];
+               $array->[$self->column_nums($table,$col)]=$self->row_values($i);
+            }
+            $affected++;
+            if ($self->{fetched_from_key}){
+                $table->update_one_row($data,$array);
+                return ($affected, 0);
+	    }
+            push(@rows, $array);
+	}
+        else {
+            push(@rows, $array);
+        }
+    }
+    $table->seek($data, 0, 0);
+    foreach my $array (@rows) {
+        $table->push_row($data, $array);
+    }
+    $table->truncate($data);
+    ($affected, 0);
+}
+sub verify_columns {
+   my($self,$table) = @_;
+   my @cols = @{$self->{column_names}};
+   if ($self->{where_clause}) {
+      if (my $col = $self->{where_clause}->{arg1}) {
+          push @cols, $col->{value} if $col->{type} eq 'column';
+      }
+      if (my $col = $self->{where_clause}->{arg2}) {
+          push @cols, $col->{value} if $col->{type} eq 'column';
+      }
+   }
+   for (@cols) {
+       $self->column_nums($table,$_);
+   }
+}
+sub column_nums {
+    my($self,$table,$stmt_col_name,$find_in_stmt)=@_;
+    my %dbd_nums = %{ $table->{col_nums} };
+    my @dbd_cols = @{ $table->{col_names} };
+    my %stmt_nums;
+    if ($stmt_col_name and !$find_in_stmt) {
+        while(my($k,$v)=each %dbd_nums) {
+            return $v if uc $k eq uc $stmt_col_name;
+        }
+        die "No such column '$stmt_col_name'\n";
+    }
+    if ($stmt_col_name and $find_in_stmt) {
+        for my $i(0..@{$self->{column_names}}) {
+            return $i if uc $stmt_col_name eq uc $self->{column_names}->[$i];
+        }
+        die "No such column '$stmt_col_name'\n";
+    }
+    for my $i(0 .. $#dbd_cols) {
+        for my $stmt_col(@{$self->{column_names}}) {
+            $stmt_nums{$stmt_col} = $i if uc $dbd_cols[$i] eq uc $stmt_col;
+        }
+    }
+    return \%stmt_nums;
+}
+sub eval_where {
+    my $self   = shift;
+    my $table  = shift;
+    my $rowary = shift;
+    my $where = $self->{"where_clause"} || return 1;
+    my $col_nums = $table->{"col_nums"} ;
+    my %cols   = reverse %{ $col_nums };
+    my $rowhash;
+    for (sort keys %cols) {
+        $rowhash->{uc $cols{$_}} = $rowary->[$_];
+    }
+    return $self->process_predicate($where,$table,$rowhash);
+}
+sub process_predicate {
+    my($self,$pred,$table,$rowhash) = @_;
+    my $val1 = $pred->{arg1};
+    if ($val1->{type} eq 'column') {
+        $val1 = $rowhash->{ uc $val1->{value}};
+    }
+    else {
+        $val1 = $val1->{value};
+    }
+    my $val2 = $pred->{arg2};
+    if ($val2->{type}eq 'column') {
+        $val2 = $rowhash->{uc $val2->{value}};
+    }
+    else {
+        $val2 = $val2->{value};
+    }
+    my $op   = $pred->{op};
+    my $neg  = $pred->{neg};
+    my $match;
+    if ( $op eq '=' and !$neg and $table->can('fetch_one_row')
+       ) {
+        my $key_col = $table->fetch_one_row(1,1);
+        if ($pred->{arg1}->{value} =~ /^$key_col$/i) {
+            $self->{fetched_from_key}=1;
+            $self->{fetched_value} = $table->fetch_one_row(
+                0,$pred->{arg2}->{value}
+            );
+            return 1;
+	}
+    }
+    $match = $self->is_matched($val1,$op,$val2) || 0;
+    if ($neg) { $match = $match ? 0 : 1; }
+    return $match;
+}
+sub is_matched {
+    my($self,$val1,$op,$val2)=@_;
+    if ($op eq 'IS') {
+        return 1 if (!defined $val1 or $val1 eq '');
+        return 0;
+    }
+    $val1 = '' unless defined $val1;
+    $val2 = '' unless defined $val2;
+    if ($op =~ /LIKE|CLIKE/i) {
+        $val2 = quotemeta($val2);
+        $val2 =~ s/\\%/.*/g;
+        $val2 =~ s/_/./g;
+    }
+    if ($op eq 'LIKE' )  { return $val1 =~ /^$val2$/s;  }
+    if ($op eq 'CLIKE' ) { return $val1 =~ /^$val2$/si; }
+    if ( DBI::looks_like_number($val1) && DBI::looks_like_number($val2) ) {
+        if ($op eq '<'  ) { return $val1 <  $val2; }
+        if ($op eq '>'  ) { return $val1 >  $val2; }
+        if ($op eq '='  ) { return $val1 == $val2; }
+        if ($op eq '<>' ) { return $val1 != $val2; }
+        if ($op eq '<=' ) { return $val1 <= $val2; }
+        if ($op eq '>=' ) { return $val1 >= $val2; }
+    }
+    else {
+        if ($op eq '<'  ) { return $val1 lt $val2; }
+        if ($op eq '>'  ) { return $val1 gt $val2; }
+        if ($op eq '='  ) { return $val1 eq $val2; }
+        if ($op eq '<>' ) { return $val1 ne $val2; }
+        if ($op eq '<=' ) { return $val1 ge $val2; }
+        if ($op eq '>=' ) { return $val1 le $val2; }
+    }
+}
+sub params {
+    my $self = shift;
+    my $val_num = shift;
+    if (!$self->{"params"}) { return 0; }
+    if (defined $val_num) {
+        return $self->{"params"}->[$val_num];
+    }
+    if (wantarray) {
+        return @{$self->{"params"}};
+    }
+    else {
+        return scalar @{ $self->{"params"} };
+    }
+
+}
+sub open_tables {
+    my($self, $data, $createMode, $lockMode) = @_;
+    my $table_name = $self->{table_name};
+    my $table;
+    eval{$table = $self->open_table($data,$table_name,$createMode,$lockMode)};
+    die $@ if $@;
+    die "Couldn't open table '$table_name'" unless $table;
+    if (!$self->{column_names} or $self->{column_names}->[0] eq '*') {
+        $self->{column_names} = $table->{col_names};
+    }
+    return $table;
+}
+sub row_values {
+    my $self = shift;
+    my $val_num = shift;
+    if (!$self->{"values"}) { return 0; }
+    if (defined $val_num) {
+        return $self->{"values"}->[$val_num]->{value};
+    }
+    if (wantarray) {
+        return map{$_->{"value"} } @{$self->{"values"}};
+    }
+    else {
+        return scalar @{ $self->{"values"} };
+    }
+}
+
+###############################
+package DBI::SQL::Nano::Table_;
+###############################
+sub new ($$) {
+    my($proto, $attr) = @_;
+    my($self) = { %$attr };
+    bless($self, (ref($proto) || $proto));
+    $self;
+}
+
+1;
+__END__
+
+=pod
+
+=head1 NAME
+
+DBI::SQL::Nano - a very tiny SQL engine
+
+=head1 SYNOPSIS
+
+ BEGIN { $ENV{DBI_SQL_NANO}=1 } # forces use of Nano rather than SQL::Statement
+ use DBI::SQL::Nano;
+ use Data::Dumper;
+ my $stmt = DBI::SQL::Nano::Statement->new(
+     "SELECT bar,baz FROM foo WHERE qux = 1"
+ ) or die "Couldn't parse";
+ print Dumper $stmt;
+
+=head1 DESCRIPTION
+
+DBI::SQL::Nano is meant as a *very* minimal SQL engine for use in situations where SQL::Statement is not available.  In most situations you are better off installing SQL::Statement although DBI::SQL::Nano may be faster for some very simple tasks.
+
+DBI::SQL::Nano, like SQL::Statement is primarily intended to provide a SQL engine for use with some pure perl DBDs including DBD::DBM, DBD::CSV, DBD::AnyData, and DBD::Excel.  It isn't of much use in and of itself.  You can dump out the structure of a parsed SQL statement, but that's about it.
+
+=head1 USAGE
+
+=head2 Setting the DBI_SQL_NANO flag
+
+By default, when a DBD uses DBI::SQL::Nano, the module will look to see if SQL::Statement is installed.  If it is, SQL::Statement objects are used.  If SQL::Statement is not available, DBI::SQL::Nano objects are used.
+
+In some cases, you may wish to use DBI::SQL::Nano objects even if SQL::Statement is available.  To force usage of DBI::SQL::Nano objects regardless of the availability of SQL::Statement, set the environment variable DBI_SQL_NANO to 1.
+
+You can set the environment variable in your shell prior to running your script (with SET or EXPORT or whatever), or else you can set it in your script by putting this at the top of the script:
+
+ BEGIN { $ENV{DBI_SQL_NANO} = 1 }
+
+=head2 Supported SQL syntax
+
+ Here's a pseudo-BNF.  Square brackets [] indicate optional items;
+ Angle brackets <> indicate items defined elsewhere in the BNF.
+
+  statement ::=
+      DROP TABLE [IF EXISTS] <table_name>
+    | CREATE TABLE <table_name> <col_def_list>
+    | INSERT INTO <table_name> [<insert_col_list>] VALUES <val_list>
+    | DELETE FROM <table_name> [<where_clause>]
+    | UPDATE <table_name> SET <set_clause> <where_clause>
+    | SELECT <select_col_list> FROM <table_name> [<where_clause>]
+                                                 [<order_clause>]
+
+  the optional IF EXISTS clause ::=
+    * similar to MySQL - prevents errors when trying to drop
+      a table that doesn't exist
+
+  identifiers ::=
+    * table and column names should be valid SQL identifiers
+    * especially avoid using spaces and commas in identifiers
+    * note: there is no error checking for invalid names, some
+      will be accepted, others will cause parse failures
+
+  table_name ::=
+    * only one table (no multiple table operations)
+    * see identifier for valid table names
+
+  col_def_list ::=
+    * a parens delimited, comma-separated list of column names
+    * see identifier for valid column names
+    * column types and column constraints may be included but are ignored
+      e.g. these are all the same:
+        (id,phrase)
+        (id INT, phrase VARCHAR(40))
+        (id INT PRIMARY KEY, phrase VARCHAR(40) NOT NULL)
+    * you are *strongly* advised to put in column types even though
+      they are ignored ... it increases portability
+
+  insert_col_list ::=
+    * a parens delimited, comma-separated list of column names
+    * as in standard SQL, this is optional
+
+  select_col_list ::=
+    * a comma-separated list of column names
+    * or an asterisk denoting all columns
+
+  val_list ::=
+    * a parens delimited, comma-separated list of values which can be:
+       * placeholders (an unquoted question mark)
+       * numbers (unquoted numbers)
+       * column names (unquoted strings)
+       * nulls (unquoted word NULL)
+       * strings (delimited with single quote marks);
+       * note: leading and trailing percent mark (%) and underscore (_)
+         can be used as wildcards in quoted strings for use with
+         the LIKE and CLIKE operators
+       * note: escaped single quote marks within strings are not
+         supported, neither are embedded commas, use placeholders instead
+
+  set_clause ::=
+    * a comma-separated list of column = value pairs
+    * see val_list for acceptable value formats
+
+  where_clause ::=
+    * a single "column/value <op> column/value" predicate, optionally
+      preceded by "NOT"
+    * note: multiple predicates combined with ORs or ANDs are not supported
+    * see val_list for acceptable value formats
+    * op may be one of:
+         < > >= <= = <> LIKE CLIKE IS
+    * CLIKE is a case insensitive LIKE
+
+  order_clause ::= column_name [ASC|DESC]
+    * a single column optional ORDER BY clause is supported
+    * as in standard SQL, if neither ASC (ascending) nor
+      DESC (descending) is specified, ASC becomes the default
+
+=head1 ACKNOWLEDGEMENTS
+
+Tim Bunce provided the original idea for this module, helped me out of the tangled trap of namespace, and provided help and advice all along the way.  Although I wrote it from the ground up, it is based on Jochen Weidmann's orignal design of SQL::Statement, so much of the credit for the API goes to him.
+
+=head1 AUTHOR AND COPYRIGHT
+
+This module is written and maintained by
+
+Jeff Zucker < jzucker AT cpan.org >
+
+Copyright (C) 2004 by Jeff Zucker, all rights reserved.
+
+You may freely distribute and/or modify this module under the terms of either the GNU General Public License (GPL) or the Artistic License, as specified in
+the Perl README file.
+
+=cut
+
+
+
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/W32ODBC.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/W32ODBC.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/DBI/W32ODBC.pm	(revision 14139)
@@ -0,0 +1,180 @@
+package
+  DBI;	# hide this non-DBI package from simple indexers
+
+# $Id$
+#
+# Copyright (c) 1997,1999 Tim Bunce
+# With many thanks to Patrick Hollins for polishing.
+#
+# You may distribute under the terms of either the GNU General Public
+# License or the Artistic License, as specified in the Perl README file.
+
+=head1 NAME
+
+DBI::W32ODBC - An experimental DBI emulation layer for Win32::ODBC
+
+=head1 SYNOPSIS
+
+  use DBI::W32ODBC;
+
+  # apart from the line above everything is just the same as with
+  # the real DBI when using a basic driver with few features.
+
+=head1 DESCRIPTION
+
+This is an experimental pure perl DBI emulation layer for Win32::ODBC
+
+If you can improve this code I'd be interested in hearing about it. If
+you are having trouble using it please respect the fact that it's very
+experimental. Ideally fix it yourself and send me the details.
+
+=head2 Some Things Not Yet Implemented
+
+	Most attributes including PrintError & RaiseError.
+	type_info and table_info
+
+Volunteers welcome!
+
+=cut
+
+${'DBI::VERSION'}	# hide version from PAUSE indexer
+   = "0.01";
+
+my $Revision = substr(q$Revision$, 10);
+
+sub DBI::W32ODBC::import { }	# must trick here since we're called DBI/W32ODBC.pm
+
+
+use Carp;
+
+use Win32::ODBC;
+
+@ISA = qw(Win32::ODBC);
+
+use strict;
+
+$DBI::dbi_debug = $ENV{PERL_DBI_DEBUG} || 0;
+carp "Loaded (W32ODBC) DBI.pm ${'DBI::VERSION'} (debug $DBI::dbi_debug)"
+	if $DBI::dbi_debug;
+
+
+
+sub connect {
+    my ($class, $dbname, $dbuser, $dbpasswd, $module, $attr) = @_;
+    $dbname .= ";UID=$dbuser"   if $dbuser;
+    $dbname .= ";PWD=$dbpasswd" if $dbpasswd;
+    my $h = new Win32::ODBC $dbname;
+    warn "Error connecting to $dbname: ".Win32::ODBC::Error()."\n" unless $h;
+    bless $h, $class if $h;	# rebless into our class
+    $h;
+}
+
+
+sub quote {
+    my ($h, $string) = @_;
+    return "NULL" if !defined $string;
+    $string =~ s/'/''/g;	# standard
+    # This hack seems to be required for Access but probably breaks for
+	# other databases when using \r and \n. It would be better if we could
+	# use ODBC options to detect that we're actually using Access.
+    $string =~ s/\r/' & chr\$(13) & '/g;
+    $string =~ s/\n/' & chr\$(10) & '/g;
+    "'$string'";
+}
+
+sub do {
+    my($h, $statement, $attribs, @params) = @_;
+    Carp::carp "\$h->do() attribs unused" if $attribs;
+    my $new_h = $h->prepare($statement) or return undef;    ##
+    pop @{ $h->{'___sths'} };                               ## certian death assured
+    $new_h->execute(@params) or return undef;               ##
+    my $rows = $new_h->rows;                                ##
+    $new_h->finish;                                         ## bang bang
+    ($rows == 0) ? "0E0" : $rows;
+}
+
+# ---
+
+sub prepare {
+    my ($h, $sql) = @_;
+	## opens a new connection with every prepare to allow
+	## multiple, concurrent queries
+	my $new_h = new Win32::ODBC $h->{DSN};	##
+	return undef if not $new_h;             ## bail if no connection
+	bless $new_h;					        ## shouldn't be sub-classed...
+    $new_h->{'__prepare'} = $sql;			##
+	$new_h->{NAME} = [];				    ##
+	$new_h->{NUM_OF_FIELDS} = -1;			##
+	push @{ $h->{'___sths'} } ,$new_h;		## save sth in parent for mass destruction
+    return $new_h;					        ##
+}
+
+sub execute {
+    my ($h) = @_;
+    my $rc = $h->Sql($h->{'__prepare'});
+    return undef if $rc;
+    my @fields = $h->FieldNames;
+    $h->{NAME} = \@fields;
+    $h->{NUM_OF_FIELDS} = scalar @fields;
+    $h;	# return dbh as pseudo sth
+}
+
+
+sub fetchrow_hashref {					## provide DBI compatibility
+	my $h = shift;
+	my $NAME = shift || "NAME";
+	my $row = $h->fetchrow_arrayref or return undef;
+	my %hash;
+	@hash{ @{ $h->{$NAME} } } = @$row;
+	return \%hash;
+}
+
+sub fetchrow {
+    my $h = shift;
+    return unless $h->FetchRow();
+    my $fields_r = $h->{NAME};
+    return $h->Data(@$fields_r);
+}
+sub fetch {
+    my @row = shift->fetchrow;
+    return undef unless @row;
+    return \@row;
+}
+*fetchrow_arrayref = \&fetch;			## provide DBI compatibility
+*fetchrow_array    = \&fetchrow;		## provide DBI compatibility
+
+sub rows {
+    shift->RowCount;
+}
+
+sub finish {
+    shift->Close;						## uncommented this line
+}
+
+# ---
+
+sub commit {
+	shift->Transact(ODBC::SQL_COMMIT);
+}
+sub rollback {
+	shift->Transact(ODBC::SQL_ROLLBACK);
+}
+
+sub disconnect {
+	my ($h) = shift; 					## this will kill all the statement handles
+	foreach (@{$h->{'___sths'}}) {		## created for a specific connection
+		$_->Close if $_->{DSN};			##
+	}							        ##
+    $h->Close;  						##
+}
+
+sub err {
+    (shift->Error)[0];
+}
+sub errstr {
+    scalar( shift->Error );
+}
+
+# ---
+
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/AuthenticateUser.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/AuthenticateUser.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/AuthenticateUser.pm	(revision 14139)
@@ -0,0 +1,74 @@
+package Win32::AuthenticateUser;
+
+use strict;
+use Carp;
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $AUTOLOAD);
+
+require Exporter;
+require DynaLoader;
+require AutoLoader;
+
+@ISA = qw(Exporter DynaLoader);
+# Items to export into callers namespace by default. Note: do not export
+# names by default without a very good reason. Use EXPORT_OK instead.
+# Do not simply export all your public functions/methods/constants.
+@EXPORT = qw(AuthenticateUser);
+
+$VERSION = '0.02';
+
+sub AUTOLOAD {
+    # This AUTOLOAD is used to 'autoload' constants from the constant()
+    # XS function.  If a constant is not found then control is passed
+    # to the AUTOLOAD in AutoLoader.
+
+    my $constname;
+    ($constname = $AUTOLOAD) =~ s/.*:://;
+    croak "& not defined" if $constname eq 'constant';
+    my $val = constant($constname, @_ ? $_[0] : 0);
+    if ($! != 0) {
+	if ($! =~ /Invalid/) {
+	    $AutoLoader::AUTOLOAD = $AUTOLOAD;
+	    goto &AutoLoader::AUTOLOAD;
+	}
+	else {
+		croak "Your vendor has not defined Win32::AuthenticateUser macro $constname";
+	}
+    }
+    no strict 'refs';
+    *$AUTOLOAD = sub () { $val };
+    goto &$AUTOLOAD;
+}
+
+bootstrap Win32::AuthenticateUser $VERSION;
+
+1;
+__END__
+
+=head1 NAME
+
+Win32::AuthenticateUser - Win32 User authentication for domains
+
+=head1 SUPPORTED PLATFORMS
+
+none
+
+=head1 SYNOPSIS
+
+  use Win32::AuthenticateUser;
+  
+  AuthenticateUser("domain", "user", "passwd");
+
+=head1 DESCRIPTION
+
+Performs Win32 user authentication using domains
+
+=head1 STATUS
+
+This module is incomplete and is not being actively developed.
+No documentation exists (yet), and there may be bugs in the code.
+
+=head1 AUTHOR
+
+Murray Nesbitt, ActiveState Tool Corp.
+
+=cut
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/ChangeNotify.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/ChangeNotify.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/ChangeNotify.pm	(revision 14139)
@@ -0,0 +1,187 @@
+#---------------------------------------------------------------------
+package Win32::ChangeNotify;
+#
+# Copyright 1998 Christopher J. Madsen
+#
+# Created: 3 Feb 1998 from the ActiveWare version
+#   (c) 1995 Microsoft Corporation. All rights reserved.
+#       Developed by ActiveWare Internet Corp., http://www.ActiveWare.com
+#
+#   Other modifications (c) 1997 by Gurusamy Sarathy <gsar@activestate.com>
+#
+# Author: Christopher J. Madsen <chris_madsen@geocities.com>
+# Version: 1.02 (13-Jun-1999)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the same terms as Perl itself.
+#
+# 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 either the
+# GNU General Public License or the Artistic License for more details.
+#
+# Monitor directory for changes
+#---------------------------------------------------------------------
+
+$VERSION = '1.02';
+
+use Carp;
+use Win32::IPC 1.00 '/./';      # Import everything
+require Exporter;
+require DynaLoader;
+
+@ISA = qw(Exporter DynaLoader Win32::IPC);
+# Items to export into callers namespace by default. Note: do not export
+# names by default without a very good reason. Use EXPORT_OK instead.
+# Do not simply export all your public functions/methods/constants.
+@EXPORT = qw(
+	FILE_NOTIFY_CHANGE_ATTRIBUTES
+	FILE_NOTIFY_CHANGE_DIR_NAME
+	FILE_NOTIFY_CHANGE_FILE_NAME
+	FILE_NOTIFY_CHANGE_LAST_WRITE
+	FILE_NOTIFY_CHANGE_SECURITY
+	FILE_NOTIFY_CHANGE_SIZE
+	INFINITE
+);
+@EXPORT_OK = qw(
+  wait_all wait_any
+);
+
+sub AUTOLOAD {
+    # This AUTOLOAD is used to 'autoload' constants from the constant()
+    # XS function.
+
+    my $constname;
+    ($constname = $AUTOLOAD) =~ s/.*:://;
+    if ($constname =~ /^(?:FILE_NOTIFY_CHANGE_|INFINITE)/) {
+	local $! = 0;
+        my $val = constant($constname);
+        croak("$constname is not defined by Win32::ChangeNotify") if $! != 0;
+        eval "sub $AUTOLOAD { $val }";
+        goto &$AUTOLOAD;
+    }
+} # end AUTOLOAD
+
+bootstrap Win32::ChangeNotify;
+
+sub new {
+    my ($class,$path,$subtree,$filter) = @_;
+
+    if ($filter =~ /\A[\s|A-Z_]+\Z/i) {
+        $filter = 0;
+        foreach (split(/[\s|]+/, $_[3])) {
+            $filter |= constant("FILE_NOTIFY_CHANGE_" . uc $_);
+            carp "Invalid filter $_" if $!;
+        }
+    }
+    _new($class,$path,$subtree,$filter);
+} # end new
+
+sub Close { &close }
+
+sub FindFirst { $_[0] = Win32::ChangeNotify->_new(@_[1..3]); }
+
+sub FindNext { &reset }
+
+1;
+__END__
+
+=head1 NAME
+
+Win32::ChangeNotify - Monitor events related to files and directories
+
+=head1 SYNOPSIS
+
+	require Win32::ChangeNotify;
+
+	$notify = Win32::ChangeNotify->new($Path,$WatchSubTree,$Events);
+	$notify->wait or warn "Something failed: $!\n";
+	# There has been a change.
+
+=head1 DESCRIPTION
+
+This module allows the user to use a Win32 change notification event
+object from Perl.  This allows the Perl program to monitor events
+relating to files and directory trees.
+
+The C<wait> method and C<wait_all> & C<wait_any> functions are
+inherited from the L<"Win32::IPC"> module.
+
+=head2 Methods
+
+=over 4
+
+=item $notify = Win32::ChangeNotify->new($path, $subtree, $filter)
+
+Constructor for a new ChangeNotification object.  C<$path> is the
+directory to monitor.  If C<$subtree> is true, then all directories
+under C<$path> will be monitored.  C<$filter> indicates what events
+should trigger a notification.  It should be a string containing any
+of the following flags (separated by whitespace and/or C<|>).
+
+   ATTRIBUTES	Any attribute change
+   DIR_NAME     Any directory name change
+   FILE_NAME    Any file name change (creating/deleting/renaming)
+   LAST_WRITE   Any change to a file's last write time
+   SECURITY     Any security descriptor change
+   SIZE         Any change in a file's size
+
+(C<$filter> can also be an integer composed from the
+C<FILE_NOTIFY_CHANGE_*> constants.)
+
+=item $notify->close
+
+Shut down monitoring.  You could just C<undef $notify> instead (but
+C<close> works even if there are other copies of the object).  This
+happens automatically when your program exits.
+
+=item $notify->reset
+
+Resets the ChangeNotification object after a change has been detected.
+The object will become signalled again after the next change.  (It is
+OK to call this immediately after C<new>, but it is not required.)
+
+=item $notify->wait
+
+See L<"Win32::IPC">.  Remember to call C<reset> afterwards if you want
+to continue monitoring.
+
+=back
+
+=head2 Deprecated Functions and Methods
+
+B<Win32::ChangeNotify> still supports the ActiveWare syntax, but its
+use is deprecated.
+
+=over 4
+
+=item FindFirst($Obj,$PathName,$WatchSubTree,$Filter)
+
+Use
+
+  $Obj = Win32::ChangeNotify->new($PathName,$WatchSubTree,$Filter)
+
+instead.
+
+=item $obj->FindNext()
+
+Use C<$obj-E<gt>reset> instead.
+
+=item $obj->Close()
+
+Use C<$obj-E<gt>close> instead.
+
+=back
+
+=head1 AUTHOR
+
+Christopher J. Madsen E<lt>F<chris_madsen@geocities.com>E<gt>
+
+Loosely based on the original module by ActiveWare Internet Corp.,
+F<http://www.ActiveWare.com>
+
+=cut
+
+# Local Variables:
+# tmtrack-file-task: "Win32::ChangeNotify"
+# End:
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Client.pl
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Client.pl	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Client.pl	(revision 14139)
@@ -0,0 +1,66 @@
+
+
+    use Win32::Pipe;
+
+
+        ####
+        #   You may notice that named pipe names are case INsensitive!
+        ####
+
+    $PipeName = "\\\\.\\pipe\\TEST this LoNG Named Pipe!";
+
+    print "I am falling asleep for few seconds, so that we give time\nFor the server to get up and running.\n";
+    sleep(4);
+    print "\nOpening a pipe ...\n";
+
+
+
+    if ($Pipe = new Win32::Pipe($PipeName)){
+        print "\n\nPipe has been opened, writing data to it...\n";
+        print "-------------------------------------------\n";
+        $iFlag2 = 1;
+        $Pipe->Write( "\n" . Win32::Pipe::Credit() . "\n\n");
+        while($iFlag2){
+            print "\nCommands:\n";
+            print "  FILE:xxxxx  Dumps the file xxxxx.\n";
+            print "  Credit      Dumps the credit screen.\n";
+            print "  Quit        Quits this client (server remains running).\n";
+            print "  Exit        Exits both client and server.\n";
+            print "  -----------------------------------------\n";
+
+            $In = <STDIN>;
+            chop($In);
+
+            if (($File = $In) =~ s/^file:(.*)/$1/i){
+                if (-s $File){
+                    if (open(FILE, "< $File")){
+                        while ($File = <FILE>){
+                            $In .= $File;
+                        };
+                        close(FILE);
+                        undef $File;
+                    }
+                }
+            }
+            if($In =~ /^credit$/i){
+                $In = "\n" . Win32::Pipe::Credit() . "\n\n";
+            }
+
+            $iFlag2 = $Pipe->Write("$In");
+            if($In =~ /^(exit|quit)$/i){
+                print "\nATTENTION: Closing due to user request.\n";
+                $iFlag2 = 0;
+            }
+
+            undef $In;
+
+        }
+        $Pipe->Close();
+    }else{
+        ($Error, $ErrorText) = Win32::Pipe::Error();
+        print "Error:$Error \"$ErrorText\"\n";
+        sleep(4);
+    }
+
+
+
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Clipboard.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Clipboard.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Clipboard.pm	(revision 14139)
@@ -0,0 +1,363 @@
+package Win32::Clipboard;
+#######################################################################
+#
+# Win32::Clipboard - Interaction with the Windows clipboard
+#
+# Version: 0.5101
+# Author: Aldo Calpini <dada@perl.it>
+#
+#######################################################################
+
+require Exporter;       # to export the constants to the main:: space
+require DynaLoader;     # to dynuhlode the module.
+
+@ISA = qw( Exporter DynaLoader );
+@EXPORT = qw(
+	CF_TEXT
+	CF_BITMAP
+	CF_METAFILEPICT
+	CF_SYLK
+	CF_DIF
+	CF_TIFF
+	CF_OEMTEXT
+	CF_DIB
+	CF_PALETTE
+	CF_PENDATA
+	CF_RIFF
+	CF_WAVE
+	CF_UNICODETEXT
+	CF_ENHMETAFILE
+	CF_HDROP
+	CF_LOCALE
+);
+
+#######################################################################
+# This AUTOLOAD is used to 'autoload' constants from the constant()
+# XS function.  If a constant is not found then control is passed
+# to the AUTOLOAD in AutoLoader.
+#
+
+sub AUTOLOAD {
+    my($constname);
+    ($constname = $AUTOLOAD) =~ s/.*:://;
+    #reset $! to zero to reset any current errors.
+    local $! = 0;
+    my $val = constant($constname, @_ ? $_[0] : 0);
+    if ($! != 0) {
+        if ($! =~ /Invalid/) {
+            $AutoLoader::AUTOLOAD = $AUTOLOAD;
+            goto &AutoLoader::AUTOLOAD;
+        } else {
+            my ($pack, $file, $line) = caller;
+            die "Win32::Clipboard::$constname is not defined, used at $file line $line.";
+        }
+    }
+    eval "sub $AUTOLOAD { $val }";
+    goto &$AUTOLOAD;
+}
+
+
+#######################################################################
+# STATIC OBJECT PROPERTIES
+#
+$VERSION = "0.5101";
+
+#######################################################################
+# FUNCTIONS
+#
+
+sub new {
+    my($class, $value) = @_;
+    my $self = "I'm the Clipboard!";
+    Set($value) if defined($value);
+    return bless(\$self);
+}
+
+sub Version {
+    return $VERSION;
+}
+
+sub Get {
+	if(    IsBitmap() ) { return GetBitmap(); }
+	elsif( IsFiles()  ) { return GetFiles();  }
+	else                { return GetText();   }
+}
+
+sub TIESCALAR {
+	my $class = shift;
+	my $value = shift;
+	Set($value) if defined $value;
+	my $self = "I'm the Clipboard!";
+	return bless \$self, $class;
+}
+
+sub FETCH { Get() }
+sub STORE { shift; Set(@_) }
+
+sub DESTROY {
+    my($self) = @_;
+    undef $self;
+    StopClipboardViewer();
+}
+
+END {
+    StopClipboardViewer();
+}
+
+#######################################################################
+# dynamically load in the Clipboard.pll module.
+#
+
+bootstrap Win32::Clipboard;
+
+#######################################################################
+# a little hack to use the module itself as a class.
+#
+
+sub main::Win32::Clipboard {
+    my($value) = @_;
+    my $self={};
+    my $result = Win32::Clipboard::Set($value) if defined($value);
+    return bless($self, "Win32::Clipboard");
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Win32::Clipboard - Interaction with the Windows clipboard
+
+=head1 SYNOPSIS
+
+    use Win32::Clipboard;
+
+    $CLIP = Win32::Clipboard();
+
+    print "Clipboard contains: ", $CLIP->Get(), "\n";
+
+    $CLIP->Set("some text to copy into the clipboard");
+
+    $CLIP->Empty();
+
+    $CLIP->WaitForChange();
+    print "Clipboard has changed!\n";
+
+
+=head1 DESCRIPTION
+
+This module lets you interact with the Windows clipboard: you can get its content,
+set it, empty it, or let your script sleep until it changes.
+This version supports 3 formats for clipboard data:
+
+=over 4
+
+=item *
+text (C<CF_TEXT>)
+
+The clipboard contains some text; this is the B<only> format you can use to set 
+clipboard data; you get it as a single string.
+
+Example:
+
+    $text = Win32::Clipboard::GetText();
+    print $text;
+
+=item *
+bitmap (C<CF_DIB>)
+
+The clipboard contains an image, either a bitmap or a picture copied in the
+clipboard from a graphic application. The data you get is a binary buffer
+ready to be written to a bitmap (BMP format) file.
+
+Example:
+
+    $image = Win32::Clipboard::GetBitmap();
+    open    BITMAP, ">some.bmp";
+    binmode BITMAP;
+    print   BITMAP $image;
+    close   BITMAP;
+
+=item *
+list of files (C<CF_HDROP>)
+
+The clipboard contains files copied or cutted from an Explorer-like 
+application; you get a list of filenames.
+
+Example:
+
+    @files = Win32::Clipboard::GetFiles();
+    print join("\n", @files);
+
+=back
+
+=head2 REFERENCE
+
+All the functions can be used either with their full name (eg. B<Win32::Clipboard::Get>)
+or as methods of a C<Win32::Clipboard> object.
+For the syntax, refer to L</SYNOPSIS> above. Note also that you can create a clipboard
+object and set its content at the same time with:
+
+    $CLIP = Win32::Clipboard("blah blah blah");
+
+or with the more common form:
+
+    $CLIP = new Win32::Clipboard("blah blah blah");
+
+If you prefer, you can even tie the Clipboard to a variable like this:
+
+	tie $CLIP, 'Win32::Clipboard';
+	
+	print "Clipboard content: $CLIP\n";
+	
+	$CLIP = "some text to copy to the clipboard...";
+
+In this case, you can still access other methods using the tied() function:
+
+	tied($CLIP)->Empty;
+	print "got the picture" if tied($CLIP)->IsBitmap;
+
+=over 4
+
+=item Empty()
+
+Empty the clipboard.
+
+=for html <P>
+
+=item EnumFormats()
+
+Returns an array of identifiers describing the format for the data currently in the
+clipboard. Formats can be standard ones (described in the L</CONSTANTS> section) or 
+application-defined custom ones. See also IsFormatAvailable().
+
+=for html <P>
+
+=item Get()
+
+Returns the clipboard content; note that the result depends on the nature of
+clipboard data; to ensure that you get only the desired format, you should use
+GetText(), GetBitmap() or GetFiles() instead. Get() is in fact implemented as:
+
+	if(    IsBitmap() ) { return GetBitmap(); }
+	elsif( IsFiles()  ) { return GetFiles();  }
+	else                { return GetText();   }
+
+See also IsBitmap(), IsFiles(), IsText(), EnumFormats() and IsFormatAvailable()
+to check the clipboard format before getting data.
+
+=for html <P>
+
+=item GetAs(FORMAT)
+
+Returns the clipboard content in the desired FORMAT (can be one of the constants
+defined in the L</CONSTANTS> section or a custom format). Note that the only
+meaningful identifiers are C<CF_TEXT>, C<CF_DIB> and C<CF_HDROP>; any other
+format is treated as a string.
+
+=for html <P>
+
+=item GetBitmap()
+
+Returns the clipboard content as an image, or C<undef> on errors.
+
+=for html <P>
+
+=item GetFiles()
+
+Returns the clipboard content as a list of filenames, or C<undef> on errors.
+
+=for html <P>
+
+=item GetFormatName(FORMAT)
+
+Returns the name of the specified custom clipboard format, or C<undef> on errors;
+note that you cannot get the name of the standard formats (described in the
+L</CONSTANTS> section).
+
+=for html <P>
+
+=item GetText()
+
+Returns the clipboard content as a string, or C<undef> on errors.
+
+=for html <P>
+
+=item IsBitmap()
+
+Returns a boolean value indicating if the clipboard contains an image.
+See also GetBitmap().
+
+=for html <P>
+
+=item IsFiles()
+
+Returns a boolean value indicating if the clipboard contains a list of
+files. See also GetFiles().
+
+=for html <P>
+
+=item IsFormatAvailable(FORMAT)
+
+Checks if the clipboard data matches the specified FORMAT (one of the constants 
+described in the L</CONSTANTS> section); returns zero if the data does not match,
+a nonzero value if it matches.
+
+=for html <P>
+
+=item IsText()
+
+Returns a boolean value indicating if the clipboard contains text.
+See also GetText().
+
+=for html <P>
+
+=item Set(VALUE)
+
+Set the clipboard content to the specified string.
+
+=for html <P>
+
+=item WaitForChange([TIMEOUT])
+
+This function halts the script until the clipboard content changes. If you specify
+a C<TIMEOUT> value (in milliseconds), the function will return when this timeout
+expires, even if the clipboard hasn't changed. If no value is given, it will wait
+indefinitely. Returns 1 if the clipboard has changed, C<undef> on errors.
+
+=back
+
+=head2 CONSTANTS
+
+These constants are the standard clipboard formats recognized by Win32::Clipboard:
+
+	CF_TEXT             1
+	CF_DIB              8
+	CF_HDROP            15
+
+The following formats are B<not recognized> by Win32::Clipboard; they are,
+however, exported constants and can eventually be used with the EnumFormats(), 
+IsFormatAvailable() and GetAs() functions:
+
+	CF_BITMAP           2
+	CF_METAFILEPICT     3
+	CF_SYLK             4
+	CF_DIF              5
+	CF_TIFF             6
+	CF_OEMTEXT          7
+	CF_PALETTE          9
+	CF_PENDATA          10
+	CF_RIFF             11
+	CF_WAVE             12
+	CF_UNICODETEXT      13
+	CF_ENHMETAFILE      14
+	CF_LOCALE           16
+
+=head1 AUTHOR
+
+Aldo Calpini <F<dada@perl.it>>
+
+Original XS porting by Gurusamy Sarathy <F<gsar@activestate.com>>.
+
+=cut
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Console.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Console.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Console.pm	(revision 14139)
@@ -0,0 +1,1483 @@
+package Win32::Console;
+#######################################################################
+#
+# Win32::Console - Win32 Console and Character Mode Functions
+# ^^^^^^^^^^^^^^
+# Version: 0.03  (07 Apr 1997)
+# Version: 0.031 (24 Sep 1999) - fixed typo in GenerateCtrlEvent()
+#
+#######################################################################
+
+require Exporter;       # to export the constants to the main:: space
+require DynaLoader;     # to dynuhlode the module.
+
+@ISA= qw( Exporter DynaLoader );
+@EXPORT = qw(
+    BACKGROUND_BLUE
+    BACKGROUND_GREEN
+    BACKGROUND_INTENSITY
+    BACKGROUND_RED
+    CAPSLOCK_ON
+    CONSOLE_TEXTMODE_BUFFER
+    CTRL_BREAK_EVENT    
+    CTRL_C_EVENT
+    ENABLE_ECHO_INPUT
+    ENABLE_LINE_INPUT
+    ENABLE_MOUSE_INPUT
+    ENABLE_PROCESSED_INPUT
+    ENABLE_PROCESSED_OUTPUT
+    ENABLE_WINDOW_INPUT
+    ENABLE_WRAP_AT_EOL_OUTPUT
+    ENHANCED_KEY
+    FILE_SHARE_READ
+    FILE_SHARE_WRITE
+    FOREGROUND_BLUE
+    FOREGROUND_GREEN
+    FOREGROUND_INTENSITY
+    FOREGROUND_RED
+    LEFT_ALT_PRESSED
+    LEFT_CTRL_PRESSED
+    NUMLOCK_ON
+    GENERIC_READ
+    GENERIC_WRITE
+    RIGHT_ALT_PRESSED
+    RIGHT_CTRL_PRESSED
+    SCROLLLOCK_ON
+    SHIFT_PRESSED
+    STD_INPUT_HANDLE
+    STD_OUTPUT_HANDLE
+    STD_ERROR_HANDLE
+);
+
+
+#######################################################################
+# This AUTOLOAD is used to 'autoload' constants from the constant()
+# XS function.  If a constant is not found then control is passed
+# to the AUTOLOAD in AutoLoader.
+#
+
+sub AUTOLOAD {
+    my($constname);
+    ($constname = $AUTOLOAD) =~ s/.*:://;
+    #reset $! to zero to reset any current errors.
+    local $! = 0;
+    my $val = constant($constname, @_ ? $_[0] : 0);
+    if ($! != 0) {
+#    if ($! =~ /Invalid/) {
+#        $AutoLoader::AUTOLOAD = $AUTOLOAD;
+#        goto &AutoLoader::AUTOLOAD;
+#    } else {
+        ($pack, $file, $line) = caller; undef $pack;
+        die "Symbol Win32::Console::$constname not defined, used at $file line $line.";
+#    }
+    }
+    eval "sub $AUTOLOAD { $val }";
+    goto &$AUTOLOAD;
+}
+
+
+#######################################################################
+# STATIC OBJECT PROPERTIES
+#
+$VERSION = "0.031";
+
+# %HandlerRoutineStack = ();
+# $HandlerRoutineRegistered = 0;
+
+#######################################################################
+# PUBLIC METHODS
+#
+
+#======== (MAIN CONSTRUCTOR)
+sub new {
+#========
+    my($class, $param1, $param2) = @_;
+
+    my $self = {};
+
+    if(defined($param1) 
+    and ($param1 == constant("STD_INPUT_HANDLE",  0)
+    or   $param1 == constant("STD_OUTPUT_HANDLE", 0)
+    or   $param1 == constant("STD_ERROR_HANDLE",  0))) {
+
+        $self->{'handle'} = _GetStdHandle($param1);
+
+    } else {
+
+        $param1 = constant("GENERIC_READ", 0)    | constant("GENERIC_WRITE", 0) unless $param1;
+        $param2 = constant("FILE_SHARE_READ", 0) | constant("FILE_SHARE_WRITE", 0) unless $param2;
+        $self->{'handle'} = _CreateConsoleScreenBuffer($param1, $param2, 
+                                                       constant("CONSOLE_TEXTMODE_BUFFER", 0));
+    }
+    bless $self, $class;
+    return $self;
+}
+
+
+#============
+sub Display {
+#============
+    my($self)=@_;
+    return undef unless ref($self);
+
+    return _SetConsoleActiveScreenBuffer($self->{'handle'});
+}
+
+#===========
+sub Select {
+#===========
+    ($self, $type) = @_;
+    return undef unless ref($self);
+
+    return _SetStdHandle($type, $self->{'handle'});
+}
+
+
+#==========
+sub Title {
+#==========
+    my($self, $title) = @_;
+
+    $title = $self unless ref($self);
+
+    if(defined($title)) {
+      return _SetConsoleTitle($title);
+    } else {
+      return _GetConsoleTitle();
+    }
+}
+
+#==============
+sub WriteChar {
+#==============
+    my($self, $text, $col, $row) = @_;
+    return undef unless ref($self);
+
+    return _WriteConsoleOutputCharacter($self->{'handle'},$text,$col,$row);
+}
+
+#=============
+sub ReadChar {
+#=============
+    my($self, $size, $col, $row) = @_;
+    return undef unless ref($self);
+  
+    my $buffer = (" " x $size);  
+    if(_ReadConsoleOutputCharacter($self->{'handle'}, $buffer, $size, $col, $row)) {
+        return $buffer;
+    } else {
+        return undef;
+    }
+}
+
+
+
+#==============
+sub WriteAttr {
+#==============
+    my($self, $attr, $col, $row) = @_;
+    return undef unless ref($self);
+    return _WriteConsoleOutputAttribute($self->{'handle'}, $attr, $col, $row);
+}
+
+#=============
+sub ReadAttr {
+#=============
+    my($self, $size, $col, $row) = @_;
+    return undef unless ref($self);
+  
+    return _ReadConsoleOutputAttribute($self->{'handle'}, $size, $col, $row);
+}
+
+
+#==========
+sub Write {
+#==========
+    my($self,$string) = @_;
+    return undef unless ref($self);
+    return _WriteConsole($self->{'handle'}, $string);
+}
+
+
+#=============
+sub ReadRect {
+#=============
+    my($self, $left, $top, $right, $bottom) = @_;
+    return undef unless ref($self);
+    
+    my $col = $right  - $left + 1;
+    my $row = $bottom - $top  + 1;
+
+    my $buffer = (" " x ($col*$row*4));
+    if(_ReadConsoleOutput($self->{'handle'},   $buffer,
+                          $col,  $row, 0,      0,
+                          $left, $top, $right, $bottom)) {
+        return $buffer;
+    } else {
+        return undef;
+    }
+}
+
+
+#==============
+sub WriteRect {
+#==============
+    my($self, $buffer, $left, $top, $right, $bottom) = @_;
+    return undef unless ref($self);
+
+    my $col = $right  - $left + 1;
+    my $row = $bottom - $top  + 1;
+
+    return _WriteConsoleOutput($self->{'handle'},   $buffer,
+                               $col,  $row, 0,  0,
+                               $left, $top, $right, $bottom);
+}
+
+
+
+#===========
+sub Scroll {
+#===========
+    my($self, $left1, $top1, $right1, $bottom1,
+              $col,   $row,  $char,   $attr,
+              $left2, $top2, $right2, $bottom2) = @_;
+    return undef unless ref($self);
+  
+    return _ScrollConsoleScreenBuffer($self->{'handle'},
+                                      $left1, $top1, $right1, $bottom1,
+                                      $col,   $row,  $char,   $attr,
+                                      $left2, $top2, $right2, $bottom2);
+}
+
+
+#==============
+sub MaxWindow {
+#==============
+    my($self, $flag) = @_;
+    return undef unless ref($self);
+  
+    if(not defined($flag)) {
+        my @info = _GetConsoleScreenBufferInfo($self->{'handle'});
+        return $info[9], $info[10];
+    } else {
+        return _GetLargestConsoleWindowSize($self->{'handle'});
+    }
+}
+
+#=========
+sub Info {
+#=========
+    my($self) = @_;
+    return undef unless ref($self);
+  
+    return _GetConsoleScreenBufferInfo($self->{'handle'});
+}
+
+
+#===========
+sub Window {
+#===========
+    my($self, $flag, $left, $top, $right, $bottom) = @_;
+    return undef unless ref($self);
+  
+    if(not defined($flag)) {
+        my @info = _GetConsoleScreenBufferInfo($self->{'handle'});
+        return $info[5], $info[6], $info[7], $info[8];
+    } else {
+        return _SetConsoleWindowInfo($self->{'handle'}, $flag, $left, $top, $right, $bottom);
+    }
+}
+
+#==============
+sub GetEvents {
+#==============
+    my $self="";
+    ($self)=@_;
+    return undef unless ref($self);
+  
+    return _GetNumberOfConsoleInputEvents($self->{'handle'});
+}
+
+
+#==========
+sub Flush {
+#==========
+    my($self) = @_;
+    return undef unless ref($self);
+
+    return _FlushConsoleInputBuffer($self->{'handle'});
+}
+
+#==============
+sub InputChar {
+#==============
+    my($self, $number) = @_;
+    return undef unless ref($self);
+    
+    $number = 1 unless defined($number);
+  
+    my $buffer = (" " x $number);
+    if(_ReadConsole($self->{'handle'}, $buffer, $number) == $number) {
+        return $buffer;
+    } else {
+        return undef;
+    }
+}
+
+#==========
+sub Input {
+#==========
+    my($self) = @_;
+    return undef unless ref($self);
+  
+    return _ReadConsoleInput($self->{'handle'});
+}
+
+#==============
+sub PeekInput {
+#==============
+    my($self) = @_;
+    return undef unless ref($self);
+  
+    return _PeekConsoleInput($self->{'handle'});
+}
+
+
+#===============
+sub WriteInput {
+#===============
+    my($self) = shift;
+    return undef unless ref($self);
+  
+    return _WriteConsoleInput($self->{'handle'}, @_);
+}
+
+
+#=========
+sub Mode {
+#=========
+    my($self, $mode) = @_;
+    return undef unless ref($self);
+  
+    if(defined($mode)) {
+        return _SetConsoleMode($self->{'handle'}, $mode);
+    } else {
+        return _GetConsoleMode($self->{'handle'});
+    }
+}
+
+#========
+sub Cls {
+#========
+    my($self, $attr) = @_;
+    return undef unless ref($self);
+
+    $attr = $main::ATTR_NORMAL unless defined($attr);
+    
+    my ($x, $y) = $self->Size();
+    my($left, $top, $right ,$bottom) = $self->Window();
+    my $vx = $right  - $left;
+    my $vy = $bottom - $top;
+    $self->FillChar(" ", $x*$y, 0, 0);
+    $self->FillAttr($attr, $x*$y, 0, 0);
+    $self->Cursor(0, 0);
+    $self->Window(1, 0, 0, $vx, $vy);
+}
+
+
+#=========
+sub Attr {
+#=========
+    my($self, $attr) = @_;
+    return undef unless ref($self);
+  
+    if(not defined($attr)) {
+        return (_GetConsoleScreenBufferInfo($self->{'handle'}))[4];
+    } else {
+        return _SetConsoleTextAttribute($self->{'handle'}, $attr);
+    }
+}
+
+#===========
+sub Cursor {
+#===========
+    my($self, $col, $row, $size, $visi) = @_;
+    return undef unless ref($self);
+
+    my $curr_row  = 0;
+    my $curr_col  = 0;
+    my $curr_size = 0;
+    my $curr_visi = 0;
+    my $return    = 0;
+    my $discard   = 0;
+
+  
+    if(defined($col)) {
+        $row = -1 if not defined($row);
+        if($col == -1 or $row == -1) {
+            ($discard, $discard, $curr_col, $curr_row) = _GetConsoleScreenBufferInfo($self->{'handle'});
+            $col=$curr_col if $col==-1;
+            $row=$curr_row if $row==-1;
+        }
+        $return += _SetConsoleCursorPosition($self->{'handle'}, $col, $row);
+        if(defined($size) and defined($visi)) {
+            if($size == -1 or $visi == -1) {
+                ($curr_size, $curr_visi) = _GetConsoleCursorInfo($self->{'handle'});
+                $size = $curr_size if $size == -1;
+                $visi = $curr_visi if $visi == -1;
+            }
+            $size = 1 if $size < 1;
+            $size = 99 if $size > 99;
+            $return += _SetConsoleCursorInfo($self->{'handle'}, $size, $visi);
+        }
+        return $return;
+    } else {
+        ($discard, $discard, $curr_col, $curr_row) = _GetConsoleScreenBufferInfo($self->{'handle'});
+        ($curr_size, $curr_visi) = _GetConsoleCursorInfo($self->{'handle'});
+        return ($curr_col, $curr_row, $curr_size, $curr_visi);
+    }
+}
+  
+#=========
+sub Size {
+#=========
+    my($self, $col, $row) = @_;
+    return undef unless ref($self);
+    if(not defined($col)) {
+        ($col, $row) = _GetConsoleScreenBufferInfo($self->{'handle'});
+        return ($col, $row);
+    } else {
+        $row = -1 if not defined($row);
+        if($col == -1 or $row == -1) {
+            ($curr_col, $curr_row) = _GetConsoleScreenBufferInfo($self->{'handle'});
+            $col=$curr_col if $col==-1;
+            $row=$curr_row if $row==-1;
+        }
+        return _SetConsoleScreenBufferSize($self->{'handle'}, $col, $row);
+    }
+}
+
+#=============
+sub FillAttr {
+#=============
+    my($self, $attr, $number, $col, $row) = @_;
+    return undef unless ref($self);
+
+    $number = 1 unless $number;
+
+    if(!defined($col) or !defined($row) or $col == -1 or $row == -1) {
+        ($discard,  $discard, 
+         $curr_col, $curr_row) = _GetConsoleScreenBufferInfo($self->{'handle'});
+        $col = $curr_col if !defined($col) or $col == -1;
+        $row = $curr_row if !defined($row) or $row == -1;
+    }
+    return _FillConsoleOutputAttribute($self->{'handle'}, $attr, $number, $col, $row);
+}
+
+#=============
+sub FillChar {
+#=============
+    my($self, $char, $number, $col, $row) = @_;
+    return undef unless ref($self);
+
+    if(!defined($col) or !defined($row) or $col == -1 or $row == -1) {
+        ($discard,  $discard,
+         $curr_col, $curr_row) = _GetConsoleScreenBufferInfo($self->{'handle'});
+        $col = $curr_col if !defined($col) or $col == -1;
+        $row = $curr_row if !defined($row) or $row == -1;
+    }
+    return _FillConsoleOutputCharacter($self->{'handle'}, $char, $number, $col, $row);
+}
+
+#============
+sub InputCP {
+#============
+    my($self, $codepage) = @_;
+    $codepage = $self if (defined($self) and ref($self) ne "Win32::Console");
+    if(defined($codepage)) {
+        return _SetConsoleCP($codepage);
+    } else {
+        return _GetConsoleCP();
+    }
+}
+
+#=============
+sub OutputCP {
+#=============
+    my($self, $codepage) = @_;
+    $codepage = $self if (defined($self) and ref($self) ne "Win32::Console");
+    if(defined($codepage)) {
+        return _SetConsoleOutputCP($codepage);
+    } else {
+        return _GetConsoleOutputCP();
+    }
+}
+
+#======================
+sub GenerateCtrlEvent {
+#======================
+    my($self, $type, $pid) = @_;
+    $type = constant("CTRL_C_EVENT", 0) unless defined($type);
+    $pid = 0 unless defined($pid);
+    return _GenerateConsoleCtrlEvent($type, $pid);
+}
+
+#===================
+#sub SetCtrlHandler {
+#===================
+#    my($name, $add) = @_;
+#    $add = 1 unless defined($add);
+#    my @nor = keys(%HandlerRoutineStack);
+#    if($add == 0) {
+#        foreach $key (@nor) {
+#            delete $HandlerRoutineStack{$key}, last if $HandlerRoutineStack{$key}==$name;
+#        }
+#        $HandlerRoutineRegistered--;
+#    } else {
+#        if($#nor == -1) {
+#            my $r = _SetConsoleCtrlHandler();
+#            if(!$r) {
+#                print "WARNING: SetConsoleCtrlHandler failed...\n";
+#            }
+#        }
+#        $HandlerRoutineRegistered++;
+#        $HandlerRoutineStack{$HandlerRoutineRegistered} = $name;
+#    }
+#}
+
+
+########################################################################
+# PRIVATE METHODS
+#
+
+#================
+#sub CtrlHandler {
+#================
+#    my($ctrltype) = @_;
+#    my $routine;
+#    my $result = 0;
+#    CALLEM: foreach $routine (sort { $b <=> $a } keys %HandlerRoutineStack) {
+#        #print "CtrlHandler: calling $HandlerRoutineStack{$routine}($ctrltype)\n";
+#        $result = &{"main::".$HandlerRoutineStack{$routine}}($ctrltype);
+#        last CALLEM if $result;
+#    }
+#    return $result;
+#}
+
+#============  (MAIN DESTRUCTOR)
+sub DESTROY {
+#============
+    my($self) = @_;
+    _CloseHandle($self->{'handle'});
+}
+
+
+
+#######################################################################
+# dynamically load in the Console.pll module.
+#
+
+bootstrap Win32::Console;
+
+#######################################################################
+# ADDITIONAL CONSTANTS EXPORTED IN THE MAIN NAMESPACE
+#
+
+$main::FG_BLACK        = 0;
+$main::FG_BLUE         = constant("FOREGROUND_BLUE",0);
+$main::FG_LIGHTBLUE    = constant("FOREGROUND_BLUE",0)|
+                         constant("FOREGROUND_INTENSITY",0);
+$main::FG_RED          = constant("FOREGROUND_RED",0);
+$main::FG_LIGHTRED     = constant("FOREGROUND_RED",0)|
+                         constant("FOREGROUND_INTENSITY",0);
+$main::FG_GREEN        = constant("FOREGROUND_GREEN",0);
+$main::FG_LIGHTGREEN   = constant("FOREGROUND_GREEN",0)|
+                         constant("FOREGROUND_INTENSITY",0);
+$main::FG_MAGENTA      = constant("FOREGROUND_RED",0)|
+                         constant("FOREGROUND_BLUE",0);
+$main::FG_LIGHTMAGENTA = constant("FOREGROUND_RED",0)|
+                         constant("FOREGROUND_BLUE",0)|
+                         constant("FOREGROUND_INTENSITY",0);
+$main::FG_CYAN         = constant("FOREGROUND_GREEN",0)|
+                         constant("FOREGROUND_BLUE",0);
+$main::FG_LIGHTCYAN    = constant("FOREGROUND_GREEN",0)|
+                         constant("FOREGROUND_BLUE",0)|
+                         constant("FOREGROUND_INTENSITY",0);
+$main::FG_BROWN        = constant("FOREGROUND_RED",0)|
+                         constant("FOREGROUND_GREEN",0);
+$main::FG_YELLOW       = constant("FOREGROUND_RED",0)|
+                         constant("FOREGROUND_GREEN",0)|
+                         constant("FOREGROUND_INTENSITY",0);
+$main::FG_GRAY         = constant("FOREGROUND_RED",0)|
+                         constant("FOREGROUND_GREEN",0)|
+                         constant("FOREGROUND_BLUE",0);
+$main::FG_WHITE        = constant("FOREGROUND_RED",0)|
+                         constant("FOREGROUND_GREEN",0)|
+                         constant("FOREGROUND_BLUE",0)|
+                         constant("FOREGROUND_INTENSITY",0);
+
+$main::BG_BLACK        = 0;
+$main::BG_BLUE         = constant("BACKGROUND_BLUE",0);
+$main::BG_LIGHTBLUE    = constant("BACKGROUND_BLUE",0)|
+                         constant("BACKGROUND_INTENSITY",0);
+$main::BG_RED          = constant("BACKGROUND_RED",0);
+$main::BG_LIGHTRED     = constant("BACKGROUND_RED",0)|
+                         constant("BACKGROUND_INTENSITY",0);
+$main::BG_GREEN        = constant("BACKGROUND_GREEN",0);
+$main::BG_LIGHTGREEN   = constant("BACKGROUND_GREEN",0)|
+                         constant("BACKGROUND_INTENSITY",0);
+$main::BG_MAGENTA      = constant("BACKGROUND_RED",0)|
+                         constant("BACKGROUND_BLUE",0);
+$main::BG_LIGHTMAGENTA = constant("BACKGROUND_RED",0)|
+                         constant("BACKGROUND_BLUE",0)|
+                         constant("BACKGROUND_INTENSITY",0);
+$main::BG_CYAN         = constant("BACKGROUND_GREEN",0)|
+                         constant("BACKGROUND_BLUE",0);
+$main::BG_LIGHTCYAN    = constant("BACKGROUND_GREEN",0)|
+                         constant("BACKGROUND_BLUE",0)|
+                         constant("BACKGROUND_INTENSITY",0);
+$main::BG_BROWN        = constant("BACKGROUND_RED",0)|
+                         constant("BACKGROUND_GREEN",0);
+$main::BG_YELLOW       = constant("BACKGROUND_RED",0)|
+                         constant("BACKGROUND_GREEN",0)|
+                         constant("BACKGROUND_INTENSITY",0);
+$main::BG_GRAY         = constant("BACKGROUND_RED",0)|
+                         constant("BACKGROUND_GREEN",0)|
+                         constant("BACKGROUND_BLUE",0);
+$main::BG_WHITE        = constant("BACKGROUND_RED",0)|
+                         constant("BACKGROUND_GREEN",0)|
+                         constant("BACKGROUND_BLUE",0)|
+                         constant("BACKGROUND_INTENSITY",0);
+
+$main::ATTR_NORMAL = $main::FG_GRAY|$main::BG_BLACK;
+$main::ATTR_INVERSE = $main::FG_BLACK|$main::BG_GRAY;
+
+undef unless $main::ATTR_NORMAL;
+undef unless $main::ATTR_INVERSE;
+undef unless $VERSION;
+
+@main::CONSOLE_COLORS = ();
+
+foreach $fg ($main::FG_BLACK, $main::FG_BLUE, $main::FG_GREEN, $main::FG_CYAN, 
+             $main::FG_RED, $main::FG_MAGENTA, $main::FG_BROWN, $main::FG_GRAY,
+             $main::FG_LIGHTBLUE, $main::FG_LIGHTGREEN, $main::FG_LIGHTCYAN,
+             $main::FG_LIGHTRED, $main::FG_LIGHTMAGENTA, $main::FG_YELLOW, 
+             $main::FG_WHITE) {
+
+    foreach $bg ($main::BG_BLACK, $main::BG_BLUE, $main::BG_GREEN, $main::BG_CYAN, 
+                 $main::BG_RED, $main::BG_MAGENTA, $main::BG_BROWN, $main::BG_GRAY,
+                 $main::BG_LIGHTBLUE, $main::BG_LIGHTGREEN, $main::BG_LIGHTCYAN,
+                 $main::BG_LIGHTRED, $main::BG_LIGHTMAGENTA, $main::BG_YELLOW, 
+                 $main::BG_WHITE) {
+        push(@main::CONSOLE_COLORS, $fg|$bg);
+    }
+}
+
+undef $fg;
+undef $bg;
+
+# Preloaded methods go here.
+
+#Currently Autoloading is not implemented in Perl for win32
+# Autoload methods go after __END__, and are processed by the autosplit program.
+
+1;
+
+__END__
+
+=head1 NAME
+
+Win32::Console - Win32 Console and Character Mode Functions
+
+
+=head1 DESCRIPTION
+
+This module implements the Win32 console and character mode
+functions.  They give you full control on the console input and output,
+including: support of off-screen console buffers (eg. multiple screen
+pages)
+
+=over
+
+=item *
+
+reading and writing of characters, attributes and whole portions of
+the screen
+
+=item *
+
+complete processing of keyboard and mouse events
+
+=item *
+
+some very funny additional features :)
+
+=back
+
+Those functions should also make possible a port of the Unix's curses
+library; if there is anyone interested (and/or willing to contribute)
+to this project, e-mail me.  Thank you.
+
+
+=head1 REFERENCE
+
+
+=head2 Methods
+
+=over
+
+=item Alloc
+
+Allocates a new console for the process.  Returns C<undef> on errors, a
+nonzero value on success.  A process cannot be associated with more
+than one console, so this method will fail if there is already an
+allocated console.  Use Free to detach the process from the console,
+and then call Alloc to create a new console.  See also: C<Free>
+
+Example:
+
+    $CONSOLE->Alloc();
+
+=item Attr [attr]
+
+Gets or sets the current console attribute.  This attribute is used by
+the Write method.
+
+Example:
+
+    $attr = $CONSOLE->Attr();
+    $CONSOLE->Attr($FG_YELLOW | $BG_BLUE);
+
+=item Close
+
+Closes a shortcut object.  Note that it is not "strictly" required to
+close the objects you created, since the Win32::Shortcut objects are
+automatically closed when the program ends (or when you elsehow
+destroy such an object).
+
+Example:
+
+    $LINK->Close();
+
+=item Cls [attr]
+
+Clear the console, with the specified I<attr> if given, or using
+ATTR_NORMAL otherwise.
+
+Example:
+
+    $CONSOLE->Cls();
+    $CONSOLE->Cls($FG_WHITE | $BG_GREEN);
+
+=item Cursor [x, y, size, visible]
+
+Gets or sets cursor position and appearance.  Returns C<undef> on
+errors, or a 4-element list containing: I<x>, I<y>, I<size>,
+I<visible>.  I<x> and I<y> are the current cursor position; ...
+
+Example:
+
+    ($x, $y, $size, $visible) = $CONSOLE->Cursor();
+
+    # Get position only
+    ($x, $y) = $CONSOLE->Cursor();
+
+    $CONSOLE->Cursor(40, 13, 50, 1);
+
+    # Set position only
+    $CONSOLE->Cursor(40, 13);
+
+    # Set size and visibility without affecting position
+    $CONSOLE->Cursor(-1, -1, 50, 1);
+
+=item Display
+
+Displays the specified console on the screen.  Returns C<undef> on errors,
+a nonzero value on success.
+
+Example:
+
+    $CONSOLE->Display();
+
+=item FillAttr [attribute, number, col, row]
+
+Fills the specified number of consecutive attributes, beginning at
+I<col>, I<row>, with the value specified in I<attribute>.  Returns the
+number of attributes filled, or C<undef> on errors.  See also:
+C<FillChar>.
+
+Example:
+
+    $CONSOLE->FillAttr($FG_BLACK | $BG_BLACK, 80*25, 0, 0);
+
+=item FillChar char, number, col, row
+
+Fills the specified number of consecutive characters, beginning at
+I<col>, I<row>, with the character specified in I<char>.  Returns the
+number of characters filled, or C<undef> on errors.  See also:
+C<FillAttr>.
+
+Example:
+
+    $CONSOLE->FillChar("X", 80*25, 0, 0);
+
+=item Flush
+
+Flushes the console input buffer.  All the events in the buffer are
+discarded.  Returns C<undef> on errors, a nonzero value on success.
+
+Example:
+
+    $CONSOLE->Flush();
+
+=item Free
+
+Detaches the process from the console.  Returns C<undef> on errors, a
+nonzero value on success.  See also: C<Alloc>.
+
+Example:
+
+    $CONSOLE->Free();
+
+=item GenerateCtrlEvent [type, processgroup]
+
+Sends a break signal of the specified I<type> to the specified
+I<processgroup>.  I<type> can be one of the following constants:
+
+    CTRL_BREAK_EVENT
+    CTRL_C_EVENT
+
+they signal, respectively, the pressing of Control + Break and of
+Control + C; if not specified, it defaults to CTRL_C_EVENT.
+I<processgroup> is the pid of a process sharing the same console.  If
+omitted, it defaults to 0 (the current process), which is also the
+only meaningful value that you can pass to this function.  Returns
+C<undef> on errors, a nonzero value on success.
+
+Example:
+
+    # break this script now
+    $CONSOLE->GenerateCtrlEvent();
+
+=item GetEvents
+
+Returns the number of unread input events in the console's input
+buffer, or C<undef> on errors.  See also: C<Input>, C<InputChar>,
+C<PeekInput>, C<WriteInput>.
+
+Example:
+
+    $events = $CONSOLE->GetEvents();
+
+=item Info
+
+Returns an array of informations about the console (or C<undef> on
+errors), which contains:
+
+=over
+
+=item *
+
+columns (X size) of the console buffer.
+
+=item *
+
+rows (Y size) of the console buffer.
+
+=item *
+
+current column (X position) of the cursor.
+
+=item *
+
+current row (Y position) of the cursor.
+
+=item *
+
+current attribute used for C<Write>.
+
+=item *
+
+left column (X of the starting point) of the current console window.
+
+=item *
+
+top row (Y of the starting point) of the current console window.
+
+=item *
+
+right column (X of the final point) of the current console window.
+
+=item *
+
+bottom row (Y of the final point) of the current console window.
+
+=item *
+
+maximum number of columns for the console window, given the current
+buffer size, font and the screen size.
+
+=item *
+
+maximum number of rows for the console window, given the current
+buffer size, font and the screen size.
+
+=back
+
+See also: C<Attr>, C<Cursor>, C<Size>, C<Window>, C<MaxWindow>.
+
+Example:
+
+    @info = $CONSOLE->Info();
+    print "Cursor at $info[3], $info[4].\n";
+
+=item Input
+
+Reads an event from the input buffer.  Returns a list of values, which
+depending on the event's nature are:
+
+=over
+
+=item keyboard event
+
+The list will contain:
+
+=over
+
+=item *
+
+event type: 1 for keyboard
+
+=item *
+
+key down: TRUE if the key is being pressed, FALSE if the key is being released
+
+=item *
+
+repeat count: the number of times the key is being held down
+
+=item *
+
+virtual keycode: the virtual key code of the key
+
+=item *
+
+virtual scancode: the virtual scan code of the key
+
+=item *
+
+char: the ASCII code of the character (if the key is a character key, 0 otherwise)
+
+=item *
+
+control key state: the state of the control keys (SHIFTs, CTRLs, ALTs, etc.)
+
+=back
+
+=item mouse event
+
+The list will contain:
+
+=over
+
+=item *
+
+event type: 2 for mouse
+
+=item *
+
+mouse pos. X: X coordinate (column) of the mouse location
+
+=item *
+
+mouse pos. Y: Y coordinate (row) of the mouse location
+
+=item *
+
+button state: the mouse button(s) which are pressed
+
+=item *
+
+control key state: the state of the control keys (SHIFTs, CTRLs, ALTs, etc.)
+
+=item *
+
+event flags: the type of the mouse event
+
+=back
+
+=back
+
+This method will return C<undef> on errors.  Note that the events
+returned are depending on the input C<Mode> of the console; for example,
+mouse events are not intercepted unless ENABLE_MOUSE_INPUT is
+specified.  See also: C<GetEvents>, C<InputChar>, C<Mode>,
+C<PeekInput>, C<WriteInput>.
+
+Example:
+
+    @event = $CONSOLE->Input();
+
+=item InputChar number
+
+Reads and returns I<number> characters from the console input buffer,
+or C<undef> on errors.  See also: C<Input>, C<Mode>.
+
+Example:
+
+    $key = $CONSOLE->InputChar(1);
+
+=item InputCP [codepage]
+
+Gets or sets the input code page used by the console.  Note that this
+doesn't apply to a console object, but to the standard input
+console.  This attribute is used by the Write method.  See also:
+C<OutputCP>.
+
+Example:
+
+    $codepage = $CONSOLE->InputCP();
+    $CONSOLE->InputCP(437);
+
+    # you may want to use the non-instanciated form to avoid confuzion :)
+    $codepage = Win32::Console::InputCP();
+    Win32::Console::InputCP(437);
+
+=item MaxWindow
+
+Returns the size of the largest possible console window, based on the
+current font and the size of the display.  The result is C<undef> on
+errors, otherwise a 2-element list containing col, row.
+
+Example:
+
+    ($maxCol, $maxRow) = $CONSOLE->MaxWindow();
+
+=item Mode [flags]
+
+Gets or sets the input or output mode of a console.  I<flags> can be a
+combination of the following constants:
+
+    ENABLE_LINE_INPUT
+    ENABLE_ECHO_INPUT
+    ENABLE_PROCESSED_INPUT
+    ENABLE_WINDOW_INPUT
+    ENABLE_MOUSE_INPUT
+    ENABLE_PROCESSED_OUTPUT
+    ENABLE_WRAP_AT_EOL_OUTPUT
+
+For more informations on the meaning of those flags, please refer to
+the L<"Microsoft's Documentation">.
+
+Example:
+
+    $mode = $CONSOLE->Mode();
+    $CONSOLE->Mode(ENABLE_MOUSE_INPUT | ENABLE_PROCESSED_INPUT);
+
+=item MouseButtons
+
+Returns the number of the buttons on your mouse, or C<undef> on errors.
+
+Example:
+
+    print "Your mouse has ", $CONSOLE->MouseButtons(), " buttons.\n";
+
+=item new Win32::Console standard_handle
+
+=item new Win32::Console [accessmode, sharemode]
+
+Creates a new console object.  The first form creates a handle to a
+standard channel, I<standard_handle> can be one of the following:
+
+    STD_OUTPUT_HANDLE
+    STD_ERROR_HANDLE
+    STD_INPUT_HANDLE
+
+The second form, instead, creates a console screen buffer in memory,
+which you can access for reading and writing as a normal console, and
+then redirect on the standard output (the screen) with C<Display>.  In
+this case, you can specify one or both of the following values for
+I<accessmode>:
+
+    GENERIC_READ
+    GENERIC_WRITE
+
+which are the permissions you will have on the created buffer, and one
+or both of the following values for I<sharemode>:
+
+    FILE_SHARE_READ
+    FILE_SHARE_WRITE
+
+which affect the way the console can be shared.  If you don't specify
+any of those parameters, all 4 flags will be used.
+
+Example:
+
+    $STDOUT = new Win32::Console(STD_OUTPUT_HANDLE);
+    $STDERR = new Win32::Console(STD_ERROR_HANDLE);
+    $STDIN  = new Win32::Console(STD_INPUT_HANDLE);
+
+    $BUFFER = new Win32::Console();
+    $BUFFER = new Win32::Console(GENERIC_READ | GENERIC_WRITE);
+
+=item OutputCP [codepage]
+
+Gets or sets the output code page used by the console.  Note that this
+doesn't apply to a console object, but to the standard output console.
+See also: C<InputCP>.
+
+Example:
+
+    $codepage = $CONSOLE->OutputCP();
+    $CONSOLE->OutputCP(437);
+
+    # you may want to use the non-instanciated form to avoid confuzion :)
+    $codepage = Win32::Console::OutputCP();
+    Win32::Console::OutputCP(437);
+
+=item PeekInput
+
+Does exactly the same as C<Input>, except that the event read is not
+removed from the input buffer.  See also: C<GetEvents>, C<Input>,
+C<InputChar>, C<Mode>, C<WriteInput>.
+
+Example:
+
+    @event = $CONSOLE->PeekInput();
+
+=item ReadAttr [number, col, row]
+
+Reads the specified I<number> of consecutive attributes, beginning at
+I<col>, I<row>, from the console.  Returns the attributes read (a
+variable containing one character for each attribute), or C<undef> on
+errors.  You can then pass the returned variable to C<WriteAttr> to
+restore the saved attributes on screen.  See also: C<ReadChar>,
+C<ReadRect>.
+
+Example:
+
+    $colors = $CONSOLE->ReadAttr(80*25, 0, 0);
+
+=item ReadChar [number, col, row]
+
+Reads the specified I<number> of consecutive characters, beginning at
+I<col>, I<row>, from the console.  Returns a string containing the
+characters read, or C<undef> on errors.  You can then pass the
+returned variable to C<WriteChar> to restore the saved characters on
+screen.  See also: C<ReadAttr>, C<ReadRect>.
+
+Example:
+
+    $chars = $CONSOLE->ReadChar(80*25, 0, 0);
+
+=item ReadRect left, top, right, bottom
+
+Reads the content (characters and attributes) of the rectangle
+specified by I<left>, I<top>, I<right>, I<bottom> from the console.
+Returns a string containing the rectangle read, or C<undef> on errors.
+You can then pass the returned variable to C<WriteRect> to restore the
+saved rectangle on screen (or on another console).  See also:
+C<ReadAttr>, C<ReadChar>.
+
+Example:
+
+     $rect = $CONSOLE->ReadRect(0, 0, 80, 25);
+
+=item Scroll left, top, right, bottom, col, row, char, attr,
+             [cleft, ctop, cright, cbottom]
+
+Moves a block of data in a console buffer; the block is identified by
+I<left>, I<top>, I<right>, I<bottom>, while I<row>, I<col> identify
+the new location of the block.  The cells left empty as a result of
+the move are filled with the character I<char> and attribute I<attr>.
+Optionally you can specify a clipping region with I<cleft>, I<ctop>,
+I<cright>, I<cbottom>, so that the content of the console outside this
+rectangle are unchanged.  Returns C<undef> on errors, a nonzero value
+on success.
+
+Example:
+
+    # scrolls the screen 10 lines down, filling with black spaces
+    $CONSOLE->Scroll(0, 0, 80, 25, 0, 10, " ", $FG_BLACK | $BG_BLACK);
+
+=item Select standard_handle
+
+Redirects a standard handle to the specified console.
+I<standard_handle> can have one of the following values:
+
+    STD_INPUT_HANDLE
+    STD_OUTPUT_HANDLE
+    STD_ERROR_HANDLE
+
+Returns C<undef> on errors, a nonzero value on success.
+
+Example:
+
+    $CONSOLE->Select(STD_OUTPUT_HANDLE);
+
+=item Size [col, row]
+
+Gets or sets the console buffer size.
+
+Example:
+
+    ($x, $y) = $CONSOLE->Size();
+    $CONSOLE->Size(80, 25);
+
+=item Title [title]
+
+Gets or sets the title bar the string of the current console window.
+
+Example:
+
+    $title = $CONSOLE->Title();
+    $CONSOLE->Title("This is a title");
+
+=item Window [flag, left, top, right, bottom]
+
+Gets or sets the current console window size.  If called without
+arguments, returns a 4-element list containing the current window
+coordinates in the form of I<left>, I<top>, I<right>, I<bottom>.  To
+set the window size, you have to specify an additional I<flag>
+parameter: if it is 0 (zero), coordinates are considered relative to
+the current coordinates; if it is non-zero, coordinates are absolute.
+
+Example:
+
+    ($left, $top, $right, $bottom) = $CONSOLE->Window();
+    $CONSOLE->Window(1, 0, 0, 80, 50);
+
+=item Write string
+
+Writes I<string> on the console, using the current attribute, that you
+can set with C<Attr>, and advancing the cursor as needed.  This isn't
+so different from Perl's "print" statement.  Returns the number of
+characters written or C<undef> on errors.  See also: C<WriteAttr>,
+C<WriteChar>, C<WriteRect>.
+
+Example:
+
+    $CONSOLE->Write("Hello, world!");
+
+=item WriteAttr attrs, col, row
+
+Writes the attributes in the string I<attrs>, beginning at I<col>,
+I<row>, without affecting the characters that are on screen.  The
+string attrs can be the result of a C<ReadAttr> function, or you can
+build your own attribute string; in this case, keep in mind that every
+attribute is treated as a character, not a number (see example).
+Returns the number of attributes written or C<undef> on errors.  See
+also: C<Write>, C<WriteChar>, C<WriteRect>.
+
+Example:
+
+    $CONSOLE->WriteAttr($attrs, 0, 0);
+
+    # note the use of chr()...
+    $attrs = chr($FG_BLACK | $BG_WHITE) x 80;
+    $CONSOLE->WriteAttr($attrs, 0, 0);
+
+=item WriteChar chars, col, row
+
+Writes the characters in the string I<attr>, beginning at I<col>, I<row>,
+without affecting the attributes that are on screen.  The string I<chars>
+can be the result of a C<ReadChar> function, or a normal string.  Returns
+the number of characters written or C<undef> on errors.  See also:
+C<Write>, C<WriteAttr>, C<WriteRect>.
+
+Example:
+
+    $CONSOLE->WriteChar("Hello, worlds!", 0, 0);
+
+=item WriteInput (event)
+
+Pushes data in the console input buffer.  I<(event)> is a list of values,
+for more information see C<Input>.  The string chars can be the result of
+a C<ReadChar> function, or a normal string.  Returns the number of
+characters written or C<undef> on errors.  See also: C<Write>,
+C<WriteAttr>, C<WriteRect>.
+
+Example:
+
+    $CONSOLE->WriteInput(@event);
+
+=item WriteRect rect, left, top, right, bottom
+
+Writes a rectangle of characters and attributes (contained in I<rect>)
+on the console at the coordinates specified by I<left>, I<top>,
+I<right>, I<bottom>.  I<rect> can be the result of a C<ReadRect>
+function.  Returns C<undef> on errors, otherwise a 4-element list
+containing the coordinates of the affected rectangle, in the format
+I<left>, I<top>, I<right>, I<bottom>.  See also: C<Write>,
+C<WriteAttr>, C<WriteChar>.
+
+Example:
+
+    $CONSOLE->WriteRect($rect, 0, 0, 80, 25);
+
+=back
+
+
+=head2 Constants
+
+The following constants are exported in the main namespace of your
+script using Win32::Console:
+
+    BACKGROUND_BLUE
+    BACKGROUND_GREEN
+    BACKGROUND_INTENSITY
+    BACKGROUND_RED
+    CAPSLOCK_ON
+    CONSOLE_TEXTMODE_BUFFER
+    ENABLE_ECHO_INPUT
+    ENABLE_LINE_INPUT
+    ENABLE_MOUSE_INPUT
+    ENABLE_PROCESSED_INPUT
+    ENABLE_PROCESSED_OUTPUT
+    ENABLE_WINDOW_INPUT
+    ENABLE_WRAP_AT_EOL_OUTPUT
+    ENHANCED_KEY
+    FILE_SHARE_READ
+    FILE_SHARE_WRITE
+    FOREGROUND_BLUE
+    FOREGROUND_GREEN
+    FOREGROUND_INTENSITY
+    FOREGROUND_RED
+    LEFT_ALT_PRESSED
+    LEFT_CTRL_PRESSED
+    NUMLOCK_ON
+    GENERIC_READ
+    GENERIC_WRITE
+    RIGHT_ALT_PRESSED
+    RIGHT_CTRL_PRESSED
+    SCROLLLOCK_ON
+    SHIFT_PRESSED
+    STD_INPUT_HANDLE
+    STD_OUTPUT_HANDLE
+    STD_ERROR_HANDLE
+
+Additionally, the following variables can be used:
+
+    $FG_BLACK
+    $FG_BLUE
+    $FG_LIGHTBLUE
+    $FG_RED
+    $FG_LIGHTRED
+    $FG_GREEN
+    $FG_LIGHTGREEN
+    $FG_MAGENTA
+    $FG_LIGHTMAGENTA
+    $FG_CYAN
+    $FG_LIGHTCYAN
+    $FG_BROWN
+    $FG_YELLOW
+    $FG_GRAY
+    $FG_WHITE
+
+    $BG_BLACK
+    $BG_BLUE
+    $BG_LIGHTBLUE
+    $BG_RED
+    $BG_LIGHTRED
+    $BG_GREEN
+    $BG_LIGHTGREEN
+    $BG_MAGENTA
+    $BG_LIGHTMAGENTA
+    $BG_CYAN
+    $BG_LIGHTCYAN
+    $BG_BROWN
+    $BG_YELLOW
+    $BG_GRAY
+    $BG_WHITE
+
+    $ATTR_NORMAL
+    $ATTR_INVERSE
+
+ATTR_NORMAL is set to gray foreground on black background (DOS's
+standard colors).
+
+
+=head2 Microsoft's Documentation
+
+Documentation for the Win32 Console and Character mode Functions can
+be found on Microsoft's site at this URL:
+
+http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/sys/src/conchar.htm
+
+A reference of the available functions is at:
+
+http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/sys/src/conchar_34.htm
+
+
+=head1 VERSION HISTORY
+
+=over
+
+=item * 0.031 (24 Sep 1999)
+
+=over
+
+=item *
+
+Fixed typo in GenerateCtrlEvent().
+
+=item *
+
+Converted and added pod documentation (from Jan Dubois <jand@activestate.com>).
+
+=back
+
+=item * 0.03 (07 Apr 1997)
+
+=over
+
+=item *
+
+Added "GenerateCtrlEvent" method.
+
+=item *
+
+The PLL file now comes in 2 versions, one for Perl version 5.001
+(build 110) and one for Perl version 5.003 (build 300 and higher,
+EXCEPT 304).
+
+=item *
+
+added an installation program that will automatically copy the right
+version in the right place.
+
+=back
+
+=item * 0.01 (09 Feb 1997)
+
+=over
+
+=item *
+
+First public release.
+
+=back
+
+=back
+
+
+=head1 AUTHOR
+
+Aldo Calpini <a.calpini@romagiubileo.it>
+
+
+=head1 CREDITS
+
+Thanks to: Jesse Dougherty, Dave Roth, ActiveWare, and the
+Perl-Win32-Users community.
+
+
+=head1 DISCLAIMER
+
+This program is FREE; you can redistribute, modify, disassemble, or
+even reverse engineer this software at your will.  Keep in mind,
+however, that NOTHING IS GUARANTEED to work and everything you do is
+AT YOUR OWN RISK - I will not take responsibility for any damage, loss
+of money and/or health that may arise from the use of this program!
+
+This is distributed under the terms of Larry Wall's Artistic License.
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/DBIODBC.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/DBIODBC.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/DBIODBC.pm	(revision 14139)
@@ -0,0 +1,248 @@
+package			# hide this package from CPAN indexer
+	Win32::ODBC;
+
+#use strict;
+
+use DBI;
+
+# once we've been loaded we don't want perl to load the real Win32::ODBC
+$INC{'Win32/ODBC.pm'} = $INC{'Win32/DBIODBC.pm'} || 1;
+
+#my $db = new Win32::ODBC("DSN=$self->{'DSN'};UID=$self->{'UID'};PWD=$self->{'PWD'};");
+
+#EMU --- my $db = new Win32::ODBC("DSN=$DSN;UID=$login;PWD=$password;");
+sub new
+{
+	shift;
+	my $connect_line= shift;
+
+# [R] self-hack to allow empty UID and PWD
+	my $temp_connect_line;
+	$connect_line=~/DSN=\w+/;
+	$temp_connect_line="$&;";
+	if ($connect_line=~/UID=\w?/)
+		{$temp_connect_line.="$&;";}
+	else	{$temp_connect_line.="UID=;";};
+	if ($connect_line=~/PWD=\w?/)
+		{$temp_connect_line.="$&;";}
+	else	{$temp_connect_line.="PWD=;";};
+	$connect_line=$temp_connect_line;
+# -[R]-
+	
+	my $self= {};
+		
+	
+	$_=$connect_line;
+ 	/^(DSN=)(.*)(;UID=)(.*)(;PWD=)(.*)(;)$/;
+
+ 	#---- DBI CONNECTION VARIABLES
+
+ 	$self->{ODBC_DSN}=$2;
+ 	$self->{ODBC_UID}=$4;
+ 	$self->{ODBC_PWD}=$6;
+	
+	
+	#---- DBI CONNECTION VARIABLES	
+	$self->{DBI_DBNAME}=$self->{ODBC_DSN};
+	$self->{DBI_USER}=$self->{ODBC_UID};
+	$self->{DBI_PASSWORD}=$self->{ODBC_PWD};
+	$self->{DBI_DBD}='ODBC';
+        	
+	#---- DBI CONNECTION
+	$self->{'DBI_DBH'}=DBI->connect($self->{'DBI_DBNAME'},
+			$self->{'DBI_USER'},$self->{'DBI_PASSWORD'},$self->{'DBI_DBD'});
+
+	warn "Error($DBI::err) : $DBI::errstr\n" if ! $self->{'DBI_DBH'}; 
+
+        
+	#---- RETURN 
+	
+	bless $self;
+}
+
+
+#EMU --- $db->Sql('SELECT * FROM DUAL');
+sub Sql
+{
+ 	my $self= shift;
+ 	my $SQL_statment=shift;
+
+ #	print " SQL : $SQL_statment \n";
+	
+	$self->{'DBI_SQL_STATMENT'}=$SQL_statment;
+	
+	my $dbh=$self->{'DBI_DBH'};
+
+ #	print " DBH : $dbh \n";
+	
+	my $sth=$dbh->prepare("$SQL_statment");
+	
+ #	print " STH : $sth \n";
+	
+	$self->{'DBI_STH'}=$sth;
+	
+	if ($sth)
+	{
+		$sth->execute();
+	}
+	
+	#--- GET ERROR MESSAGES
+	$self->{DBI_ERR}=$DBI::err;
+	$self->{DBI_ERRSTR}=$DBI::errstr;
+
+	if ($sth)
+	{
+		#--- GET COLUMNS NAMES
+		$self->{'DBI_NAME'} = $sth->{NAME};
+	}
+
+# [R] provide compatibility with Win32::ODBC's way of identifying erraneous SQL statements
+ 	return ($self->{'DBI_ERR'})?1:undef;
+# -[R]-
+}
+ 
+
+#EMU --- $db->FetchRow())
+sub FetchRow
+{ 
+ 	my $self= shift;
+ 	
+ 	my $sth=$self->{'DBI_STH'};
+ 	if ($sth)
+	{
+	 	my @row=$sth->fetchrow_array;
+	 	$self->{'DBI_ROW'}=\@row;
+
+	 	if (scalar(@row)>0)
+	 	{
+			#-- the row of result is not nul
+			#-- return somthing nothing will be return else
+			return 1;
+	 	} 	
+	}
+	return undef;
+} 
+
+# [R] provide compatibility with Win32::ODBC's Data() method.
+sub Data
+{
+	my $self=shift;
+	my @array=@{$self->{'DBI_ROW'}};
+	foreach my $element (@array)
+	{
+		# remove padding of spaces by DBI
+		$element=~s/(\s*$)//;
+	};
+	return (wantarray())?@array:join('', @array);
+};
+# -[R]-
+ 
+#EMU --- %record = $db->DataHash;
+sub DataHash
+{ 
+ 	my $self= shift;
+ 	 	
+ 	my $p_name=$self->{'DBI_NAME'};
+ 	my $p_row=$self->{'DBI_ROW'};
+
+ 	my @name=@$p_name;
+ 	my @row=@$p_row;
+
+ 	my %DataHash;
+#print @name; print "\n"; print @row;
+# [R] new code that seems to work consistent with Win32::ODBC
+	while (@name)
+	{
+		my $name=shift(@name);
+		my $value=shift(@row);
+
+		# remove padding of spaces by DBI
+		$name=~s/(\s*$)//;
+		$value=~s/(\s*$)//;
+
+		$DataHash{$name}=$value;
+	};
+# -[R]-
+
+# [R] old code that didn't appear to work
+#	foreach my $name (@name)
+#	{
+#		$name=~s/(^\s*)|(\s*$)//;
+#		my @arr=@$name;
+#		foreach (@arr)
+#		{
+#			print "lot $name  name  col $_   or ROW= 0 $row[0]  1 $row[1] 2 $row[2] \n ";
+#			$DataHash{$name}=shift(@row);
+#		}
+#	}
+# -[R]-
+
+ 	#--- Return Hash
+ 	return %DataHash; 	
+} 
+
+
+#EMU --- $db->Error()
+sub Error
+{ 
+ 	my $self= shift;
+ 	 	
+ 	if ($self->{'DBI_ERR'} ne '')
+ 	{
+		#--- Return error message
+		$self->{'DBI_ERRSTR'};
+ 	}
+
+ 	#-- else good no error message 	
+ 	
+}
+
+# [R] provide compatibility with Win32::ODBC's Close() method.
+sub Close
+{
+	my $self=shift;
+
+	my $dbh=$self->{'DBI_DBH'};
+	$dbh->disconnect;
+}
+# -[R]-
+
+1;
+
+__END__
+
+# [R] to -[R]- indicate sections edited by me, Roy Lee
+
+=head1 NAME
+
+Win32::DBIODBC - Win32::ODBC emulation layer for the DBI
+
+=head1 SYNOPSIS
+
+  use Win32::DBIODBC;     # instead of use Win32::ODBC
+
+=head1 DESCRIPTION
+
+This is a I<very> basic I<very> alpha quality Win32::ODBC emulation
+for the DBI. To use it just replace
+
+	use Win32::ODBC;
+
+in your scripts with
+
+	use Win32::DBIODBC;
+
+or, while experimenting, you can pre-load this module without changing your
+scripts by doing
+
+	perl -MWin32::DBIODBC your_script_name
+
+=head1 TO DO
+
+Error handling is virtually non-existant.
+
+=head1 AUTHOR
+
+Tom Horen <tho@melexis.com>
+
+=cut
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Event.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Event.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Event.pm	(revision 14139)
@@ -0,0 +1,103 @@
+#---------------------------------------------------------------------
+package Win32::Event;
+#
+# Copyright 1998 Christopher J. Madsen
+#
+# Author: Christopher J. Madsen <chris_madsen@geocities.com>
+# Created: 3 Feb 1998 from the ActiveWare version
+# Version: 1.00 (6-Feb-1998)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the same terms as Perl itself.
+#
+# 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 either the
+# GNU General Public License or the Artistic License for more details.
+#
+# Use Win32 event objects for synchronization
+#---------------------------------------------------------------------
+
+$VERSION = '1.01';
+
+use Win32::IPC 1.00 '/./';      # Import everything
+require Exporter;
+require DynaLoader;
+
+@ISA = qw(Exporter DynaLoader Win32::IPC);
+@EXPORT_OK = qw(
+  wait_all wait_any INFINITE
+);
+
+bootstrap Win32::Event;
+
+1;
+__END__
+
+=head1 NAME
+
+Win32::Event - Use Win32 event objects from Perl
+
+=head1 SYNOPSIS
+
+	use Win32::Event;
+
+	$event = Win32::Event->new($manual,$initial,$name);
+	$event->wait();
+
+=head1 DESCRIPTION
+
+This module allows access to the Win32 event objects.  The C<wait>
+method and C<wait_all> & C<wait_any> functions are inherited from the
+L<"Win32::IPC"> module.
+
+=head2 Methods
+
+=over 4
+
+=item $event = Win32::Event->new([$manual, [$initial, [$name]]])
+
+Constructor for a new event object.  If C<$manual> is true, you must
+manually reset the event after it is signalled (the default is false).
+If C<$initial> is true, the initial state of the object is signalled
+(default false).  If C<$name> is omitted, creates an unnamed event
+object.
+
+If C<$name> signifies an existing event object, then C<$manual> and
+C<$initial> are ignored and the object is opened.
+
+=item $event = Win32::Event->open($name)
+
+Constructor for opening an existing event object.
+
+=item $event->pulse
+
+Signal the C<$event> and then immediately reset it.  If C<$event> is a
+manual-reset event, releases all threads currently blocking on it.  If
+it's an auto-reset event, releases just one thread.
+
+If no threads are waiting, just resets the event.
+
+=item $event->reset
+
+Reset the C<$event> to nonsignalled.
+
+=item $event->set
+
+Set the C<$event> to signalled.
+
+=item $event->wait([$timeout])
+
+Wait for C<$event> to be signalled.  See L<"Win32::IPC">.
+
+=back
+
+=head1 AUTHOR
+
+Christopher J. Madsen E<lt>F<chris_madsen@geocities.com>E<gt>
+
+=cut
+
+# Local Variables:
+# tmtrack-file-task: "Win32::Event"
+# End:
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/EventLog.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/EventLog.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/EventLog.pm	(revision 14139)
@@ -0,0 +1,471 @@
+#
+# EventLog.pm
+#
+# Creates an object oriented interface to the Windows NT Evenlog
+# Written by Jesse Dougherty
+#
+
+package Win32::EventLog;
+
+use strict;
+use vars qw($VERSION $AUTOLOAD @ISA @EXPORT $GetMessageText);
+$VERSION = '0.074';
+
+require Exporter;
+require DynaLoader;
+
+die "The Win32::Eventlog module works only on Windows NT"
+	unless Win32::IsWinNT();
+
+@ISA= qw(Exporter DynaLoader);
+@EXPORT = qw(
+	EVENTLOG_AUDIT_FAILURE
+	EVENTLOG_AUDIT_SUCCESS
+	EVENTLOG_BACKWARDS_READ
+	EVENTLOG_END_ALL_PAIRED_EVENTS
+	EVENTLOG_END_PAIRED_EVENT
+	EVENTLOG_ERROR_TYPE
+	EVENTLOG_FORWARDS_READ
+	EVENTLOG_INFORMATION_TYPE
+	EVENTLOG_PAIRED_EVENT_ACTIVE
+	EVENTLOG_PAIRED_EVENT_INACTIVE
+	EVENTLOG_SEEK_READ
+	EVENTLOG_SEQUENTIAL_READ
+	EVENTLOG_START_PAIRED_EVENT
+	EVENTLOG_SUCCESS
+	EVENTLOG_WARNING_TYPE
+);
+
+$GetMessageText=0;
+
+sub AUTOLOAD {
+    my($constname);
+    ($constname = $AUTOLOAD) =~ s/.*:://;
+    # reset $! to zero to reset any current errors.
+    local $! = 0;
+    my $val = constant($constname, @_ ? $_[0] : 0);
+    if ($!) {
+	if ($! =~ /Invalid/) {
+	    $AutoLoader::AUTOLOAD = $AUTOLOAD;
+	    goto &AutoLoader::AUTOLOAD;
+	}
+	else {
+	    my ($pack,$file,$line) = caller;
+	    die "Unknown Win32::EventLog macro $constname, at $file line $line.\n";
+	}
+    }
+    eval "sub $AUTOLOAD { $val }";
+    goto &$AUTOLOAD;
+}
+
+#
+# new()
+#
+#   Win32::EventLog->new("source name", "ServerName");
+#
+sub new {
+    die "usage: PACKAGE->new(SOURCENAME[, SERVERNAME])\n" unless @_ > 1;
+    my ($class,$source,$server) = @_;
+    my $handle;
+
+    # Create new handle
+    if ($source !~ /\\/) {
+	OpenEventLog($handle, $server, $source);
+    }
+    else {
+	OpenBackupEventLog($handle, $server, $source);
+    }
+    return bless {handle   => $handle,
+                  Source   => $source,
+                  Computer => $server} => $class;
+}
+
+sub DESTROY {shift->Close}
+
+#
+# Open (the rather braindead old way)
+# A variable initialized to empty must be supplied as the first
+# arg, followed by whatever new() takes
+#
+sub Open {
+    $_[0] = Win32::EventLog->new($_[1],$_[2]);
+}
+
+sub OpenBackup {
+    my ($class,$source,$server) = @_;
+    OpenBackupEventLog(my $handle, $server, $source);
+    return bless {handle   => $handle,
+		  Source   => $source,
+		  Computer => $server} => $class;
+}
+
+sub Backup {
+    die " usage: OBJECT->Backup(FILENAME)\n" unless @_ == 2;
+    my ($self,$file) = @_;
+    return BackupEventLog($self->{handle}, $file);
+}
+
+sub Close {
+    my $self = shift;
+    CloseEventLog($self->{handle});
+    $self->{handle} = 0;
+}
+
+# Read
+# Note: the EventInfo arguement requires a hash reference.
+sub Read {
+    my $self = shift;
+
+    die "usage: OBJECT->Read(FLAGS, RECORDOFFSET, HASHREF)\n" unless @_ == 3;
+
+    my ($readflags,$recordoffset) = @_;
+    # The following is stolen shamelessly from Wyt's tests for the registry.
+    my $result = ReadEventLog($self->{handle}, $readflags, $recordoffset,
+			      my $header, my $source, my $computer, my $sid,
+			      my $data, my $strings);
+    my ($length,
+	$reserved,
+	$recordnumber,
+	$timegenerated,
+	$timewritten,
+	$eventid,
+	$eventtype,
+	$numstrings,
+	$eventcategory,
+	$reservedflags,
+	$closingrecordnumber,
+	$stringoffset,
+	$usersidlength,
+	$usersidoffset,
+	$datalength,
+	$dataoffset) = unpack('l6s4l6', $header);
+
+    # make a hash out of the values returned from ReadEventLog.
+    my %h = ( Source              => $source,
+              Computer            => $computer,
+              Length              => $datalength,
+              Category            => $eventcategory,
+              RecordNumber        => $recordnumber,
+              TimeGenerated       => $timegenerated,
+              Timewritten         => $timewritten,
+              EventID             => $eventid,
+              EventType           => $eventtype,
+              ClosingRecordNumber => $closingrecordnumber,
+              User                => $sid,
+              Strings             => $strings,
+              Data                => $data,
+            );
+
+    # get the text message here
+    if ($result and $GetMessageText) {
+	GetEventLogText($source, $eventid, $strings, $numstrings, my $message);
+	$h{Message} = $message;
+    }
+
+    if (ref($_[2]) eq 'HASH') {
+	%{$_[2]} = %h;		# this needed for Read(...,\%foo) case
+    }
+    else {
+	$_[2] = \%h;
+    }
+    return $result;
+}
+
+sub GetMessageText {
+    my $self = shift;
+    local $^W;
+    GetEventLogText($self->{Source},
+		    $self->{EventID},
+		    $self->{Strings},
+		    $self->{Strings} =~ tr/\0/\0/,
+		    my $message);
+
+    $self->{Message} = $message;
+    return $message;
+}
+
+sub Report {
+    die "usage: OBJECT->Report( HASHREF )\n" unless @_ == 2;
+    my ($self,$EventInfo) = @_;
+
+    die "Win32::EventLog::Report requires a hash reference as arg 2\n"
+	unless ref($EventInfo) eq "HASH";
+
+    my $computer = $EventInfo->{Computer} ? $EventInfo->{Computer}
+                                          : $self->{Computer};
+    my $source   = exists($EventInfo->{Source}) ? $EventInfo->{Source}
+                                                : $self->{Source};
+
+    return WriteEventLog($computer, $source, $EventInfo->{EventType},
+			 $EventInfo->{Category}, $EventInfo->{EventID}, 0,
+			 $EventInfo->{Data}, split(/\0/, $EventInfo->{Strings}));
+
+}
+
+sub GetOldest {
+    my $self = shift;
+    die "usage: OBJECT->GetOldest( SCALAREF )\n" unless @_ == 1;
+    return GetOldestEventLogRecord($self->{handle},$_[0]);
+}
+
+sub GetNumber {
+    my $self = shift;
+    die "usage: OBJECT->GetNumber( SCALARREF )\n" unless @_ == 1;
+    return GetNumberOfEventLogRecords($self->{handle}, $_[0]);
+}
+
+sub Clear {
+    my ($self,$file) = @_;
+    die "usage: OBJECT->Clear( FILENAME )\n" unless @_ == 2;
+    return ClearEventLog($self->{handle}, $file);
+}
+
+bootstrap Win32::EventLog;
+
+1;
+__END__
+
+=head1 NAME
+
+Win32::EventLog - Process Win32 Event Logs from Perl
+
+=head1 SYNOPSIS
+
+	use Win32::EventLog
+	$handle=Win32::EventLog->new("Application");
+
+=head1 DESCRIPTION
+
+This module implements most of the functionality available from the
+Win32 API for accessing and manipulating Win32 Event Logs. The access
+to the EventLog routines is divided into those that relate to an
+EventLog object and its associated methods and those that relate other
+EventLog tasks (like adding an EventLog record).
+
+=head1 The EventLog Object and its Methods
+
+The following methods are available to open, read, close and backup
+EventLogs.
+
+=over 4
+
+=item Win32::EventLog->new(SOURCENAME [,SERVERNAME]);
+
+The new() method creates a new EventLog object and returns a handle
+to it. This hande is then used to call the methods below.
+
+The method is overloaded in that if the supplied SOURCENAME
+argument contains one or more literal '\' characters (an illegal
+character in a SOURCENAME), it assumes that you are trying to open
+a backup eventlog and uses SOURCENAME as the backup eventlog to
+open. Note that when opening a backup eventlog, the SERVERNAME
+argument is ignored (as it is in the underlying Win32 API). For
+EventLogs on remote machines, the SOURCENAME parameter must
+therefore be specified as a UNC path.
+
+=item $handle->Backup(FILENAME);
+
+The Backup() method backs up the EventLog represented by $handle. It
+takes a single arguemt, FILENAME. When $handle represents an
+EventLog on a remote machine, FILENAME is filename on the remote
+machine and cannot be a UNC path (i.e you must use F<C:\TEMP\App.EVT>).
+The method will fail if the log file already exists.
+
+=item $handle->Read(FLAGS, OFFSET, HASHREF);
+
+The Read() method read an EventLog entry from the EventLog represented
+by $handle.
+
+=item $handle->Close();
+
+The Close() method closes the EventLog represented by $handle. After
+Close() has been called, any further attempt to use the EventLog
+represented by $handle will fail.
+
+=item $handle->GetOldest(SCALARREF);
+
+The GetOldest() method number of the the oldest EventLog record in
+the EventLog represented by $handle. This is required to correctly
+compute the OFFSET required by the Read() method.
+
+=item $handle->GetNumber(SCALARREF);
+
+The GetNumber() method returns the number of EventLog records in
+the EventLog represented by $handle. The number of the most recent
+record in the EventLog is therefore computed by
+
+	$handle->GetOldest($oldest);
+	$handle->GetNumber($lastRec);
+	$lastRecOffset=$oldest+$lastRec;
+
+=item $handle->Clear(FILENAME);
+
+The Clear() method clears the EventLog represented by $handle.  If
+you provide a non-null FILENAME, the EventLog will be backed up
+into FILENAME before the EventLog is cleared. The method will fail
+if FILENAME is specified and the file refered to exists. Note also
+that FILENAME specifies a file local to the machine on which the
+EventLog resides and cannot be specified as a UNC name.
+
+=item $handle->Report(HASHREF);
+
+The Report() method generates an EventLog entry. The HASHREF should
+contain the following keys:
+
+=over 4
+
+=item C<Computer>
+
+The C<Computer> field specfies which computer you want the EventLog
+entry recorded.  If this key doesn't exist, the server name used to
+create the $handle is used.
+
+=item C<Source>
+
+The C<Source> field specifies the source that generated the EventLog
+entry.  If this key doesn't exist, the source name used to create the
+$handle is used.
+
+=item C<EventType>
+
+The C<EventType> field should be one of the constants
+
+=over 4
+
+=item C<EVENTLOG_ERROR_TYPE>
+
+An Error event is being logged.
+
+=item C<EVENTLOG_WARNING_TYPE>
+
+A Warning event is being logged.
+
+=item C<EVENTLOG_INFORMATION_TYPE>
+
+An Information event is being logged.
+
+=item C<EVENTLOG_AUDIT_SUCCESS>
+
+A Success Audit event is being logged (typically in the Security
+EventLog).
+
+=item C<EVENTLOG_AUDIT_FAILURE>
+
+A Failure Audit event is being logged (typically in the Security
+EventLog).
+
+=back
+
+These constants are exported into the main namespace by default.
+
+=item C<Category>
+
+The C<Category> field can have any value you want. It is specific to
+the particular Source.
+
+=item C<EventID>
+
+The C<EventID> field should contain the ID of the message that this
+event pertains too. This assumes that you have an associated message
+file (indirectly referenced by the field C<Source>).
+
+=item C<Data>
+
+The C<Data> field contains raw data associated with this event.
+
+=item C<Strings>
+
+The C<Strings> field contains the single string that itself contains
+NUL terminated sub-strings. This are used with the EventID to generate
+the message as seen from (for example) the Event Viewer application.
+
+=back
+
+=back
+
+=head1 Other Win32::EventLog functions.
+
+The following functions are part of the Win32::EventLog package but
+are not callable from an EventLog object.
+
+=over 4
+
+=item GetMessageText(HASHREF);
+
+The GetMessageText() function assumes that HASHREF was obtained by
+a call to C<$handle-E<gt>Read()>. It returns the formatted string that
+represents the fully resolved text of the EventLog message (such as
+would be seen in the Windows NT Event Viewer). For convenience, the
+key 'Message' in the supplied HASHREF is also set to the return value
+of this function.
+
+If you set the variable $Win32::EventLog::GetMessageText to 1 then
+each call to C<$handle-E<gt>Read()> will call this function automatically.
+
+=back
+
+=head1 Example 1
+
+The following example illustrates the way in which the EventLog module
+can be used. It opens the System EventLog and reads through it from
+oldest to newest records. For each record from the B<Source> EventLog
+it extracts the full text of the Entry and prints the EventLog message
+text out.
+
+ use Win32::EventLog;
+
+ $handle=Win32::EventLog->new("System", $ENV{ComputerName})
+ 	or die "Can't open Application EventLog\n";
+ $handle->GetNumber($recs)
+ 	or die "Can't get number of EventLog records\n";
+ $handle->GetOldest($base)
+ 	or die "Can't get number of oldest EventLog record\n";
+
+ while ($x < $recs) {
+ 	$handle->Read(EVENTLOG_FORWARDS_READ|EVENTLOG_SEEK_READ,
+ 				  $base+$x,
+ 				  $hashRef)
+ 		or die "Can't read EventLog entry #$x\n";
+ 	if ($hashRef->{Source} eq "EventLog") {
+ 		Win32::EventLog::GetMessageText($hashRef);
+ 		print "Entry $x: $hashRef->{Message}\n";
+ 	}
+ 	$x++;
+ }
+
+=head1 Example 2
+
+To backup and clear the EventLogs on a remote machine, do the following :-
+
+ use Win32::EventLog;
+
+ $myServer="\\\\my-server";	# your servername here.
+ my($date)=join("-", ((split(/\s+/, scalar(localtime)))[0,1,2,4]));
+ my($dest);
+
+ for my $eventLog ("Application", "System", "Security") {
+ 	$handle=Win32::EventLog->new($eventLog, $myServer)
+ 		or die "Can't open Application EventLog on $myServer\n";
+
+ 	$dest="C:\\BackupEventLogs\\$eventLog\\$date.evt";
+	$handle->Backup($dest)
+		or warn "Could not backup and clear the $eventLog EventLog on $myServer ($^E)\n";
+
+	$handle->Close;
+ }
+
+Note that only the Clear method is required. Note also that if the
+file $dest exists, the function will fail.
+
+=head1 BUGS
+
+None currently known.
+
+The test script for 'make test' should be re-written to use the
+EventLog object.
+
+=head1 AUTHOR
+
+Original code by Jesse Dougherty for HiP Communications. Additional
+fixes and updates attributed to Martin Pauley
+<martin.pauley@ulsterbank.ltd.uk>) and Bret Giddings (bret@essex.ac.uk).
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/File.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/File.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/File.pm	(revision 14139)
@@ -0,0 +1,118 @@
+package Win32::File;
+
+#
+# File.pm
+# Written by Douglas_Lankshear@ActiveWare.com
+#
+# subsequent hacks:
+#   Gurusamy Sarathy
+#
+
+$VERSION = '0.05';
+
+require Exporter;
+require DynaLoader;
+
+@ISA= qw( Exporter DynaLoader );
+@EXPORT = qw(
+		ARCHIVE
+		COMPRESSED
+		DIRECTORY
+		HIDDEN
+		NORMAL
+		OFFLINE
+		READONLY
+		SYSTEM
+		TEMPORARY
+	    );
+@EXPORT_OK = qw(GetAttributes SetAttributes);
+
+=head1 NAME
+
+Win32::File - manage file attributes in perl
+
+=head1 SYNOPSIS
+
+	use Win32::File;
+
+=head1 DESCRIPTION
+
+This module offers the retrieval and setting of file attributes.
+
+=head1 Functions
+
+=head2 NOTE
+
+All of the functions return FALSE (0) if they fail, unless otherwise noted.
+The function names are exported into the caller's namespace by request.
+
+=over 10
+
+=item GetAttributes(filename, returnedAttributes)
+
+Gets the attributes of a file or directory. returnedAttributes will be set
+to the OR-ed combination of the filename attributes.
+
+=item SetAttributes(filename, newAttributes)
+
+Sets the attributes of a file or directory. newAttributes must be an OR-ed
+combination of the attributes.
+
+=back
+
+=head1 Constants
+
+The following constants are exported by default.
+
+=over 10
+
+=item ARCHIVE
+
+=item COMPRESSED
+
+=item DIRECTORY
+
+=item HIDDEN
+
+=item NORMAL
+
+=item OFFLINE
+
+=item READONLY
+
+=item SYSTEM
+
+=item TEMPORARY
+
+=back
+
+=cut
+
+sub AUTOLOAD 
+{
+    my($constname);
+    ($constname = $AUTOLOAD) =~ s/.*:://;
+    #reset $! to zero to reset any current errors.
+    local $! = 0;
+    my $val = constant($constname);
+    if($! != 0)
+	{
+		if($! =~ /Invalid/)
+		{
+			$AutoLoader::AUTOLOAD = $AUTOLOAD;
+			goto &AutoLoader::AUTOLOAD;
+		}
+		else 
+		{
+			($pack,$file,$line) = caller;
+			die "Your vendor has not defined Win32::File macro $constname, used in $file at line $line.";
+		}
+    }
+    eval "sub $AUTOLOAD { $val }";
+    goto &$AUTOLOAD;
+}
+
+bootstrap Win32::File;
+
+1;
+__END__
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/FileSecurity.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/FileSecurity.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/FileSecurity.pm	(revision 14139)
@@ -0,0 +1,307 @@
+package Win32::FileSecurity;
+
+#
+# FileSecurity.pm
+# By Monte Mitzelfelt, monte@conchas.nm.org
+# Larry Wall's Artistic License applies to all related Perl
+#  and C code for this module
+# Thanks to the guys at ActiveWare!
+# ver 0.67 ALPHA 1997.07.07
+#
+
+require Exporter;
+require DynaLoader;
+use Carp ;
+
+$VERSION = '1.04';
+
+croak "The Win32::FileSecurity module works only on Windows NT" if (!Win32::IsWinNT()) ;
+
+@ISA= qw( Exporter DynaLoader );
+
+require Exporter ;
+require DynaLoader ;
+
+@ISA = qw(Exporter DynaLoader) ;
+@EXPORT_OK = qw(
+	Get
+	Set
+	EnumerateRights
+	MakeMask
+	DELETE
+	READ_CONTROL
+	WRITE_DAC
+	WRITE_OWNER
+	SYNCHRONIZE
+	STANDARD_RIGHTS_REQUIRED
+	STANDARD_RIGHTS_READ
+	STANDARD_RIGHTS_WRITE
+	STANDARD_RIGHTS_EXECUTE
+	STANDARD_RIGHTS_ALL
+	SPECIFIC_RIGHTS_ALL
+	ACCESS_SYSTEM_SECURITY
+	MAXIMUM_ALLOWED
+	GENERIC_READ
+	GENERIC_WRITE
+	GENERIC_EXECUTE
+	GENERIC_ALL
+	F
+	FULL
+	R
+	READ
+	C
+	CHANGE
+	A
+	ADD
+	       ) ;
+
+sub AUTOLOAD {
+    local($constname);
+    ($constname = $AUTOLOAD) =~ s/.*:://;
+    #reset $! to zero to reset any current errors.
+    local $! = 0;
+    $val = constant($constname);
+    if($! != 0) {
+	if($! =~ /Invalid/) {
+	    $AutoLoader::AUTOLOAD = $AUTOLOAD;
+	    goto &AutoLoader::AUTOLOAD;
+	}
+	else {
+	    ($pack,$file,$line) = caller;
+	    die "Your vendor has not defined Win32::FileSecurity macro "
+	       ."$constname, used in $file at line $line.";
+	}
+    }
+    eval "sub $AUTOLOAD { $val }";
+    goto &$AUTOLOAD;
+}
+
+bootstrap Win32::FileSecurity;
+
+1;
+
+__END__
+
+=head1 NAME
+
+Win32::FileSecurity - manage FileSecurity Discretionary Access Control Lists in perl
+
+=head1 SYNOPSIS
+
+	use Win32::FileSecurity;
+
+=head1 DESCRIPTION
+
+This module offers control over the administration of system FileSecurity DACLs.  
+You may want to use Get and EnumerateRights to get an idea of what mask values
+correspond to what rights as viewed from File Manager.
+
+=head1 CONSTANTS
+
+  DELETE, READ_CONTROL, WRITE_DAC, WRITE_OWNER,
+  SYNCHRONIZE, STANDARD_RIGHTS_REQUIRED, 
+  STANDARD_RIGHTS_READ, STANDARD_RIGHTS_WRITE,
+  STANDARD_RIGHTS_EXECUTE, STANDARD_RIGHTS_ALL,
+  SPECIFIC_RIGHTS_ALL, ACCESS_SYSTEM_SECURITY, 
+  MAXIMUM_ALLOWED, GENERIC_READ, GENERIC_WRITE,
+  GENERIC_EXECUTE, GENERIC_ALL, F, FULL, R, READ,
+  C, CHANGE
+
+=head1 FUNCTIONS
+
+=head2 NOTE:
+
+All of the functions return false if they fail, unless otherwise noted.
+Errors returned via $! containing both Win32 GetLastError() and a text message
+indicating Win32 function that failed.
+
+=over 10
+
+=item constant( $name, $set )
+
+Stores the value of named constant $name into $set.
+Same as C<$set = Win32::FileSecurity::NAME_OF_CONSTANT();>.
+
+=item Get( $filename, \%permisshash )
+
+Gets the DACLs of a file or directory.
+
+=item Set( $filename, \%permisshash )
+
+Sets the DACL for a file or directory.
+
+=item EnumerateRights( $mask, \@rightslist )
+
+Turns the bitmask in $mask into a list of strings in @rightslist.
+
+=item MakeMask( qw( DELETE READ_CONTROL ) )
+
+Takes a list of strings representing constants and returns a bitmasked
+integer value.
+
+=back
+
+=head2 %permisshash
+
+Entries take the form $permisshash{USERNAME} = $mask ;
+
+=head1 EXAMPLE1
+
+    # Gets the rights for all files listed on the command line.
+    use Win32::FileSecurity qw(Get EnumerateRights);
+    
+    foreach( @ARGV ) {
+	next unless -e $_ ;
+	if ( Get( $_, \%hash ) ) {
+	    while( ($name, $mask) = each %hash ) {
+		print "$name:\n\t"; 
+		EnumerateRights( $mask, \@happy ) ;
+		print join( "\n\t", @happy ), "\n";
+	    }
+	}
+	else {
+	    print( "Error #", int( $! ), ": $!" ) ;
+	}
+    }
+
+=head1 EXAMPLE2
+
+    # Gets existing DACL and modifies Administrator rights
+    use Win32::FileSecurity qw(MakeMask Get Set);
+    
+    # These masks show up as Full Control in File Manager
+    $file = MakeMask( qw( FULL ) );
+    
+    $dir = MakeMask( qw(
+	    FULL
+	GENERIC_ALL
+    ) );
+    
+    foreach( @ARGV ) {
+	s/\\$//;
+	next unless -e;
+	Get( $_, \%hash ) ;
+	$hash{Administrator} = ( -d ) ? $dir : $file ;
+	Set( $_, \%hash ) ;
+    }
+
+=head1 COMMON MASKS FROM CACLS AND WINFILE
+
+=head2 READ
+
+	MakeMask( qw( FULL ) ); # for files
+	MakeMask( qw( READ GENERIC_READ GENERIC_EXECUTE ) ); # for directories
+
+=head2 CHANGE
+
+	MakeMask( qw( CHANGE ) ); # for files
+	MakeMask( qw( CHANGE GENERIC_WRITE GENERIC_READ GENERIC_EXECUTE ) ); # for directories
+
+=head2 ADD & READ
+
+	MakeMask( qw( ADD GENERIC_READ GENERIC_EXECUTE ) ); # for directories only!
+
+=head2 FULL
+
+	MakeMask( qw( FULL ) ); # for files
+	MakeMask( qw( FULL  GENERIC_ALL ) ); # for directories
+
+=head1 RESOURCES
+
+From Microsoft: check_sd
+	http://premium.microsoft.com/download/msdn/samples/2760.exe
+
+(thanks to Guert Schimmel at Sybase for turning me on to this one)
+
+=head1 VERSION
+
+1.03 ALPHA	97-12-14
+
+=head1 REVISION NOTES
+
+=over 10
+
+=item 1.03 ALPHA 1998.01.11
+
+Imported diffs from 0.67 (parent) version
+
+=item 1.02 ALPHA 1997.12.14
+
+Pod fixes, @EXPORT list additions <gsar@activestate.com>
+
+Fix unitialized vars on unknown ACLs <jmk@exc.bybyte.de>
+
+=item 1.01 ALPHA 1997.04.25
+
+CORE Win32 version imported from 0.66 <gsar@activestate.com>
+
+=item 0.67 ALPHA 1997.07.07
+
+Kludged bug in mapping bits to separate ACE's.  Notably, this screwed
+up CHANGE access by leaving out a delete bit in the
+C<INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE> Access Control Entry.
+
+May need to rethink...
+
+=item 0.66 ALPHA 1997.03.13
+
+Fixed bug in memory allocation check
+
+=item 0.65 ALPHA 1997.02.25
+
+Tested with 5.003 build 303
+
+Added ISA exporter, and @EXPORT_OK
+
+Added F, FULL, R, READ, C, CHANGE as composite pre-built mask names.
+
+Added server\ to keys returned in hash from Get
+
+Made constants and MakeMask case insensitive (I don't know why I did that)
+
+Fixed mask comparison in ListDacl and Enumerate Rights from simple & mask
+to exact bit match ! ( ( x & y ) ^ x ) makes sure all bits in x
+are set in y
+
+Fixed some "wild" pointers
+
+=item 0.60 ALPHA 1996.07.31
+
+Now suitable for file and directory permissions
+
+Included ListDacl.exe in bundle for debugging
+
+Added "intuitive" inheritance for directories, basically functions like FM
+triggered by presence of GENERIC_ rights this may need to change
+
+see EXAMPLE2
+
+Changed from AddAccessAllowedAce to AddAce for control over inheritance
+
+=item 0.51 ALPHA 1996.07.20
+
+Fixed memory allocation bug
+
+=item 0.50 ALPHA 1996.07.29
+
+Base functionality
+
+Using AddAccessAllowedAce
+
+Suitable for file permissions
+
+=back
+
+=head1 KNOWN ISSUES / BUGS
+
+=over 10
+
+=item 1
+
+May not work on remote drives.
+
+=item 2
+
+Errors croak, don't return via $! as documented.
+
+=cut
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/IPC.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/IPC.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/IPC.pm	(revision 14139)
@@ -0,0 +1,178 @@
+#---------------------------------------------------------------------
+package Win32::IPC;
+#
+# Copyright 1998 Christopher J. Madsen
+#
+# Created: 3 Feb 1998 from the ActiveWare version
+#   (c) 1995 Microsoft Corporation. All rights reserved.
+#       Developed by ActiveWare Internet Corp., http://www.ActiveWare.com
+#
+#   Other modifications (c) 1997 by Gurusamy Sarathy <gsar@activestate.com>
+#
+# Author: Christopher J. Madsen <chris_madsen@geocities.com>
+# Version: 1.00 (6-Feb-1998)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the same terms as Perl itself.
+#
+# 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 either the
+# GNU General Public License or the Artistic License for more details.
+#
+# Base class for Win32 synchronization objects
+#---------------------------------------------------------------------
+
+$VERSION = '1.02';
+
+require Exporter;
+require DynaLoader;
+use strict;
+use vars qw($AUTOLOAD $VERSION @ISA @EXPORT @EXPORT_OK);
+
+@ISA = qw(Exporter DynaLoader);
+@EXPORT = qw(
+	INFINITE
+	WaitForMultipleObjects
+);
+@EXPORT_OK = qw(
+  wait_any wait_all
+);
+
+sub AUTOLOAD {
+    # This AUTOLOAD is used to 'autoload' constants from the constant()
+    # XS function.
+    my($constname);
+    ($constname = $AUTOLOAD) =~ s/.*:://;
+    local $! = 0;
+    my $val = constant($constname);
+    if ($! != 0) {
+        my ($pack,$file,$line) = caller;
+        die "Your vendor has not defined Win32::IPC macro $constname, used at $file line $line.";
+    }
+    eval "sub $AUTOLOAD { $val }";
+    goto &$AUTOLOAD;
+} # end AUTOLOAD
+
+bootstrap Win32::IPC;
+
+# How's this for cryptic?  Use wait_any or wait_all!
+sub WaitForMultipleObjects
+{
+    my $result = (($_[1] ? wait_all($_[0], $_[2])
+                   : wait_any($_[0], $_[2]))
+                  ? 1
+                  : 0);
+    @{$_[0]} = (); # Bug for bug compatibility!  Use wait_any or wait_all!
+    $result;
+} # end WaitForMultipleObjects
+
+1;
+__END__
+
+=head1 NAME
+
+Win32::IPC - Base class for Win32 synchronization objects
+
+=head1 SYNOPSIS
+
+    use Win32::Event 1.00 qw(wait_any);
+    #Create objects.
+
+    wait_any(@ListOfObjects,$timeout);
+
+=head1 DESCRIPTION
+
+This module is loaded by the other Win32 synchronization modules.  You
+shouldn't need to load it yourself.  It supplies the wait functions to
+those modules.
+
+The synchronization modules are L<"Win32::ChangeNotify">,
+L<"Win32::Event">, L<"Win32::Mutex">, & L<"Win32::Semaphore">.
+
+=head2 Methods
+
+B<Win32::IPC> supplies one method to all synchronization objects.
+
+=over 4
+
+=item $obj->wait([$timeout])
+
+Waits for C<$obj> to become signalled.  C<$timeout> is the maximum time
+to wait (in milliseconds).  If C<$timeout> is omitted, waits forever.
+If C<$timeout> is 0, returns immediately.
+
+Returns:
+
+   +1    The object is signalled
+   -1    The object is an abandoned mutex
+    0    Timed out
+  undef  An error occurred
+
+=back
+
+=head2 Functions
+
+=over 4
+
+=item wait_any(@objects, [$timeout])
+
+Waits for at least one of the C<@objects> to become signalled.
+C<$timeout> is the maximum time to wait (in milliseconds).  If
+C<$timeout> is omitted, waits forever.  If C<$timeout> is 0, returns
+immediately.
+
+The return value indicates which object ended the wait:
+
+   +N    $object[N-1] is signalled
+   -N    $object[N-1] is an abandoned mutex
+    0    Timed out
+  undef  An error occurred
+
+If more than one object became signalled, the one with the lowest
+index is used.
+
+=item wait_all(@objects, [$timeout])
+
+This is the same as C<wait_any>, but it waits for all the C<@objects>
+to become signalled.  The return value indicates the last object to
+become signalled, and is negative if at least one of the C<@objects>
+is an abandoned mutex.
+
+=back
+
+=head2 Deprecated Functions and Methods
+
+B<Win32::IPC> still supports the ActiveWare syntax, but its use is
+deprecated.
+
+=over 4
+
+=item INFINITE
+
+Constant value for an infinite timeout.  Omit the C<$timeout> argument
+instead.
+
+=item WaitForMultipleObjects(\@objects, $wait_all, $timeout)
+
+Warning: C<WaitForMultipleObjects> erases C<@objects>!
+Use C<wait_all> or C<wait_any> instead.
+
+=item $obj->Wait($timeout)
+
+Similar to C<not $obj-E<gt>wait($timeout)>.
+
+=back
+
+=head1 AUTHOR
+
+Christopher J. Madsen E<lt>F<chris_madsen@geocities.com>E<gt>
+
+Loosely based on the original module by ActiveWare Internet Corp.,
+F<http://www.ActiveWare.com>
+
+=cut
+
+# Local Variables:
+# tmtrack-file-task: "Win32::IPC"
+# End:
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Internet.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Internet.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Internet.pm	(revision 14139)
@@ -0,0 +1,3008 @@
+#######################################################################
+#
+# Win32::Internet - Perl Module for Internet Extensions
+# ^^^^^^^^^^^^^^^
+# This module creates an object oriented interface to the Win32
+# Internet Functions (WININET.DLL).
+#
+# Version: 0.08  (14 Feb 1997)
+# Version: 0.081 (25 Sep 1999)
+# Version: 0.082 (04 Sep 2001)
+#
+#######################################################################
+
+# changes:
+# - fixed 2 bugs in Option(s) related subs
+# - works with build 30x also
+
+package Win32::Internet;
+
+require Exporter;       # to export the constants to the main:: space
+require DynaLoader;     # to dynuhlode the module.
+
+# use Win32::WinError;    # for windows constants.
+
+@ISA= qw( Exporter DynaLoader );
+@EXPORT = qw(
+    HTTP_ADDREQ_FLAG_ADD
+    HTTP_ADDREQ_FLAG_REPLACE
+    HTTP_QUERY_ALLOW
+    HTTP_QUERY_CONTENT_DESCRIPTION
+    HTTP_QUERY_CONTENT_ID
+    HTTP_QUERY_CONTENT_LENGTH
+    HTTP_QUERY_CONTENT_TRANSFER_ENCODING
+    HTTP_QUERY_CONTENT_TYPE
+    HTTP_QUERY_COST
+    HTTP_QUERY_CUSTOM
+    HTTP_QUERY_DATE
+    HTTP_QUERY_DERIVED_FROM
+    HTTP_QUERY_EXPIRES
+    HTTP_QUERY_FLAG_REQUEST_HEADERS
+    HTTP_QUERY_FLAG_SYSTEMTIME
+    HTTP_QUERY_LANGUAGE
+    HTTP_QUERY_LAST_MODIFIED
+    HTTP_QUERY_MESSAGE_ID
+    HTTP_QUERY_MIME_VERSION
+    HTTP_QUERY_PRAGMA
+    HTTP_QUERY_PUBLIC
+    HTTP_QUERY_RAW_HEADERS
+    HTTP_QUERY_RAW_HEADERS_CRLF
+    HTTP_QUERY_REQUEST_METHOD
+    HTTP_QUERY_SERVER
+    HTTP_QUERY_STATUS_CODE
+    HTTP_QUERY_STATUS_TEXT
+    HTTP_QUERY_URI
+    HTTP_QUERY_USER_AGENT
+    HTTP_QUERY_VERSION
+    HTTP_QUERY_WWW_LINK
+    ICU_BROWSER_MODE
+    ICU_DECODE
+    ICU_ENCODE_SPACES_ONLY
+    ICU_ESCAPE
+    ICU_NO_ENCODE
+    ICU_NO_META
+    ICU_USERNAME
+    INTERNET_FLAG_PASSIVE
+    INTERNET_FLAG_ASYNC
+    INTERNET_HYPERLINK
+    INTERNET_FLAG_KEEP_CONNECTION
+    INTERNET_FLAG_MAKE_PERSISTENT
+    INTERNET_FLAG_NO_AUTH
+    INTERNET_FLAG_NO_AUTO_REDIRECT
+    INTERNET_FLAG_NO_CACHE_WRITE
+    INTERNET_FLAG_NO_COOKIES
+    INTERNET_FLAG_READ_PREFETCH
+    INTERNET_FLAG_RELOAD
+    INTERNET_FLAG_RESYNCHRONIZE
+    INTERNET_FLAG_TRANSFER_ASCII
+    INTERNET_FLAG_TRANSFER_BINARY
+    INTERNET_INVALID_PORT_NUMBER
+    INTERNET_INVALID_STATUS_CALLBACK
+    INTERNET_OPEN_TYPE_DIRECT
+    INTERNET_OPEN_TYPE_PROXY
+    INTERNET_OPEN_TYPE_PROXY_PRECONFIG
+    INTERNET_OPTION_CONNECT_BACKOFF
+    INTERNET_OPTION_CONNECT_RETRIES
+    INTERNET_OPTION_CONNECT_TIMEOUT
+    INTERNET_OPTION_CONTROL_SEND_TIMEOUT
+    INTERNET_OPTION_CONTROL_RECEIVE_TIMEOUT
+    INTERNET_OPTION_DATA_SEND_TIMEOUT
+    INTERNET_OPTION_DATA_RECEIVE_TIMEOUT
+    INTERNET_OPTION_HANDLE_SIZE
+    INTERNET_OPTION_LISTEN_TIMEOUT
+    INTERNET_OPTION_PASSWORD
+    INTERNET_OPTION_READ_BUFFER_SIZE
+    INTERNET_OPTION_USER_AGENT
+    INTERNET_OPTION_USERNAME
+    INTERNET_OPTION_VERSION
+    INTERNET_OPTION_WRITE_BUFFER_SIZE
+    INTERNET_SERVICE_FTP
+    INTERNET_SERVICE_GOPHER
+    INTERNET_SERVICE_HTTP
+    INTERNET_STATUS_CLOSING_CONNECTION
+    INTERNET_STATUS_CONNECTED_TO_SERVER    
+    INTERNET_STATUS_CONNECTING_TO_SERVER
+    INTERNET_STATUS_CONNECTION_CLOSED
+    INTERNET_STATUS_HANDLE_CLOSING
+    INTERNET_STATUS_HANDLE_CREATED
+    INTERNET_STATUS_NAME_RESOLVED
+    INTERNET_STATUS_RECEIVING_RESPONSE
+    INTERNET_STATUS_REDIRECT    
+    INTERNET_STATUS_REQUEST_COMPLETE    
+    INTERNET_STATUS_REQUEST_SENT    
+    INTERNET_STATUS_RESOLVING_NAME    
+    INTERNET_STATUS_RESPONSE_RECEIVED
+    INTERNET_STATUS_SENDING_REQUEST    
+);
+
+
+#######################################################################
+# This AUTOLOAD is used to 'autoload' constants from the constant()
+# XS function.  If a constant is not found then control is passed
+# to the AUTOLOAD in AutoLoader.
+#
+
+sub AUTOLOAD {
+    my($constname);
+    ($constname = $AUTOLOAD) =~ s/.*:://;
+    #reset $! to zero to reset any current errors.
+    local $! = 0;
+    my $val = constant($constname, @_ ? $_[0] : 0);
+    if ($! != 0) {
+
+        # [dada] This results in an ugly Autoloader error
+        #if ($! =~ /Invalid/) {
+        #  $AutoLoader::AUTOLOAD = $AUTOLOAD;
+        #  goto &AutoLoader::AUTOLOAD;
+        #} else {
+      
+        # [dada] ... I prefer this one :)
+  
+            ($pack,$file,$line) = caller; undef $pack;
+            die "Win32::Internet::$constname is not defined, used at $file line $line.";
+  
+        #}
+    }
+    eval "sub $AUTOLOAD { $val }";
+    goto &$AUTOLOAD;
+}
+
+
+#######################################################################
+# STATIC OBJECT PROPERTIES
+#
+$VERSION = "0.082";
+
+%callback_code = ();
+%callback_info = ();
+
+
+#######################################################################
+# PUBLIC METHODS
+#
+
+#======== ### CLASS CONSTRUCTOR
+sub new {
+#========
+    my($class, $useragent, $opentype, $proxy, $proxybypass, $flags) = @_;
+    my $self = {};  
+
+    if(ref($useragent) and ref($useragent) eq "HASH") {
+        $opentype       = $useragent->{'opentype'};
+        $proxy          = $useragent->{'proxy'};
+        $proxybypass    = $useragent->{'proxybypass'};
+        $flags          = $useragent->{'flags'};
+        my $myuseragent = $useragent->{'useragent'};
+        undef $useragent;
+        $useragent      = $myuseragent;
+    }
+
+    $useragent = "Perl-Win32::Internet/".$VERSION       unless defined($useragent);
+    $opentype = constant("INTERNET_OPEN_TYPE_DIRECT",0) unless defined($opentype);
+    $proxy = ""                                         unless defined($proxy);
+    $proxybypass = ""                                   unless defined($proxybypass);
+    $flags = 0                                          unless defined($flags);
+
+
+    my $handle = InternetOpen($useragent, $opentype, $proxy, $proxybypass, $flags);
+    if ($handle) {
+        $self->{'connections'} = 0;
+        $self->{'pasv'}        = 0;
+        $self->{'handle'}      = $handle; 
+        $self->{'useragent'}   = $useragent;
+        $self->{'proxy'}       = $proxy;
+        $self->{'proxybypass'} = $proxybypass;
+        $self->{'flags'}       = $flags;
+        $self->{'Type'}        = "Internet";
+    
+        # [dada] I think it's better to call SetStatusCallback explicitly...
+        #if($flags & constant("INTERNET_FLAG_ASYNC",0)) {
+        #  my $callbackresult=InternetSetStatusCallback($handle);
+        #  if($callbackresult==&constant("INTERNET_INVALID_STATUS_CALLBACK",0)) {
+        #    $self->{'Error'} = -2;
+        #  }
+        #}
+
+        bless $self;
+    } else {
+        $self->{'handle'} = undef;
+        bless $self;
+    }
+    $self;
+}  
+
+
+#============
+sub OpenURL {
+#============
+    my($self,$new,$URL) = @_;
+    return undef unless ref($self);
+
+    my $newhandle=InternetOpenUrl($self->{'handle'},$URL,"",0,0,0);
+    if(!$newhandle) {
+        $self->{'Error'} = "Cannot open URL.";
+        return undef;
+    } else {
+        $self->{'connections'}++;
+        $_[1] = _new($newhandle);
+        $_[1]->{'Type'} = "URL";
+        $_[1]->{'URL'}  = $URL;
+        return $newhandle;
+    }
+}
+
+
+#================
+sub TimeConvert {
+#================
+    my($self, $sec, $min, $hour, $day, $mon, $year, $wday, $rfc) = @_;
+    return undef unless ref($self);
+
+    if(!defined($rfc)) {
+        return InternetTimeToSystemTime($sec);
+    } else {
+        return InternetTimeFromSystemTime($sec, $min, $hour, 
+                                          $day, $mon, $year, 
+                                          $wday, $rfc);
+    }
+}
+
+
+#=======================
+sub QueryDataAvailable {
+#=======================
+    my($self) = @_;
+    return undef unless ref($self);
+  
+    return InternetQueryDataAvailable($self->{'handle'});
+}
+
+
+#=============
+sub ReadFile {
+#=============
+    my($self, $buffersize) = @_;
+    return undef unless ref($self);
+
+    my $howmuch = InternetQueryDataAvailable($self->{'handle'});
+    $buffersize = $howmuch unless defined($buffersize);
+    return InternetReadFile($self->{'handle'}, ($howmuch<$buffersize) ? $howmuch 
+                                                                      : $buffersize);
+}
+
+
+#===================
+sub ReadEntireFile {
+#===================
+    my($handle) = @_;
+    my $content    = "";
+    my $buffersize = 16000;
+    my $howmuch    = 0;
+    my $buffer     = "";
+
+    $handle = $handle->{'handle'} if defined($handle) and ref($handle);
+
+    $howmuch = InternetQueryDataAvailable($handle);
+    # print "\nReadEntireFile: $howmuch bytes to read...\n";
+  
+    while($howmuch>0) {
+        $buffer = InternetReadFile($handle, ($howmuch<$buffersize) ? $howmuch 
+                                                                   : $buffersize);
+        # print "\nReadEntireFile: ", length($buffer), " bytes read...\n";
+    
+        if(!defined($buffer)) {
+            return undef;
+        } else {
+            $content .= $buffer;
+        }
+        $howmuch = InternetQueryDataAvailable($handle);
+        # print "\nReadEntireFile: still $howmuch bytes to read...\n";
+    
+    }
+    return $content;
+}
+
+
+#=============
+sub FetchURL {
+#=============
+    # (OpenURL+Read+Close)...
+    my($self, $URL) = @_;
+    return undef unless ref($self);
+
+    my $newhandle = InternetOpenUrl($self->{'handle'}, $URL, "", 0, 0, 0);
+    if(!$newhandle) {
+        $self->{'Error'} = "Cannot open URL.";
+        return undef;
+    } else {
+        my $content = ReadEntireFile($newhandle);
+        InternetCloseHandle($newhandle);
+        return $content;
+    }
+}
+
+
+#================
+sub Connections {
+#================
+    my($self) = @_;
+    return undef unless ref($self);
+
+    return $self->{'connections'} if $self->{'Type'} eq "Internet";
+    return undef;
+}
+
+
+#================
+sub GetResponse {
+#================
+    my($num, $text) = InternetGetLastResponseInfo();
+    return $text;
+}
+
+#===========
+sub Option {
+#===========
+    my($self, $option, $value) = @_;
+    return undef unless ref($self);
+
+    my $retval = 0;
+
+    $option = constant("INTERNET_OPTION_USER_AGENT", 0) unless defined($option);
+  
+    if(!defined($value)) {
+        $retval = InternetQueryOption($self->{'handle'}, $option);
+    } else {
+        $retval = InternetSetOption($self->{'handle'}, $option, $value);
+    }
+    return $retval;
+}
+
+
+#==============
+sub UserAgent {
+#==============
+    my($self, $value) = @_;
+    return undef unless ref($self);
+
+    return Option($self, constant("INTERNET_OPTION_USER_AGENT", 0), $value);
+}
+
+
+#=============
+sub Username {
+#=============
+    my($self, $value) = @_;
+    return undef unless ref($self);
+  
+    if($self->{'Type'} ne "HTTP" and $self->{'Type'} ne "FTP") {
+        $self->{'Error'} = "Username() only on FTP or HTTP sessions.";
+        return undef;
+    }
+
+    return Option($self, constant("INTERNET_OPTION_USERNAME", 0), $value);
+}
+
+
+#=============
+sub Password {
+#=============
+    my($self, $value)=@_;
+    return undef unless ref($self);
+
+    if($self->{'Type'} ne "HTTP" and $self->{'Type'} ne "FTP") {
+        $self->{'Error'} = "Password() only on FTP or HTTP sessions.";
+        return undef;
+    }
+
+    return Option($self, constant("INTERNET_OPTION_PASSWORD", 0), $value);
+}
+
+
+#===================
+sub ConnectTimeout {
+#===================
+    my($self, $value) = @_;
+    return undef unless ref($self);
+
+    return Option($self, constant("INTERNET_OPTION_CONNECT_TIMEOUT", 0), $value);
+}
+
+
+#===================
+sub ConnectRetries {
+#===================
+    my($self, $value) = @_;
+    return undef unless ref($self);
+
+    return Option($self, constant("INTERNET_OPTION_CONNECT_RETRIES", 0), $value);
+}
+
+
+#===================
+sub ConnectBackoff {
+#===================
+    my($self,$value)=@_;
+    return undef unless ref($self);
+
+    return Option($self, constant("INTERNET_OPTION_CONNECT_BACKOFF", 0), $value);
+}
+
+
+#====================
+sub DataSendTimeout {
+#====================
+    my($self,$value) = @_;
+    return undef unless ref($self);
+
+    return Option($self, constant("INTERNET_OPTION_DATA_SEND_TIMEOUT", 0), $value);
+}
+
+
+#=======================
+sub DataReceiveTimeout {
+#=======================
+    my($self, $value) = @_;
+    return undef unless ref($self);
+
+    return Option($self, constant("INTERNET_OPTION_DATA_RECEIVE_TIMEOUT", 0), $value);
+}
+
+
+#==========================
+sub ControlReceiveTimeout {
+#==========================
+    my($self, $value) = @_;
+    return undef unless ref($self);
+
+    return Option($self, constant("INTERNET_OPTION_CONTROL_RECEIVE_TIMEOUT", 0), $value);
+}
+
+
+#=======================
+sub ControlSendTimeout {
+#=======================
+    my($self, $value) = @_;
+    return undef unless ref($self);
+
+    return Option($self, constant("INTERNET_OPTION_CONTROL_SEND_TIMEOUT", 0), $value);
+}
+
+
+#================
+sub QueryOption {
+#================
+    my($self, $option) = @_;
+    return undef unless ref($self);
+
+    return InternetQueryOption($self->{'handle'}, $option);
+}
+
+
+#==============
+sub SetOption {
+#==============
+    my($self, $option, $value) = @_;
+    return undef unless ref($self);
+
+    return InternetSetOption($self->{'handle'}, $option, $value);
+}
+
+
+#=============
+sub CrackURL {
+#=============
+    my($self, $URL, $flags) = @_;
+    return undef unless ref($self);
+
+    $flags = constant("ICU_ESCAPE", 0) unless defined($flags);
+  
+    my @newurl = InternetCrackUrl($URL, $flags);
+  
+    if(!defined($newurl[0])) {
+        $self->{'Error'} = "Cannot crack URL.";
+        return undef;
+    } else {
+        return @newurl;
+    }
+}
+
+
+#==============
+sub CreateURL {
+#==============
+    my($self, $scheme, $hostname, $port, 
+       $username, $password, 
+       $path, $extrainfo, $flags) = @_;
+    return undef unless ref($self);
+
+    if(ref($scheme) and ref($scheme) eq "HASH") {
+        $flags       = $hostname;
+        $hostname    = $scheme->{'hostname'};
+        $port        = $scheme->{'port'};
+        $username    = $scheme->{'username'};
+        $password    = $scheme->{'password'};
+        $path        = $scheme->{'path'};
+        $extrainfo   = $scheme->{'extrainfo'};
+        my $myscheme = $scheme->{'scheme'};
+        undef $scheme;
+        $scheme      = $myscheme;
+    }
+
+    $hostname  = ""                    unless defined($hostname);
+    $port      = 0                     unless defined($port);
+    $username  = ""                    unless defined($username);
+    $password  = ""                    unless defined($password);
+    $path      = ""                    unless defined($path);
+    $extrainfo = ""                    unless defined($extrainfo);
+    $flags = constant("ICU_ESCAPE", 0) unless defined($flags);
+  
+    my $newurl = InternetCreateUrl($scheme, $hostname, $port,
+                                   $username, $password,
+                                   $path, $extrainfo, $flags);
+    if(!defined($newurl)) {
+        $self->{'Error'} = "Cannot create URL.";
+        return undef;
+    } else {
+        return $newurl;
+    }
+}
+
+
+#====================
+sub CanonicalizeURL {
+#====================
+    my($self, $URL, $flags) = @_;
+    return undef unless ref($self);
+  
+    my $newurl = InternetCanonicalizeUrl($URL, $flags);
+    if(!defined($newurl)) {
+        $self->{'Error'} = "Cannot canonicalize URL.";
+        return undef;
+    } else {
+        return $newurl;
+    }
+}
+
+
+#===============
+sub CombineURL {
+#===============
+    my($self, $baseURL, $relativeURL, $flags) = @_;
+    return undef unless ref($self);
+  
+    my $newurl = InternetCombineUrl($baseURL, $relativeURL, $flags);
+    if(!defined($newurl)) {
+        $self->{'Error'} = "Cannot combine URL(s).";
+        return undef;
+    } else {
+        return $newurl;
+    }
+}
+
+
+#======================
+sub SetStatusCallback {
+#======================
+    my($self) = @_;
+    return undef unless ref($self);
+  
+    my $callback = InternetSetStatusCallback($self->{'handle'});
+    print "callback=$callback, constant=",constant("INTERNET_INVALID_STATUS_CALLBACK", 0), "\n";
+    if($callback == constant("INTERNET_INVALID_STATUS_CALLBACK", 0)) {
+        return undef;
+    } else {
+        return $callback;
+    }
+}
+
+
+#======================
+sub GetStatusCallback {
+#======================
+    my($self, $context) = @_;
+    $context = $self if not defined $context;
+    return($callback_code{$context}, $callback_info{$context});
+}
+
+
+#==========
+sub Error {
+#==========
+    my($self) = @_;
+    return undef unless ref($self);
+  
+    my $errtext = "";
+    my $tmp     = "";
+    my $errnum  = Win32::GetLastError();
+
+    if($errnum < 12000) {
+        $errtext =  Win32::FormatMessage($errnum);
+        $errtext =~ s/[\r\n]//g;
+    } elsif($errnum == 12003) {
+        ($tmp, $errtext) = InternetGetLastResponseInfo();
+        chomp $errtext;
+        1 while($errtext =~ s/(.*)\n//); # the last line should be significative... 
+                                         # otherwise call GetResponse() to get it whole
+    } elsif($errnum >= 12000) {
+        $errtext = FormatMessage($errnum);
+        $errtext =~ s/[\r\n]//g;        
+    } else {
+        $errtext="Error";
+    }
+    if($errnum == 0 and defined($self->{'Error'})) { 
+        if($self->{'Error'} == -2) {
+            $errnum  = -2;
+            $errtext = "Asynchronous operations not available.";
+        } else {
+            $errnum  = -1;
+            $errtext = $self->{'Error'};
+        }
+    }
+    return (wantarray)? ($errnum, $errtext) : "\[".$errnum."\] ".$errtext;
+}
+
+
+#============
+sub Version {
+#============
+    my $dll =  InternetDllVersion();
+       $dll =~ s/\0//g;
+    return (wantarray)? ($Win32::Internet::VERSION,    $dll) 
+                      :  $Win32::Internet::VERSION."/".$dll;
+}
+
+
+#==========
+sub Close {
+#==========
+    my($self, $handle) = @_;
+    if(!defined($handle)) {
+        return undef unless ref($self);
+        $handle = $self->{'handle'};
+    }
+    InternetCloseHandle($handle);
+}
+
+
+
+#######################################################################
+# FTP CLASS METHODS
+#
+
+#======== ### FTP CONSTRUCTOR
+sub FTP {
+#========
+    my($self, $new, $server, $username, $password, $port, $pasv, $context) = @_;    
+    return undef unless ref($self);
+
+    if(ref($server) and ref($server) eq "HASH") {
+        $port        = $server->{'port'};
+        $username    = $server->{'username'};
+        $password    = $password->{'host'};
+        my $myserver = $server->{'server'};
+        $pasv        = $server->{'pasv'};
+        $context     = $server->{'context'};
+        undef $server;
+        $server      = $myserver;
+    }
+
+    $server   = ""          unless defined($server);
+    $username = "anonymous" unless defined($username);
+    $password = ""          unless defined($password);
+    $port     = 21          unless defined($port);
+    $context  = 0           unless defined($context);
+
+    $pasv = $self->{'pasv'} unless defined $pasv;
+    $pasv = $pasv ? constant("INTERNET_FLAG_PASSIVE",0) : 0;
+
+    my $newhandle = InternetConnect($self->{'handle'}, $server, $port,
+                                    $username, $password,
+                                    constant("INTERNET_SERVICE_FTP", 0),
+                                    $pasv, $context);
+    if($newhandle) {
+        $self->{'connections'}++;
+        $_[1] = _new($newhandle);
+        $_[1]->{'Type'}     = "FTP";
+        $_[1]->{'Mode'}     = "bin";
+        $_[1]->{'pasv'}     = $pasv;
+        $_[1]->{'username'} = $username;
+        $_[1]->{'password'} = $password;
+        $_[1]->{'server'}   = $server;
+        return $newhandle;
+    } else {
+        return undef;
+    }
+}
+
+#========
+sub Pwd {
+#========
+    my($self) = @_;
+    return undef unless ref($self);
+
+    if($self->{'Type'} ne "FTP" or !defined($self->{'handle'})) {
+        $self->{'Error'} = "Pwd() only on FTP sessions.";
+        return undef;
+    }
+  
+    return FtpGetCurrentDirectory($self->{'handle'});
+}
+
+
+#=======
+sub Cd {
+#=======
+    my($self, $path) = @_;
+    return undef unless ref($self);
+
+    if($self->{'Type'} ne "FTP" || !defined($self->{'handle'})) {
+        $self->{'Error'} = "Cd() only on FTP sessions.";
+        return undef;
+    }
+  
+    my $retval = FtpSetCurrentDirectory($self->{'handle'}, $path);
+    if(!defined($retval)) {
+        return undef;
+    } else {
+        return $path;
+    }
+}
+#====================
+sub Cwd   { Cd(@_); }
+sub Chdir { Cd(@_); }
+#====================
+
+
+#==========
+sub Mkdir {
+#==========
+    my($self, $path) = @_;
+    return undef unless ref($self);
+
+    if($self->{'Type'} ne "FTP" or !defined($self->{'handle'})) {
+        $self->{'Error'} = "Mkdir() only on FTP sessions.";
+        return undef;
+    }
+  
+    my $retval = FtpCreateDirectory($self->{'handle'}, $path);
+    $self->{'Error'} = "Can't create directory." unless defined($retval);
+    return $retval;
+}
+#====================
+sub Md { Mkdir(@_); }
+#====================
+
+
+#=========
+sub Mode {
+#=========
+    my($self, $value) = @_;
+    return undef unless ref($self);
+
+    if($self->{'Type'} ne "FTP" or !defined($self->{'handle'})) {
+        $self->{'Error'} = "Mode() only on FTP sessions.";
+        return undef;
+    }
+  
+    if(!defined($value)) {
+        return $self->{'Mode'};
+    } else {
+        my $modesub = ($value =~ /^a/i) ? "Ascii" : "Binary";
+        $self->$modesub($_[0]);
+    }
+    return $self->{'Mode'};
+}
+
+
+#==========
+sub Rmdir {
+#==========
+    my($self, $path) = @_;
+    return undef unless ref($self);
+
+    if($self->{'Type'} ne "FTP" or !defined($self->{'handle'})) {
+        $self->{'Error'} = "Rmdir() only on FTP sessions.";
+        return undef;
+    }
+    my $retval = FtpRemoveDirectory($self->{'handle'}, $path);
+    $self->{'Error'} = "Can't remove directory." unless defined($retval);
+    return $retval;
+}
+#====================
+sub Rd { Rmdir(@_); }
+#====================
+
+
+#=========
+sub Pasv {
+#=========
+    my($self, $value) = @_;
+    return undef unless ref($self);
+
+    if(defined($value) and $self->{'Type'} eq "Internet") {
+        if($value == 0) {
+            $self->{'pasv'} = 0;
+        } else {
+            $self->{'pasv'} = 1;
+        }
+    }
+    return $self->{'pasv'};
+}
+
+#=========
+sub List {
+#=========
+    my($self, $pattern, $retmode) = @_;
+    return undef unless ref($self);
+
+    my $retval = "";
+    my $size   = ""; 
+    my $attr   = ""; 
+    my $ctime  = ""; 
+    my $atime  = ""; 
+    my $mtime  = "";
+    my $csec = 0; my $cmin = 0; my $chou = 0; my $cday = 0; my $cmon = 0; my $cyea = 0;
+    my $asec = 0; my $amin = 0; my $ahou = 0; my $aday = 0; my $amon = 0; my $ayea = 0;
+    my $msec = 0; my $mmin = 0; my $mhou = 0; my $mday = 0; my $mmon = 0; my $myea = 0;
+    my $newhandle = 0;
+    my $nextfile  = 1;
+    my @results   = ();
+    my ($filename, $altname, $file);
+  
+    if($self->{'Type'} ne "FTP") {
+        $self->{'Error'} = "List() only on FTP sessions.";
+        return undef;
+    }
+  
+    $pattern = "" unless defined($pattern);
+    $retmode = 1  unless defined($retmode);
+
+    if($retmode == 2) {
+  
+        ( $newhandle,$filename, $altname, $size, $attr,         
+          $csec, $cmin, $chou, $cday, $cmon, $cyea,
+          $asec, $amin, $ahou, $aday, $amon, $ayea,
+          $msec, $mmin, $mhou, $mday, $mmon, $myea
+        ) = FtpFindFirstFile($self->{'handle'}, $pattern, 0, 0);
+    
+        if(!$newhandle) {
+            $self->{'Error'} = "Can't read FTP directory.";
+            return undef;
+        } else {
+    
+            while($nextfile) {
+                $ctime = join(",", ($csec, $cmin, $chou, $cday, $cmon, $cyea));
+                $atime = join(",", ($asec, $amin, $ahou, $aday, $amon, $ayea));
+                $mtime = join(",", ($msec, $mmin, $mhou, $mday, $mmon, $myea));
+                push(@results, $filename, $altname, $size, $attr, $ctime, $atime, $mtime);
+        
+                ( $nextfile, $filename, $altname, $size, $attr,
+                  $csec, $cmin, $chou, $cday, $cmon, $cyea,
+                  $asec, $amin, $ahou, $aday, $amon, $ayea,
+                  $msec, $mmin, $mhou, $mday, $mmon, $myea
+                ) = InternetFindNextFile($newhandle);      
+        
+            }
+            InternetCloseHandle($newhandle);
+            return @results;
+      
+        }
+    
+    } elsif($retmode == 3) {
+  
+        ( $newhandle,$filename, $altname, $size, $attr,
+          $csec, $cmin, $chou, $cday, $cmon, $cyea,
+          $asec, $amin, $ahou, $aday, $amon, $ayea,
+          $msec, $mmin, $mhou, $mday, $mmon, $myea
+        ) = FtpFindFirstFile($self->{'handle'}, $pattern, 0, 0);
+    
+        if(!$newhandle) {
+            $self->{'Error'} = "Can't read FTP directory.";
+            return undef;
+       
+        } else {
+     
+            while($nextfile) {
+                $ctime = join(",", ($csec, $cmin, $chou, $cday, $cmon, $cyea));
+                $atime = join(",", ($asec, $amin, $ahou, $aday, $amon, $ayea));
+                $mtime = join(",", ($msec, $mmin, $mhou, $mday, $mmon, $myea));
+                $file = { "name"     => $filename,
+                          "altname"  => $altname,
+                          "size"     => $size,
+                          "attr"     => $attr,
+                          "ctime"    => $ctime,
+                          "atime"    => $atime,
+                          "mtime"    => $mtime,
+                };
+                push(@results, $file);
+         
+                ( $nextfile, $filename, $altname, $size, $attr,
+                  $csec, $cmin, $chou, $cday, $cmon, $cyea,
+                  $asec, $amin, $ahou, $aday, $amon, $ayea,
+                  $msec, $mmin, $mhou, $mday, $mmon, $myea
+                ) = InternetFindNextFile($newhandle);
+         
+            }
+            InternetCloseHandle($newhandle);
+            return @results;
+        }
+    
+    } else {
+    
+        ($newhandle, $filename) = FtpFindFirstFile($self->{'handle'}, $pattern, 0, 0);
+    
+        if(!$newhandle) {
+            $self->{'Error'} = "Can't read FTP directory.";
+            return undef;
+      
+        } else {
+    
+            while($nextfile) {
+                push(@results, $filename);
+        
+                ($nextfile, $filename) = InternetFindNextFile($newhandle);  
+                # print "List.no more files\n" if !$nextfile;
+        
+            }
+            InternetCloseHandle($newhandle);
+            return @results;
+        }
+    }
+}
+#====================
+sub Ls  { List(@_); }
+sub Dir { List(@_); }
+#====================
+
+
+#=================
+sub FileAttrInfo {
+#=================
+    my($self,$attr) = @_;
+    my @attrinfo = ();
+    push(@attrinfo, "READONLY")   if $attr & 1;
+    push(@attrinfo, "HIDDEN")     if $attr & 2;
+    push(@attrinfo, "SYSTEM")     if $attr & 4;
+    push(@attrinfo, "DIRECTORY")  if $attr & 16;
+    push(@attrinfo, "ARCHIVE")    if $attr & 32;
+    push(@attrinfo, "NORMAL")     if $attr & 128;
+    push(@attrinfo, "TEMPORARY")  if $attr & 256;
+    push(@attrinfo, "COMPRESSED") if $attr & 2048;
+    return (wantarray)? @attrinfo : join(" ", @attrinfo);
+}
+
+
+#===========
+sub Binary {
+#===========
+    my($self) = @_;
+    return undef unless ref($self);
+
+    if($self->{'Type'} ne "FTP") {
+        $self->{'Error'} = "Binary() only on FTP sessions.";
+        return undef;
+    }
+    $self->{'Mode'} = "bin";
+    return undef;
+}
+#======================
+sub Bin { Binary(@_); }
+#======================
+
+
+#==========
+sub Ascii {
+#==========
+    my($self) = @_;
+    return undef unless ref($self);
+
+    if($self->{'Type'} ne "FTP") {
+        $self->{'Error'} = "Ascii() only on FTP sessions.";
+        return undef;
+    }
+    $self->{'Mode'} = "asc";
+    return undef;
+}
+#=====================
+sub Asc { Ascii(@_); }
+#=====================
+
+
+#========
+sub Get {
+#========
+    my($self, $remote, $local, $overwrite, $flags, $context) = @_;
+    return undef unless ref($self);
+
+    if($self->{'Type'} ne "FTP") {
+        $self->{'Error'} = "Get() only on FTP sessions.";
+        return undef;
+    }
+    my $mode = ($self->{'Mode'} eq "asc" ? 1 : 2);
+ 
+    $remote    = ""      unless defined($remote);
+    $local     = $remote unless defined($local);
+    $overwrite = 0       unless defined($overwrite);
+    $flags     = 0       unless defined($flags);
+    $context   = 0       unless defined($context);
+  
+    my $retval = FtpGetFile($self->{'handle'},
+                            $remote,
+                            $local,
+                            $overwrite,
+                            $flags,
+                            $mode,
+                            $context);
+    $self->{'Error'} = "Can't get file." unless defined($retval);
+    return $retval;
+}
+
+
+#===========
+sub Rename {
+#===========
+    my($self, $oldname, $newname) = @_;
+    return undef unless ref($self);
+
+    if($self->{'Type'} ne "FTP") {
+        $self->{'Error'} = "Rename() only on FTP sessions.";
+        return undef;
+    }
+
+    my $retval = FtpRenameFile($self->{'handle'}, $oldname, $newname);
+    $self->{'Error'} = "Can't rename file." unless defined($retval);
+    return $retval;
+}
+#======================
+sub Ren { Rename(@_); }
+#======================
+
+
+#===========
+sub Delete {
+#===========
+    my($self, $filename) = @_;
+    return undef unless ref($self);
+
+    if($self->{'Type'} ne "FTP") {
+        $self->{'Error'} = "Delete() only on FTP sessions.";
+        return undef;
+    }
+    my $retval = FtpDeleteFile($self->{'handle'}, $filename);
+    $self->{'Error'} = "Can't delete file." unless defined($retval);
+    return $retval;
+}
+#======================
+sub Del { Delete(@_); }
+#======================
+
+
+#========
+sub Put {
+#========
+    my($self, $local, $remote, $context) = @_;
+    return undef unless ref($self);
+
+    if($self->{'Type'} ne "FTP") {
+        $self->{'Error'} = "Put() only on FTP sessions.";
+        return undef;
+    }
+    my $mode = ($self->{'Mode'} eq "asc" ? 1 : 2);
+
+    $context = 0 unless defined($context);
+  
+    my $retval = FtpPutFile($self->{'handle'}, $local, $remote, $mode, $context);
+    $self->{'Error'} = "Can't put file." unless defined($retval);
+    return $retval;
+}
+
+
+#######################################################################
+# HTTP CLASS METHODS
+#
+
+#========= ### HTTP CONSTRUCTOR
+sub HTTP {
+#=========
+    my($self, $new, $server, $username, $password, $port, $flags, $context) = @_;    
+    return undef unless ref($self);
+
+    if(ref($server) and ref($server) eq "HASH") {
+        my $myserver = $server->{'server'};
+        $username    = $server->{'username'};
+        $password    = $password->{'host'};
+        $port        = $server->{'port'};    
+        $flags       = $server->{'flags'};
+        $context     = $server->{'context'};
+        undef $server;
+        $server      = $myserver;
+    }
+
+    $server   = ""          unless defined($server);
+    $username = "anonymous" unless defined($username);
+    $password = ""          unless defined($password);
+    $port     = 80          unless defined($port);
+    $flags    = 0           unless defined($flags);
+    $context  = 0           unless defined($context);
+  
+    my $newhandle = InternetConnect($self->{'handle'}, $server, $port,
+                                    $username, $password,
+                                    constant("INTERNET_SERVICE_HTTP", 0),
+                                    $flags, $context);
+    if($newhandle) {
+        $self->{'connections'}++;
+        $_[1] = _new($newhandle);
+        $_[1]->{'Type'}     = "HTTP";
+        $_[1]->{'username'} = $username;
+        $_[1]->{'password'} = $password;
+        $_[1]->{'server'}   = $server;
+        $_[1]->{'accept'}   = "text/*\0image/gif\0image/jpeg\0\0";
+        return $newhandle;
+    } else {
+        return undef;
+    }
+}
+
+
+#================
+sub OpenRequest {
+#================
+    # alternatively to Request:
+    # it creates a new HTTP_Request object
+    # you can act upon it with AddHeader, SendRequest, ReadFile, QueryInfo, Close, ...
+
+    my($self, $new, $path, $method, $version, $referer, $accept, $flags, $context) = @_;
+    return undef unless ref($self);
+
+    if($self->{'Type'} ne "HTTP") {
+        $self->{'Error'} = "OpenRequest() only on HTTP sessions.";
+        return undef;
+    }
+
+    if(ref($path) and ref($path) eq "HASH") {
+        $method    = $path->{'method'};
+        $version   = $path->{'version'};
+        $referer   = $path->{'referer'};
+        $accept    = $path->{'accept'};
+        $flags     = $path->{'flags'};
+        $context   = $path->{'context'};
+        my $mypath = $path->{'path'};
+        undef $path;
+        $path      = $mypath;
+    }
+
+    $method  = "GET"             unless defined($method);
+    $path    = "/"               unless defined($path);
+    $version = "HTTP/1.0"        unless defined($version); 
+    $referer = ""                unless defined($referer);
+    $accept  = $self->{'accept'} unless defined($accept);
+    $flags   = 0                 unless defined($flags);
+    $context = 0                 unless defined($context);
+  
+    $path = "/".$path if substr($path,0,1) ne "/";  
+    # accept string list needs to be terminated by double-NULL
+    $accept .= "\0\0" unless $accept =~ /\0\0\z/;
+  
+    my $newhandle = HttpOpenRequest($self->{'handle'},
+                                    $method,
+                                    $path,
+                                    $version,
+                                    $referer,
+                                    $accept,
+                                    $flags,
+                                    $context);
+    if($newhandle) {
+        $_[1] = _new($newhandle);
+        $_[1]->{'Type'}    = "HTTP_Request";
+        $_[1]->{'method'}  = $method;
+        $_[1]->{'request'} = $path;
+        $_[1]->{'accept'}  = $accept;
+        return $newhandle;
+    } else {
+        return undef;
+    }
+}
+
+#================
+sub SendRequest {
+#================
+    my($self, $postdata) = @_;
+    return undef unless ref($self);
+
+    if($self->{'Type'} ne "HTTP_Request") {
+        $self->{'Error'} = "SendRequest() only on HTTP requests.";
+        return undef;
+    }
+  
+    $postdata = "" unless defined($postdata);
+
+    return HttpSendRequest($self->{'handle'}, "", $postdata);
+}
+
+
+#==============
+sub AddHeader {
+#==============
+    my($self, $header, $flags) = @_;
+    return undef unless ref($self);
+  
+    if($self->{'Type'} ne "HTTP_Request") {
+        $self->{'Error'} = "AddHeader() only on HTTP requests.";
+        return undef;
+    }
+  
+    $flags = constant("HTTP_ADDREQ_FLAG_ADD", 0) if (!defined($flags) or $flags == 0);
+
+    return HttpAddRequestHeaders($self->{'handle'}, $header, $flags);
+}
+
+
+#==============
+sub QueryInfo {
+#==============
+    my($self, $header, $flags) = @_;
+    return undef unless ref($self);
+
+    if($self->{'Type'} ne "HTTP_Request") {
+        $self->{'Error'}="QueryInfo() only on HTTP requests.";
+        return undef;
+    }
+  
+    $flags = constant("HTTP_QUERY_CUSTOM", 0) if (!defined($flags) and defined($header));
+    my @queryresult = HttpQueryInfo($self->{'handle'}, $flags, $header);
+    return (wantarray)? @queryresult : join(" ", @queryresult);
+}
+
+
+#============
+sub Request {
+#============
+    # HttpOpenRequest+HttpAddHeaders+HttpSendRequest+InternetReadFile+HttpQueryInfo
+    my($self, $path, $method, $version, $referer, $accept, $flags, $postdata) = @_;
+    return undef unless ref($self);
+
+    if($self->{'Type'} ne "HTTP") {
+        $self->{'Error'} = "Request() only on HTTP sessions.";
+        return undef;
+    }
+
+    if(ref($path) and ref($path) eq "HASH") {
+        $method    = $path->{'method'};
+        $version   = $path->{'version'};
+        $referer   = $path->{'referer'};
+        $accept    = $path->{'accept'};
+        $flags     = $path->{'flags'};
+        $postdata  = $path->{'postdata'};
+        my $mypath = $path->{'path'};
+        undef $path;
+        $path      = $mypath;
+    }
+
+    my $content     = "";
+    my $result      = "";
+    my @queryresult = ();
+    my $statuscode  = "";
+    my $headers     = "";
+  
+    $path     = "/"               unless defined($path);
+    $method   = "GET"             unless defined($method);
+    $version  = "HTTP/1.0"        unless defined($version); 
+    $referer  = ""                unless defined($referer);
+    $accept   = $self->{'accept'} unless defined($accept);
+    $flags    = 0                 unless defined($flags);
+    $postdata = ""                unless defined($postdata);
+
+    $path = "/".$path if substr($path,0,1) ne "/";  
+    # accept string list needs to be terminated by double-NULL
+    $accept .= "\0\0" unless $accept =~ /\0\0\z/;
+
+    my $newhandle = HttpOpenRequest($self->{'handle'},
+                                    $method,
+                                    $path,
+                                    $version,
+                                    $referer,
+                                    $accept,
+                                    $flags,
+				    0);
+
+    if($newhandle) {
+
+        $result = HttpSendRequest($newhandle, "", $postdata);
+
+        if(defined($result)) {
+            $statuscode = HttpQueryInfo($newhandle,
+                                        constant("HTTP_QUERY_STATUS_CODE", 0), "");
+            $headers = HttpQueryInfo($newhandle,
+                                     constant("HTTP_QUERY_RAW_HEADERS_CRLF", 0), "");
+            $content = ReadEntireFile($newhandle);
+               
+            InternetCloseHandle($newhandle);
+      
+            return($statuscode, $headers, $content);
+        } else {
+            return undef;
+        }
+    } else {
+        return undef;
+    }
+}
+
+
+#######################################################################
+# END OF THE PUBLIC METHODS
+#
+
+
+#========= ### SUB-CLASSES CONSTRUCTOR
+sub _new {
+#=========
+    my $self = {};
+    if ($_[0]) {
+        $self->{'handle'} = $_[0];
+        bless $self;
+    } else {
+        undef($self);
+    }
+    $self;
+}
+
+
+#============ ### CLASS DESTRUCTOR
+sub DESTROY {
+#============
+    my($self) = @_;
+    # print "Closing handle $self->{'handle'}...\n";
+    InternetCloseHandle($self->{'handle'});
+    # [dada] rest in peace
+}
+
+
+#=============
+sub callback {
+#=============
+    my($name, $status, $info) = @_;
+    $callback_code{$name} = $status;
+    $callback_info{$name} = $info;
+}
+
+#######################################################################
+# dynamically load in the Internet.pll module.
+#
+
+bootstrap Win32::Internet;
+
+# Preloaded methods go here.
+
+#Currently Autoloading is not implemented in Perl for win32
+# Autoload methods go after __END__, and are processed by the autosplit program.
+
+1;
+__END__
+
+=head1 NAME
+
+Win32::Internet - Access to WININET.DLL functions
+
+=head1 INTRODUCTION
+
+This extension to Perl implements the Win32 Internet APIs (found in
+F<WININET.DLL>). They give a complete support for HTTP, FTP and GOPHER
+connections.
+
+See the L<"Version History"> and the L<"Functions Table"> for a list
+of the currently supported features. You should also get a copy of the
+L<"Microsoft Win32 Internet Functions"> documentation.
+
+=head1 REFERENCE
+
+To use this module, first add the following line at the beginning of
+your script:
+
+    use Win32::Internet;
+
+Then you have to open an Internet connection with this command:
+
+    $Connection = new Win32::Internet();
+
+This is required to use any of the function of this module.  It will
+create an Internet object in Perl on which you can act upon with the
+L<"General Internet Functions"> explained later.
+
+The objects available are:
+
+=over
+
+=item *
+
+Internet connections (the main object, see C<new>)
+
+=item *
+
+URLs (see C<OpenURL>)
+
+=item *
+
+FTP sessions (see C<FTP>)
+
+=item *
+
+HTTP sessions (see C<HTTP>)
+
+=item *
+
+HTTP requests (see C<OpenRequest>)
+
+=back
+
+As in the good Perl tradition, there are in this extension different
+ways to do the same thing; there are, in fact, different levels of
+implementation of the Win32 Internet Functions.  Some routines use
+several Win32 API functions to perform a complex task in a single
+call; they are simpler to use, but of course less powerful.
+
+There are then other functions that implement nothing more and nothing
+less than the corresponding API function, so you can use all of their
+power, but with some additional programming steps.
+
+To make an example, there is a function called C<FetchURL> that you
+can use to fetch the content of any HTTP, FTP or GOPHER URL with this
+simple commands:
+
+    $INET = new Win32::Internet();
+    $file = $INET->FetchURL("http://www.yahoo.com");
+
+You can have the same result (and this is actually what is done by
+C<FetchURL>) this way:
+
+    $INET = new Win32::Internet();
+    $URL = $INET->OpenURL("http://www.yahoo.com");
+    $file = $URL->ReadFile();
+    $URL->Close();
+
+Or, you can open a complete HTTP session:
+
+    $INET = new Win32::Internet();
+    $HTTP = $INET->HTTP("www.yahoo.com", "anonymous", "dada@divinf.it");
+    ($statuscode, $headers, $file) = $HTTP->Request("/");
+    $HTTP->Close();
+
+Finally, you can choose to manage even the HTTP request:
+
+    $INET = new Win32::Internet();
+    $HTTP = $INET->HTTP("www.yahoo.com", "anonymous", "dada@divinf.it");
+    $HTTP->OpenRequest($REQ, "/");
+    $REQ->AddHeader("If-Modified-Since: Saturday, 16-Nov-96 15:58:50 GMT");
+    $REQ->SendRequest();
+    $statuscode = $REQ->QueryInfo("",HTTP_QUERY_STATUS_CODE);
+    $lastmodified = $REQ->QueryInfo("Last-Modified");
+    $file = $REQ->ReadEntireFile();
+    $REQ->Close();
+    $HTTP->Close();
+
+To open and control a complete FTP session, type:
+
+    $Connection->FTP($Session, "ftp://ftp.activeware.com", "anonymous", "dada\@divinf.it");
+
+This will create an FTP object in Perl to which you can apply the L<"FTP
+functions"> provided by the package:
+
+    $Session->Cd("/ntperl/perl5.001m/CurrentBuild");
+    $Session->Ascii();
+    $Session->Get("110-i86.zip");
+    $Session->Close();
+
+For a more complete example, see the TEST.PL file that comes with the
+package.
+
+=head2 General Internet Functions
+
+B<General Note>
+
+All methods assume that you have the line:
+
+    use Win32::Internet;
+
+somewhere before the method calls, and that you have an Internet
+object called $INET which was created using this call:
+
+    $INET = new Win32::Internet();
+
+See C<new> for more information.
+
+B<Methods>
+
+=over
+
+=item CanonicalizeURL URL, [flags]
+
+Converts a URL to a canonical format, which includes converting unsafe
+characters to escape sequences.  Returns the canonicalized URL or
+C<undef> on errors.  For the possible values of I<flags>, refer to the
+L<"Microsoft Win32 Internet Functions"> document.  See also
+C<CombineURL> and C<OpenURL>.
+
+Example:
+
+    $cURL = $INET->CanonicalizeURL($URL);
+    $URL = $INET->CanonicalizeURL($cURL, ICU_DECODE);
+
+=item Close
+
+=item Close object
+
+Closes an Internet connection.  This can be applied to any
+Win32::Internet object (Internet connections, URLs, FTP sessions,
+etc.).  Note that it is not "strictly" required to close the
+connections you create, since the Win32::Internet objects are
+automatically closed when the program ends (or when you elsehow
+destroy such an object).
+
+Example:
+
+    $INET->Close();
+    $FTP->Close();
+    $INET->Close($FTP); # same as above...
+
+=item CombineURL baseURL, relativeURL, [flags]
+
+Combines a base and relative URL into a single URL.  Returns the
+(canonicalized) combined URL or C<undef> on errors.  For the possible
+values of I<flags>, refer to the L<"Microsoft Win32 Internet
+Functions"> document.  See also C<CombineURL> and C<OpenURL>.
+
+Example:
+
+    $URL = $INET->CombineURL("http://www.divinf.it/dada/perl/internet", "..");
+
+=item ConnectBackoff [value]
+
+Reads or sets the delay value, in milliseconds, to wait between
+connection retries.  If no I<value> parameter is specified, the
+current value is returned; otherwise, the delay between retries is set
+to I<value>.  See also C<ConnectTimeout>, C<ConnectRetries>,
+C<QueryOption> and C<SetOption>.
+
+Example:
+
+    $HTTP->ConnectBackoff(2000);
+    $backoff = $HTTP->ConnectBackoff();
+
+=item ConnectRetries [value]
+
+Reads or sets the number of times a connection is retried before
+considering it failed.  If no I<value> parameter is specified, the
+current value is returned; otherwise, the number of retries is set to
+I<value>.  The default value for C<ConnectRetries> is 5.  See also
+C<ConnectBackoff>, C<ConnectTimeout>, C<QueryOption> and C<SetOption>.
+
+Example:
+
+    $HTTP->ConnectRetries(20);
+    $retries = $HTTP->ConnectRetries();
+
+=item ConnectTimeout [value]
+
+Reads or sets the timeout value (in milliseconds) before a connection
+is considered failed.  If no I<value> parameter is specified, the
+current value is returned; otherwise, the timeout is set to I<value>.
+The default value for C<ConnectTimeout> is infinite.  See also
+C<ConnectBackoff>, C<ConnectRetries>, C<QueryOption> and C<SetOption>.
+
+Example:
+
+    $HTTP->ConnectTimeout(10000);
+    $timeout = $HTTP->ConnectTimeout();
+
+=item ControlReceiveTimeout [value]
+
+Reads or sets the timeout value (in milliseconds) to use for non-data
+(control) receive requests before they are canceled.  Currently, this
+value has meaning only for C<FTP> sessions.  If no I<value> parameter
+is specified, the current value is returned; otherwise, the timeout is
+set to I<value>.  The default value for C<ControlReceiveTimeout> is
+infinite.  See also C<ControlSendTimeout>, C<QueryOption> and
+C<SetOption>.
+
+Example:
+
+    $HTTP->ControlReceiveTimeout(10000);
+    $timeout = $HTTP->ControlReceiveTimeout();
+
+=item ControlSendTimeout [value]
+
+Reads or sets the timeout value (in milliseconds) to use for non-data
+(control) send requests before they are canceled.  Currently, this
+value has meaning only for C<FTP> sessions.  If no I<value> parameter
+is specified, the current value is returned; otherwise, the timeout is
+set to I<value>.  The default value for C<ControlSendTimeout> is
+infinite.  See also C<ControlReceiveTimeout>, C<QueryOption> and
+C<SetOption>.
+
+Example:
+
+    $HTTP->ControlSendTimeout(10000);
+    $timeout = $HTTP->ControlSendTimeout();
+
+=item CrackURL URL, [flags]
+
+Splits an URL into its component parts and returns them in an array.
+Returns C<undef> on errors, otherwise the array will contain the
+following values: I<scheme, host, port, username, password, path,
+extrainfo>.
+
+For example, the URL "http://www.divinf.it/index.html#top" can be
+splitted in:
+
+    http, www.divinf.it, 80, anonymous, dada@divinf.it, /index.html, #top
+
+If you don't specify a I<flags> parameter, ICU_ESCAPE will be used by
+default; for the possible values of I<flags> refer to the L<"Microsoft
+Win32 Internet Functions"> documentation.  See also C<CreateURL>.
+
+Example:
+
+    @parts=$INET->CrackURL("http://www.activeware.com");
+    ($scheme, $host, $port, $user, $pass, $path, $extra) =
+         $INET->CrackURL("http://www.divinf.it:80/perl-win32/index.sht#feedback");
+
+=item CreateURL scheme, hostname, port, username, password, path, extrainfo, [flags]
+
+=item CreateURL hashref, [flags]
+
+Creates a URL from its component parts.  Returns C<undef> on errors,
+otherwise the created URL.
+
+If you pass I<hashref> (a reference to an hash array), the following
+values are taken from the array:
+
+    %hash=(
+      "scheme"    => "scheme",
+      "hostname"  => "hostname",
+      "port"      => port,
+      "username"  => "username",
+      "password"  => "password",
+      "path"      => "path",
+      "extrainfo" => "extrainfo",
+    );
+
+If you don't specify a I<flags> parameter, ICU_ESCAPE will be used by
+default; for the other possible values of I<flags> refer to the
+L<"Microsoft Win32 Internet Functions"> documentation.  See also
+C<CrackURL>.
+
+Example:
+
+    $URL=$I->CreateURL("http", "www.divinf.it", 80, "", "", "/perl-win32/index.sht", "#feedback");
+    $URL=$I->CreateURL(\%params);
+
+=item DataReceiveTimeout [value]
+
+Reads or sets the timeout value (in milliseconds) to use for data
+receive requests before they are canceled.  If no I<value> parameter
+is specified, the current value is returned; otherwise, the timeout is
+set to I<value>.  The default value for DataReceiveTimeout is
+infinite.  See also C<DataSendTimeout>, C<QueryOption> and
+C<SetOption>.
+
+Example:
+
+    $HTTP->DataReceiveTimeout(10000);
+    $timeout = $HTTP->DataReceiveTimeout();
+
+=item DataSendTimeout [value]
+
+Reads or sets the timeout value (in milliseconds) to use for data send
+requests before they are canceled.  If no I<value> parameter is
+specified, the current value is returned; otherwise, the timeout is
+set to I<value>.  The default value for DataSendTimeout is infinite.
+See also C<DataReceiveTimeout>, C<QueryOption> and C<SetOption>.
+
+Example:
+
+    $HTTP->DataSendTimeout(10000);
+    $timeout = $HTTP->DataSendTimeout();
+
+=item Error
+
+Returns the last recorded error in the form of an array or string
+(depending upon the context) containing the error number and an error
+description.  Can be applied on any Win32::Internet object (FTP
+sessions, etc.).  There are 3 types of error you can encounter; they
+are recognizable by the error number returned:
+
+=over
+
+=item * -1
+
+A "trivial" error has occurred in the package.  For example, you tried
+to use a method on the wrong type of object.
+
+=item * 1 .. 11999
+
+A generic error has occurred and the Win32::GetLastError error message
+is returned.
+
+=item * 12000 and higher
+
+An Internet error has occurred; the extended Win32 Internet API error
+message is returned.
+
+=back
+
+See also C<GetResponse>.
+
+Example:
+
+    die $INET->Error(), qq(\n);
+    ($ErrNum, $ErrText) = $INET->Error();
+
+=item FetchURL URL
+
+Fetch the content of an HTTP, FTP or GOPHER URL.  Returns the content
+of the file read (or C<undef> if there was an error and nothing was
+read).  See also C<OpenURL> and C<ReadFile>.
+
+Example:
+
+    $file = $INET->FetchURL("http://www.yahoo.com/");
+    $file = $INET->FetchURL("ftp://www.activeware.com/contrib/internet.zip");
+
+=item FTP ftpobject, server, username, password, [port, pasv, context]
+
+=item FTP ftpobject, hashref
+
+Opens an FTP connection to server logging in with the given
+I<username> and I<password>.
+
+The parameters and their values are:
+
+=over
+
+=item * server
+
+The server to connect to.  Default: I<none>.
+
+=item * username
+
+The username used to login to the server.  Default: anonymous.
+
+=item * password
+
+The password used to login to the server.  Default: I<none>.
+
+=item * port
+
+The port of the FTP service on the server.  Default: 21.
+
+=item * pasv
+
+If it is a value other than 0, use passive transfer mode.  Default is
+taken from the parent Internet connection object; you can set this
+value with the C<Pasv> method.
+
+=item * context
+
+A number to identify this operation if it is asynchronous.  See
+C<SetStatusCallback> and C<GetStatusCallback> for more info on
+asynchronous operations.  Default: I<none>.
+
+=back
+
+If you pass I<hashref> (a reference to an hash array), the following
+values are taken from the array:
+
+    %hash=(
+      "server"   => "server",
+      "username" => "username",
+      "password" => "password",
+      "port"     => port,
+      "pasv"     => pasv,
+      "context"  => context,
+    );
+
+This method returns C<undef> if the connection failed, a number
+otherwise.  You can then call any of the L<"FTP functions"> as methods
+of the newly created I<ftpobject>.
+
+Example:
+
+    $result = $INET->FTP($FTP, "ftp.activeware.com", "anonymous", "dada\@divinf.it");
+    # and then for example...
+    $FTP->Cd("/ntperl/perl5.001m/CurrentBuild");
+
+    $params{"server"} = "ftp.activeware.com";
+    $params{"password"} = "dada\@divinf.it";
+    $params{"pasv"} = 0;
+    $result = $INET->FTP($FTP,\%params);
+
+=item GetResponse
+
+Returns the text sent by a remote server in response to the last
+function executed.  It applies on any Win32::Internet object,
+particularly of course on L<FTP sessions|"FTP functions">.  See also
+the C<Error> function.
+
+Example:
+
+    print $INET->GetResponse();
+    $INET->FTP($FTP, "ftp.activeware.com", "anonymous", "dada\@divinf.it");
+    print $FTP->GetResponse();
+
+=item GetStatusCallback context
+
+Returns information about the progress of the asynchronous operation
+identified by I<context>; those informations consist of two values: a
+status code (one of the INTERNET_STATUS_* L<"Constants">) and an
+additional value depending on the status code; for example, if the
+status code returned is INTERNET_STATUS_HANDLE_CREATED, the second
+value will hold the handle just created.  For more informations on
+those values, please refer to the L<"Microsoft Win32 Internet
+Functions"> documentation.  See also C<SetStatusCallback>.
+
+Example:
+
+    ($status, $info) = $INET->GetStatusCallback(1);
+
+=item HTTP httpobject, server, username, password, [port, flags, context]
+
+=item HTTP httpobject, hashref
+
+Opens an HTTP connection to I<server> logging in with the given
+I<username> and I<password>.
+
+The parameters and their values are:
+
+=over
+
+=item * server
+
+The server to connect to.  Default: I<none>.
+
+=item * username
+
+The username used to login to the server.  Default: anonymous.
+
+=item * password
+
+The password used to login to the server.  Default: I<none>.
+
+=item * port
+
+The port of the HTTP service on the server.  Default: 80.
+
+=item * flags
+
+Additional flags affecting the behavior of the function.  Default:
+I<none>.
+
+=item * context
+
+A number to identify this operation if it is asynchronous.  See
+C<SetStatusCallback> and C<GetStatusCallback> for more info on
+asynchronous operations.  Default: I<none>.
+
+=back
+
+Refer to the L<"Microsoft Win32 Internet Functions"> documentation for
+more details on those parameters.
+
+If you pass I<hashref> (a reference to an hash array), the following
+values are taken from the array:
+
+    %hash=(
+      "server"   => "server",
+      "username" => "username",
+      "password" => "password",
+      "port"     => port,
+      "flags"    => flags,
+      "context"  => context,
+    );
+
+This method returns C<undef> if the connection failed, a number
+otherwise.  You can then call any of the L<"HTTP functions"> as
+methods of the newly created I<httpobject>.
+
+Example:
+
+    $result = $INET->HTTP($HTTP,"www.activeware.com","anonymous","dada\@divinf.it");
+    # and then for example...
+    ($statuscode, $headers, $file) = $HTTP->Request("/gifs/camel.gif");
+
+    $params{"server"} = "www.activeware.com";
+    $params{"password"} = "dada\@divinf.it";
+    $params{"flags"} = INTERNET_FLAG_RELOAD;
+    $result = $INET->HTTP($HTTP,\%params);
+
+=item new Win32::Internet [useragent, opentype, proxy, proxybypass, flags]
+
+=item new Win32::Internet [hashref]
+
+Creates a new Internet object and initializes the use of the Internet
+functions; this is required before any of the functions of this
+package can be used.  Returns C<undef> if the connection fails, a number
+otherwise.  The parameters and their values are:
+
+=over
+
+=item * useragent
+
+The user agent passed to HTTP requests.  See C<OpenRequest>.  Default:
+Perl-Win32::Internet/I<version>.
+
+=item * opentype
+
+How to access to the Internet (eg. directly or using a proxy).
+Default: INTERNET_OPEN_TYPE_DIRECT.
+
+=item * proxy
+
+Name of the proxy server (or servers) to use.  Default: I<none>.
+
+=item * proxybypass
+
+Optional list of host names or IP addresses, or both, that are known
+locally.  Default: I<none>.
+
+=item * flags
+
+Additional flags affecting the behavior of the function.  Default:
+I<none>.
+
+=back
+
+Refer to the L<"Microsoft Win32 Internet Functions"> documentation for
+more details on those parameters.  If you pass I<hashref> (a reference to
+an hash array), the following values are taken from the array:
+
+    %hash=(
+      "useragent"   => "useragent",
+      "opentype"    => "opentype",
+      "proxy"       => "proxy",
+      "proxybypass" => "proxybypass",
+      "flags"       => flags,
+    );
+
+Example:
+
+    $INET = new Win32::Internet();
+    die qq(Cannot connect to Internet...\n) if ! $INET;
+
+    $INET = new Win32::Internet("Mozilla/3.0", INTERNET_OPEN_TYPE_PROXY, "www.microsoft.com", "");
+
+    $params{"flags"} = INTERNET_FLAG_ASYNC;
+    $INET = new Win32::Internet(\%params);
+
+=item OpenURL urlobject, URL
+
+Opens a connection to an HTTP, FTP or GOPHER Uniform Resource Location
+(URL).  Returns C<undef> on errors or a number if the connection was
+succesful.  You can then retrieve the URL content by applying the
+methods C<QueryDataAvailable> and C<ReadFile> on the newly created
+I<urlobject>.  See also C<FetchURL>.
+
+Example:
+
+    $INET->OpenURL($URL, "http://www.yahoo.com/");
+    $bytes = $URL->QueryDataAvailable();
+    $file = $URL->ReadEntireFile();
+    $URL->Close();
+
+=item Password [password]
+
+Reads or sets the password used for an C<FTP> or C<HTTP> connection.
+If no I<password> parameter is specified, the current value is
+returned; otherwise, the password is set to I<password>.  See also
+C<Username>, C<QueryOption> and C<SetOption>.
+
+Example:
+
+    $HTTP->Password("splurfgnagbxam");
+    $password = $HTTP->Password();
+
+=item QueryDataAvailable
+
+Returns the number of bytes of data that are available to be read
+immediately by a subsequent call to C<ReadFile> (or C<undef> on
+errors).  Can be applied to URL or HTTP request objects.  See
+C<OpenURL> or C<OpenRequest>.
+
+Example:
+
+    $INET->OpenURL($URL, "http://www.yahoo.com/");
+    $bytes = $URL->QueryDataAvailable();
+
+=item QueryOption option
+
+Queries an Internet option.  For the possible values of I<option>,
+refer to the L<"Microsoft Win32 Internet Functions"> document.  See
+also C<SetOption>.
+
+Example:
+
+    $value = $INET->QueryOption(INTERNET_OPTION_CONNECT_TIMEOUT);
+    $value = $HTTP->QueryOption(INTERNET_OPTION_USERNAME);
+
+=item ReadEntireFile
+
+Reads all the data available from an opened URL or HTTP request
+object.  Returns what have been read or C<undef> on errors.  See also
+C<OpenURL>, C<OpenRequest> and C<ReadFile>.
+
+Example:
+
+    $INET->OpenURL($URL, "http://www.yahoo.com/");
+    $file = $URL->ReadEntireFile();
+
+=item ReadFile bytes
+
+Reads I<bytes> bytes of data from an opened URL or HTTP request
+object.  Returns what have been read or C<undef> on errors.  See also
+C<OpenURL>, C<OpenRequest>, C<QueryDataAvailable> and
+C<ReadEntireFile>.
+
+B<Note:> be careful to keep I<bytes> to an acceptable value (eg.  don't
+tell him to swallow megabytes at once...).  C<ReadEntireFile> in fact
+uses C<QueryDataAvailable> and C<ReadFile> in a loop to read no more
+than 16k at a time.
+
+Example:
+
+    $INET->OpenURL($URL, "http://www.yahoo.com/");
+    $chunk = $URL->ReadFile(16000);
+
+=item SetOption option, value
+
+Sets an Internet option.  For the possible values of I<option>, refer to
+the L<"Microsoft Win32 Internet Functions"> document.  See also
+C<QueryOption>.
+
+Example:
+
+    $INET->SetOption(INTERNET_OPTION_CONNECT_TIMEOUT,10000);
+    $HTTP->SetOption(INTERNET_OPTION_USERNAME,"dada");
+
+=item SetStatusCallback
+
+Initializes the callback routine used to return data about the
+progress of an asynchronous operation.
+
+Example:
+
+    $INET->SetStatusCallback();
+
+This is one of the step required to perform asynchronous operations;
+the complete procedure is:
+
+    # use the INTERNET_FLAG_ASYNC when initializing
+    $params{'flags'}=INTERNET_FLAG_ASYNC;
+    $INET = new Win32::Internet(\%params);
+
+    # initialize the callback routine
+    $INET->SetStatusCallback();
+
+    # specify the context parameter (the last 1 in this case)
+    $INET->HTTP($HTTP, "www.yahoo.com", "anonymous", "dada\@divinf.it", 80, 0, 1);
+
+At this point, control returns immediately to Perl and $INET->Error()
+will return 997, which means an asynchronous I/O operation is
+pending.  Now, you can call
+
+    $HTTP->GetStatusCallback(1);
+
+in a loop to verify what's happening; see also C<GetStatusCallback>.
+
+=item TimeConvert time
+
+=item TimeConvert seconds, minute, hours, day, month, year,
+                  day_of_week, RFC
+
+The first form takes a HTTP date/time string and returns the date/time
+converted in the following array: I<seconds, minute, hours, day,
+month, year, day_of_week>.
+
+The second form does the opposite (or at least it should, because
+actually seems to be malfunctioning): it takes the values and returns
+an HTTP date/time string, in the RFC format specified by the I<RFC>
+parameter (OK, I didn't find yet any accepted value in the range
+0..2000, let me know if you have more luck with it).
+
+Example:
+
+    ($sec, $min, $hour, $day, $mday, $year, $wday) =
+       $INET->TimeConvert("Sun, 26 Jan 1997 20:01:52 GMT");
+
+    # the opposite DOESN'T WORK! which value should $RFC have???
+    $time = $INET->TimeConvert(52, 1, 20, 26, 1, 1997, 0, $RFC);
+
+=item UserAgent [name]
+
+Reads or sets the user agent used for HTTP requests.  If no I<name>
+parameter is specified, the current value is returned; otherwise, the
+user agent is set to I<name>.  See also C<QueryOption> and
+C<SetOption>.
+
+Example:
+
+    $INET->UserAgent("Mozilla/3.0");
+    $useragent = $INET->UserAgent();
+
+=item Username [name]
+
+Reads or sets the username used for an C<FTP> or C<HTTP> connection.
+If no I<name> parameter is specified, the current value is returned;
+otherwise, the username is set to I<name>.  See also C<Password>,
+C<QueryOption> and SetOption.
+
+Example:
+
+    $HTTP->Username("dada");
+    $username = $HTTP->Username();
+
+=item Version
+
+Returns the version numbers for the Win32::Internet package and the
+WININET.DLL version, as an array or string, depending on the context.
+The string returned will contain "package_version/DLL_version", while
+the array will contain: "package_version", "DLL_version".
+
+Example:
+
+    $version = $INET->Version(); # should return "0.06/4.70.1215"
+    @version = $INET->Version(); # should return ("0.06", "4.70.1215")
+
+=back
+
+
+=head2 FTP Functions
+
+B<General Note>
+
+All methods assume that you have the following lines:
+
+    use Win32::Internet;
+    $INET = new Win32::Internet();
+    $INET->FTP($FTP, "hostname", "username", "password");
+
+somewhere before the method calls; in other words, we assume that you
+have an Internet object called $INET and an open FTP session called
+$FTP.
+
+See C<new> and C<FTP> for more information.
+
+
+B<Methods>
+
+=over
+
+=item Ascii
+
+=item Asc
+
+Sets the ASCII transfer mode for this FTP session.  It will be applied
+to the subsequent C<Get> functions.  See also the C<Binary> and
+C<Mode> function.
+
+Example:
+
+    $FTP->Ascii();
+
+=item Binary
+
+=item Bin
+
+Sets the binary transfer mode for this FTP session.  It will be
+applied to the subsequent C<Get> functions.  See also the C<Ascii> and
+C<Mode> function.
+
+Example:
+
+    $FTP->Binary();
+
+=item Cd path
+
+=item Cwd path
+
+=item Chdir path
+
+Changes the current directory on the FTP remote host.  Returns I<path>
+or C<undef> on error.
+
+Example:
+
+    $FTP->Cd("/pub");
+
+=item Delete file
+
+=item Del file
+
+Deletes a file on the FTP remote host.  Returns C<undef> on error.
+
+Example:
+
+    $FTP->Delete("110-i86.zip");
+
+=item Get remote, [local, overwrite, flags, context]
+
+Gets the I<remote> FTP file and saves it locally in I<local>.  If
+I<local> is not specified, it will be the same name as I<remote>.
+Returns C<undef> on error.  The parameters and their values are:
+
+=over
+
+=item * remote
+
+The name of the remote file on the FTP server.  Default: I<none>.
+
+=item * local
+
+The name of the local file to create.  Default: remote.
+
+=item * overwrite
+
+If 0, overwrites I<local> if it exists; with any other value, the
+function fails if the I<local> file already exists.  Default: 0.
+
+=item * flags
+
+Additional flags affecting the behavior of the function.  Default:
+I<none>.
+
+=item * context
+
+A number to identify this operation if it is asynchronous.  See
+C<SetStatusCallback> and C<GetStatusCallback> for more info on
+asynchronous operations.  Default: I<none>.
+
+=back
+
+Refer to the L<"Microsoft Win32 Internet Functions"> documentation for
+more details on those parameters.
+
+Example:
+
+    $FTP->Get("110-i86.zip");
+    $FTP->Get("/pub/perl/languages/CPAN/00index.html", "CPAN_index.html");
+
+=item List [pattern, listmode]
+
+=item Ls [pattern, listmode]
+
+=item Dir [pattern, listmode]
+
+Returns a list containing the files found in this directory,
+eventually matching the given I<pattern> (which, if omitted, is
+considered "*.*").  The content of the returned list depends on the
+I<listmode> parameter, which can have the following values:
+
+=over
+
+=item * listmode=1 (or omitted)
+
+the list contains the names of the files found.  Example:
+
+    @files = $FTP->List();
+    @textfiles = $FTP->List("*.txt");
+    foreach $file (@textfiles) {
+      print "Name: ", $file, "\n";
+    }
+
+=item * listmode=2
+
+the list contains 7 values for each file, which respectively are:
+
+=over
+
+=item * the file name
+
+=item * the DOS short file name, aka 8.3
+
+=item * the size
+
+=item * the attributes
+
+=item * the creation time
+
+=item * the last access time
+
+=item * the last modified time
+
+=back
+
+Example:
+
+    @files = $FTP->List("*.*", 2);
+    for($i=0; $i<=$#files; $i+=7) {
+      print "Name: ", @files[$i], "\n";
+      print "Size: ", @files[$i+2], "\n";
+      print "Attr: ", @files[$i+3], "\n";
+    }
+
+=item * listmode=3
+
+the list contains a reference to an hash array for each found file;
+each hash contains:
+
+=over
+
+=item * name => the file name
+
+=item * altname => the DOS short file name, aka 8.3
+
+=item * size => the size
+
+=item * attr => the attributes
+
+=item * ctime => the creation time
+
+=item * atime => the last access time
+
+=item * mtime => the last modified time
+
+=back
+
+Example:
+
+    @files = $FTP->List("*.*", 3);
+    foreach $file (@files) {
+      print $file->{'name'}, " ", $file->{'size'}, " ", $file->{'attr'}, "\n";
+    }
+
+B<Note:> all times are reported as strings of the following format:
+I<second, hour, minute, day, month, year>.
+
+Example:
+
+    $file->{'mtime'} == "0,10,58,9,12,1996" stands for 09 Dec 1996 at 10:58:00
+
+=back
+
+=item Mkdir name
+
+=item Md name
+
+Creates a directory on the FTP remote host.  Returns C<undef> on error.
+
+Example:
+
+    $FTP->Mkdir("NextBuild");
+
+=item Mode [mode]
+
+If called with no arguments, returns the current transfer mode for
+this FTP session ("asc" for ASCII or "bin" for binary).  The I<mode>
+argument can be "asc" or "bin", in which case the appropriate transfer
+mode is selected.  See also the Ascii and Binary functions.  Returns
+C<undef> on errors.
+
+Example:
+
+    print "Current mode is: ", $FTP->Mode();
+    $FTP->Mode("asc"); # ...  same as $FTP->Ascii();
+
+=item Pasv [mode]
+
+If called with no arguments, returns 1 if the current FTP session has
+passive transfer mode enabled, 0 if not.
+
+You can call it with a I<mode> parameter (0/1) only as a method of a
+Internet object (see C<new>), in which case it will set the default
+value for the next C<FTP> objects you create (read: set it before,
+because you can't change this value once you opened the FTP session).
+
+Example:
+
+    print "Pasv is: ", $FTP->Pasv();
+
+    $INET->Pasv(1);
+    $INET->FTP($FTP,"ftp.activeware.com", "anonymous", "dada\@divinf.it");
+    $FTP->Pasv(0); # this will be ignored...
+
+=item Put local, [remote, context]
+
+Upload the I<local> file to the FTP server saving it under the name
+I<remote>, which if if omitted is the same name as I<local>.  Returns
+C<undef> on error.
+
+I<context> is a number to identify this operation if it is asynchronous.
+See C<SetStatusCallback> and C<GetStatusCallback> for more info on
+asynchronous operations.
+
+Example:
+
+    $FTP->Put("internet.zip");
+    $FTP->Put("d:/users/dada/temp.zip", "/temp/dada.zip");
+
+=item Pwd
+
+Returns the current directory on the FTP server or C<undef> on errors.
+
+Example:
+
+    $path = $FTP->Pwd();
+
+=item Rename oldfile, newfile
+
+=item Ren oldfile, newfile
+
+Renames a file on the FTP remote host.  Returns C<undef> on error.
+
+Example:
+
+    $FTP->Rename("110-i86.zip", "68i-011.zip");
+
+=item Rmdir name
+
+=item Rd name
+
+Removes a directory on the FTP remote host.  Returns C<undef> on error.
+
+Example:
+
+    $FTP->Rmdir("CurrentBuild");
+
+=back
+
+=head2 HTTP Functions
+
+B<General Note>
+
+All methods assume that you have the following lines:
+
+    use Win32::Internet;
+    $INET = new Win32::Internet();
+    $INET->HTTP($HTTP, "hostname", "username", "password");
+
+somewhere before the method calls; in other words, we assume that you
+have an Internet object called $INET and an open HTTP session called
+$HTTP.
+
+See C<new> and C<HTTP> for more information.
+
+
+B<Methods>
+
+=over
+
+=item AddHeader header, [flags]
+
+Adds HTTP request headers to an HTTP request object created with
+C<OpenRequest>.  For the possible values of I<flags> refer to the
+L<"Microsoft Win32 Internet Functions"> document.
+
+Example:
+
+    $HTTP->OpenRequest($REQUEST,"/index.html");
+    $REQUEST->AddHeader("If-Modified-Since:  Sunday, 17-Nov-96 11:40:03 GMT");
+    $REQUEST->AddHeader("Accept: text/html\r\n", HTTP_ADDREQ_FLAG_REPLACE);
+
+=item OpenRequest requestobject, [path, method, version, referer, accept, flags, context]
+
+=item OpenRequest requestobject, hashref
+
+Opens an HTTP request.  Returns C<undef> on errors or a number if the
+connection was succesful.  You can then use one of the C<AddHeader>,
+C<SendRequest>, C<QueryInfo>, C<QueryDataAvailable> and C<ReadFile>
+methods on the newly created I<requestobject>.  The parameters and
+their values are:
+
+=over
+
+=item * path
+
+The object to request.  This is generally a file name, an executable
+module, etc.  Default: /
+
+=item * method
+
+The method to use; can actually be GET, POST, HEAD or PUT.  Default:
+GET
+
+=item * version
+
+The HTTP version.  Default: HTTP/1.0
+
+=item * referer
+
+The URL of the document from which the URL in the request was
+obtained.  Default: I<none>
+
+=item * accept
+
+A single string with "\0" (ASCII zero) delimited list of content
+types accepted.  The string must be terminated by "\0\0".
+Default: "text/*\0image/gif\0image/jpeg\0\0"
+
+=item * flags
+
+Additional flags affecting the behavior of the function.  Default:
+I<none>
+
+=item * context
+
+A number to identify this operation if it is asynchronous.  See
+C<SetStatusCallback> and C<GetStatusCallback> for more info on
+asynchronous operations.  Default: I<none>
+
+=back
+
+Refer to the L<"Microsoft Win32 Internet Functions"> documentation for
+more details on those parameters.  If you pass I<hashref> (a reference to
+an hash array), the following values are taken from the array:
+
+    %hash=(
+      "path"        => "path",
+      "method"      => "method",
+      "version"     => "version",
+      "referer"     => "referer",
+      "accept"      => "accept",
+      "flags"       => flags,
+      "context"     => context,
+    );
+
+See also C<Request>.
+
+Example:
+
+    $HTTP->OpenRequest($REQUEST, "/index.html");
+    $HTTP->OpenRequest($REQUEST, "/index.html", "GET", "HTTP/0.9");
+
+    $params{"path"} = "/index.html";
+    $params{"flags"} = "
+    $HTTP->OpenRequest($REQUEST, \%params);
+
+=item QueryInfo header, [flags]
+
+Queries information about an HTTP request object created with
+C<OpenRequest>.  You can specify an I<header> (for example,
+"Content-type") and/or one or more I<flags>.  If you don't specify
+I<flags>, HTTP_QUERY_CUSTOM will be used by default; this means that
+I<header> should contain a valid HTTP header name.  For the possible
+values of I<flags> refer to the L<"Microsoft Win32 Internet
+Functions"> document.
+
+Example:
+
+    $HTTP->OpenRequest($REQUEST,"/index.html");
+    $statuscode = $REQUEST->QueryInfo("", HTTP_QUERY_STATUS_CODE);
+    $headers = $REQUEST->QueryInfo("", HTTP_QUERY_RAW_HEADERS_CRLF); # will get all the headers
+    $length = $REQUEST->QueryInfo("Content-length");
+
+=item Request [path, method, version, referer, accept, flags]
+
+=item Request hashref
+
+Performs an HTTP request and returns an array containing the status
+code, the headers and the content of the file.  It is a one-step
+procedure that makes an C<OpenRequest>, a C<SendRequest>, some
+C<QueryInfo>, C<ReadFile> and finally C<Close>.  For a description of
+the parameters, see C<OpenRequest>.
+
+Example:
+
+    ($statuscode, $headers, $file) = $HTTP->Request("/index.html");
+    ($s, $h, $f) = $HTTP->Request("/index.html", "GET", "HTTP/1.0");
+
+=item SendRequest [postdata]
+
+Send an HTTP request to the destination server.  I<postdata> are any
+optional data to send immediately after the request header; this is
+generally used for POST or PUT requests.  See also C<OpenRequest>.
+
+Example:
+
+    $HTTP->OpenRequest($REQUEST, "/index.html");
+    $REQUEST->SendRequest();
+
+    # A POST request...
+    $HTTP->OpenRequest($REQUEST, "/cgi-bin/somescript.pl", "POST");
+
+    #This line is a must -> (thanks Philip :)
+    $REQUEST->AddHeader("Content-Type: application/x-www-form-urlencoded");
+
+    $REQUEST->SendRequest("key1=value1&key2=value2&key3=value3");
+
+=back
+
+
+=head1 APPENDIX
+
+
+=head2 Microsoft Win32 Internet Functions
+
+Complete documentation for the Microsoft Win32 Internet Functions can
+be found, in both HTML and zipped Word format, at this address:
+
+    http://www.microsoft.com/intdev/sdk/docs/wininet/
+
+=head2 Functions Table
+
+This table reports the correspondence between the functions offered by
+WININET.DLL and their implementation in the Win32::Internet
+extension. Functions showing a "---" are not currently
+implemented. Functions enclosed in parens ( ) aren't implemented
+straightforwardly, but in a higher-level routine, eg. together with
+other functions.
+
+    WININET.DLL                     Win32::Internet
+
+    InternetOpen                    new Win32::Internet
+    InternetConnect                 FTP / HTTP
+    InternetCloseHandle             Close
+    InternetQueryOption             QueryOption
+    InternetSetOption               SetOption
+    InternetSetOptionEx             ---
+    InternetSetStatusCallback       SetStatusCallback
+    InternetStatusCallback          GetStatusCallback
+    InternetConfirmZoneCrossing     ---
+    InternetTimeFromSystemTime      TimeConvert
+    InternetTimeToSystemTime        TimeConvert
+    InternetAttemptConnect          ---
+    InternetReadFile                ReadFile
+    InternetSetFilePointer          ---
+    InternetFindNextFile            (List)
+    InternetQueryDataAvailable      QueryDataAvailable
+    InternetGetLastResponseInfo     GetResponse
+    InternetWriteFile               ---
+    InternetCrackUrl                CrackURL
+    InternetCreateUrl               CreateURL
+    InternetCanonicalizeUrl         CanonicalizeURL
+    InternetCombineUrl              CombineURL
+    InternetOpenUrl                 OpenURL
+    FtpFindFirstFile                (List)
+    FtpGetFile                      Get
+    FtpPutFile                      Put
+    FtpDeleteFile                   Delete
+    FtpRenameFile                   Rename
+    FtpOpenFile                     ---
+    FtpCreateDirectory              Mkdir
+    FtpRemoveDirectory              Rmdir
+    FtpSetCurrentDirectory          Cd
+    FtpGetCurrentDirectory          Pwd
+    HttpOpenRequest                 OpenRequest
+    HttpAddRequestHeaders           AddHeader
+    HttpSendRequest                 SendRequest
+    HttpQueryInfo                   QueryInfo
+    InternetErrorDlg                ---
+
+
+Actually, I don't plan to add support for Gopher, Cookie and Cache
+functions. I will if there will be consistent requests to do so.
+
+There are a number of higher-level functions in the Win32::Internet
+that simplify some usual procedures, calling more that one WININET API
+function. This table reports those functions and the relative WININET
+functions they use.
+
+    Win32::Internet                 WININET.DLL
+
+    FetchURL                        InternetOpenUrl
+                                    InternetQueryDataAvailable
+                                    InternetReadFile
+                                    InternetCloseHandle
+
+    ReadEntireFile                  InternetQueryDataAvailable
+                                    InternetReadFile
+
+    Request                         HttpOpenRequest
+                                    HttpSendRequest
+                                    HttpQueryInfo
+                                    InternetQueryDataAvailable
+                                    InternetReadFile
+                                    InternetCloseHandle
+
+    List                            FtpFindFirstFile
+                                    InternetFindNextFile
+
+
+=head2 Constants
+
+Those are the constants exported by the package in the main namespace
+(eg. you can use them in your scripts); for their meaning and proper
+use, refer to the Microsoft Win32 Internet Functions document.
+
+    HTTP_ADDREQ_FLAG_ADD
+    HTTP_ADDREQ_FLAG_REPLACE
+    HTTP_QUERY_ALLOW
+    HTTP_QUERY_CONTENT_DESCRIPTION
+    HTTP_QUERY_CONTENT_ID
+    HTTP_QUERY_CONTENT_LENGTH
+    HTTP_QUERY_CONTENT_TRANSFER_ENCODING
+    HTTP_QUERY_CONTENT_TYPE
+    HTTP_QUERY_COST
+    HTTP_QUERY_CUSTOM
+    HTTP_QUERY_DATE
+    HTTP_QUERY_DERIVED_FROM
+    HTTP_QUERY_EXPIRES
+    HTTP_QUERY_FLAG_REQUEST_HEADERS
+    HTTP_QUERY_FLAG_SYSTEMTIME
+    HTTP_QUERY_LANGUAGE
+    HTTP_QUERY_LAST_MODIFIED
+    HTTP_QUERY_MESSAGE_ID
+    HTTP_QUERY_MIME_VERSION
+    HTTP_QUERY_PRAGMA
+    HTTP_QUERY_PUBLIC
+    HTTP_QUERY_RAW_HEADERS
+    HTTP_QUERY_RAW_HEADERS_CRLF
+    HTTP_QUERY_REQUEST_METHOD
+    HTTP_QUERY_SERVER
+    HTTP_QUERY_STATUS_CODE
+    HTTP_QUERY_STATUS_TEXT
+    HTTP_QUERY_URI
+    HTTP_QUERY_USER_AGENT
+    HTTP_QUERY_VERSION
+    HTTP_QUERY_WWW_LINK
+    ICU_BROWSER_MODE
+    ICU_DECODE
+    ICU_ENCODE_SPACES_ONLY
+    ICU_ESCAPE
+    ICU_NO_ENCODE
+    ICU_NO_META
+    ICU_USERNAME
+    INTERNET_FLAG_PASSIVE
+    INTERNET_FLAG_ASYNC
+    INTERNET_FLAG_HYPERLINK
+    INTERNET_FLAG_KEEP_CONNECTION
+    INTERNET_FLAG_MAKE_PERSISTENT
+    INTERNET_FLAG_NO_AUTH
+    INTERNET_FLAG_NO_AUTO_REDIRECT
+    INTERNET_FLAG_NO_CACHE_WRITE
+    INTERNET_FLAG_NO_COOKIES
+    INTERNET_FLAG_READ_PREFETCH
+    INTERNET_FLAG_RELOAD
+    INTERNET_FLAG_RESYNCHRONIZE
+    INTERNET_FLAG_TRANSFER_ASCII
+    INTERNET_FLAG_TRANSFER_BINARY
+    INTERNET_INVALID_PORT_NUMBER
+    INTERNET_INVALID_STATUS_CALLBACK
+    INTERNET_OPEN_TYPE_DIRECT
+    INTERNET_OPEN_TYPE_PROXY
+    INTERNET_OPEN_TYPE_PROXY_PRECONFIG
+    INTERNET_OPTION_CONNECT_BACKOFF
+    INTERNET_OPTION_CONNECT_RETRIES
+    INTERNET_OPTION_CONNECT_TIMEOUT
+    INTERNET_OPTION_CONTROL_SEND_TIMEOUT
+    INTERNET_OPTION_CONTROL_RECEIVE_TIMEOUT
+    INTERNET_OPTION_DATA_SEND_TIMEOUT
+    INTERNET_OPTION_DATA_RECEIVE_TIMEOUT
+    INTERNET_OPTION_HANDLE_TYPE
+    INTERNET_OPTION_LISTEN_TIMEOUT
+    INTERNET_OPTION_PASSWORD
+    INTERNET_OPTION_READ_BUFFER_SIZE
+    INTERNET_OPTION_USER_AGENT
+    INTERNET_OPTION_USERNAME
+    INTERNET_OPTION_VERSION
+    INTERNET_OPTION_WRITE_BUFFER_SIZE
+    INTERNET_SERVICE_FTP
+    INTERNET_SERVICE_GOPHER
+    INTERNET_SERVICE_HTTP
+    INTERNET_STATUS_CLOSING_CONNECTION
+    INTERNET_STATUS_CONNECTED_TO_SERVER
+    INTERNET_STATUS_CONNECTING_TO_SERVER
+    INTERNET_STATUS_CONNECTION_CLOSED
+    INTERNET_STATUS_HANDLE_CLOSING
+    INTERNET_STATUS_HANDLE_CREATED
+    INTERNET_STATUS_NAME_RESOLVED
+    INTERNET_STATUS_RECEIVING_RESPONSE
+    INTERNET_STATUS_REDIRECT
+    INTERNET_STATUS_REQUEST_COMPLETE
+    INTERNET_STATUS_REQUEST_SENT
+    INTERNET_STATUS_RESOLVING_NAME
+    INTERNET_STATUS_RESPONSE_RECEIVED
+    INTERNET_STATUS_SENDING_REQUEST
+
+
+=head1 VERSION HISTORY
+
+=over
+
+=item * 0.082 (4 Sep 2001)
+
+=over
+
+=item *
+
+Fix passive FTP mode.  INTERNET_FLAG_PASSIVE was misspelled in earlier
+versions (as INTERNET_CONNECT_FLAG_PASSIVE) and wouldn't work.  Found
+by Steve Raynesford <stever@evolvecomm.com>.
+
+=back
+
+=item * 0.081 (25 Sep 1999)
+
+=over
+
+=item *
+
+Documentation converted to pod format by Jan Dubois <JanD@ActiveState.com>.
+
+=item *
+
+Minor changes from Perl 5.005xx compatibility.
+
+=back
+
+=item * 0.08 (14 Feb 1997)
+
+=over
+
+=item *
+
+fixed 2 more bugs in Option(s) related subs (thanks to Brian
+Helterline!).
+
+=item *
+
+Error() now gets error messages directly from WININET.DLL.
+
+=item *
+
+The PLL file now comes in 2 versions, one for Perl version 5.001
+(build 100) and one for Perl version 5.003 (build 300 and
+higher). Everybody should be happy now :)
+
+=item *
+
+added an installation program.
+
+=back
+
+=item * 0.07 (10 Feb 1997)
+
+=over
+
+=item *
+
+fixed a bug in Version() introduced with 0.06...
+
+=item *
+
+completely reworked PM file, fixed *lots* of minor bugs, and removed
+almost all the warnings with "perl -w".
+
+=back
+
+=item * 0.06 (26 Jan 1997)
+
+=over
+
+=item *
+
+fixed another hideous bug in "new" (the 'class' parameter was still
+missing).
+
+=item *
+
+added support for asynchronous operations (work still in embryo).
+
+=item *
+
+removed the ending \0 (ASCII zero) from the DLL version returned by
+"Version".
+
+=item *
+
+added a lot of constants.
+
+=item *
+
+added safefree() after every safemalloc() in C... wonder why I didn't
+it before :)
+
+=item *
+
+added TimeConvert, which actually works one way only.
+
+=back
+
+=item * 0.05f (29 Nov 1996)
+
+=over
+
+=item *
+
+fixed a bug in "new" (parameters passed were simply ignored).
+
+=item *
+
+fixed another bug: "Chdir" and "Cwd" were aliases of RMDIR instead of
+CD..
+
+=back
+
+=item * 0.05 (29 Nov 1996)
+
+=over
+
+=item *
+
+added "CrackURL" and "CreateURL".
+
+=item *
+
+corrected an error in TEST.PL (there was a GetUserAgent instead of
+UserAgent).
+
+=back
+
+=item * 0.04 (25 Nov 1996)
+
+=over
+
+=item *
+
+added "Version" to retrieve package and DLL versions.
+
+=item *
+
+added proxies and other options to "new".
+
+=item *
+
+changed "OpenRequest" and "Request" to read parameters from a hash.
+
+=item *
+
+added "SetOption/QueryOption" and a lot of relative functions
+(connect, username, password, useragent, etc.).
+
+=item *
+
+added "CanonicalizeURL" and "CombineURL".
+
+=item *
+
+"Error" covers a wider spectrum of errors.
+
+=back
+
+=item * 0.02 (18 Nov 1996)
+
+=over
+
+=item *
+
+added support for HTTP sessions and requests.
+
+=back
+
+=item * 0.01 (11 Nov 1996)
+
+=over
+
+=item *
+
+fetching of HTTP, FTP and GOPHER URLs.
+
+=item *
+
+complete set of commands to manage an FTP session.
+
+=back
+
+=back
+
+=head1 AUTHOR
+
+Version 0.08 (14 Feb 1997) by Aldo Calpini <a.calpini@romagiubileo.it>
+
+
+=head1 CREDITS
+
+Win32::Internet is based on the Win32::Registry code written by Jesse
+Dougherty.
+
+Additional thanks to: Carl Tichler for his help in the initial
+development; Tore Haraldsen, Brian Helterline for the bugfixes; Dave
+Roth for his great source code examples.
+
+
+=head1 DISCLAIMER
+
+This program is FREE; you can redistribute, modify, disassemble, or
+even reverse engineer this software at your will. Keep in mind,
+however, that NOTHING IS GUARANTEED to work and everything you do is
+AT YOUR OWN RISK - I will not take responsability for any damage, loss
+of money and/or health that may arise from the use of this program!
+
+This is distributed under the terms of Larry Wall's Artistic License.
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Job.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Job.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Job.pm	(revision 14139)
@@ -0,0 +1,369 @@
+package Win32::Job;
+
+use strict;
+use base qw(DynaLoader);
+use vars qw($VERSION);
+
+$VERSION = '0.01';
+
+use constant WIN32s => 0;
+use constant WIN9X  => 1;
+use constant WINNT  => 2;
+
+my @ver = Win32::GetOSVersion;
+die "Win32::Job is not supported on $ver[0]" unless (
+    $ver[4] == WINNT and (
+	$ver[1] > 5 or
+	($ver[1] == 5 and $ver[2] > 0) or
+	($ver[1] == 5 and $ver[2] == 0 and $ver[3] >= 0)
+    )
+);
+
+Win32::Job->bootstrap($VERSION);
+
+1;
+
+__END__
+
+=head1 NAME
+
+Win32::Job - Run sub-processes in a "job" environment
+
+=head1 SYNOPSIS
+
+   use Win32::Job;
+   
+   my $job = Win32::Job->new;
+
+   # Run 'perl Makefile.PL' for 10 seconds
+   $job->spawn($Config{perlpath}, "perl Makefile.PL");
+   $job->run(10);
+
+=head1 PLATFORMS
+
+Win32::Job requires Windows 2000 or later. Windows 95, 98, NT, and Me are not
+supported.
+
+=head1 DESCRIPTION
+
+Windows 2000 introduced the concept of a "job": a collection of processes
+which can be controlled as a single unit. For example, you can reliably kill a
+process and all of its children by launching the process in a job, then
+telling Windows to kill all processes in the job.  Win32::Job makes this
+feature available to Perl.
+
+For example, imagine you want to allow 2 minutes for a process to complete.
+If you have control over the child process, you can probably just run it in
+the background, then poll every second to see if it has finished.
+
+That's fine as long as the child process doesn't spawn any child processes.
+What if it does? If you wrote the child process yourself and made an effort to
+clean up your child processes before terminating, you don't have to worry.
+If not, you will leave hanging processes (called "zombie" processes in Unix).
+
+With Win32::Job, just create a new Job, then use the job to spawn the child
+process. All I<its> children will also be created in the new Job. When you
+time out, just call the job's kill() method and the entire process tree will
+be terminated.
+
+=head1 Using Win32::Job
+
+The following methods are available:
+
+=over 4
+
+=item 1
+
+new()
+
+   new();
+
+Creates a new Job object using the Win32 API call CreateJobObject(). The job
+is created with a default security context, and is unnamed.
+
+Note: this method returns C<undef> if CreateJobObject() fails. Look at C<$^E>
+for more detailed error information.
+
+=item 2
+
+spawn()
+
+   spawn($exe, $args, \%opts);
+
+Creates a new process and associates it with the Job. The process is initially
+suspended, and can be resumed with one of the other methods. Uses the Win32
+API call CreateProcess(). Returns the PID of the newly created process.
+
+Note: this method returns C<undef> if CreateProcess() fails. See C<$^E> for
+more detailed error information. One reason this will fail is if the calling
+process is itself part of a job, and the job's security context does not allow
+child processes to be created in a different job context than the parent.
+
+The arguments are described here:
+
+=over 4
+
+=item 1
+
+$exe
+
+The executable program to run. This may be C<undef>, in which case the first
+argument in $args is the program to run.
+
+If this has path information in it, it is used "as is" and passed to
+CreateProcess(), which interprets it as either an absolute path, or a
+path relative to the current drive and directory. If you did not specify an
+extension, ".exe" is assumed.
+
+If there are no path separators (either backslashes or forward slashes),
+then Win32::Job will search the current directory and your PATH, looking
+for the file. In addition, if you did not specify an extension, then
+Win32::Job checks ".exe", ".com", and ".bat" in order. If it finds a ".bat"
+file, Win32::Job will actually call F<cmd.exe> and prepend "cmd.exe" to the
+$args.
+
+For example, assuming a fairly normal PATH:
+
+   spawn(q{c:\winnt\system\cmd.exe}, q{cmd /C "echo %PATH%"})
+   exefile: c:\winnt\system\cmd.exe
+   cmdline: cmd /C "echo %PATH%"
+
+   spawn("cmd.exe", q{cmd /C "echo %PATH%"})
+   exefile: c:\winnt\system\cmd.exe
+   cmdline: cmd /C "echo %PATH%"
+
+=item 2
+
+$args
+
+The commandline to pass to the executable program. The first word will be
+C<argv[0]> to an EXE file, so you should repeat the command name in $args.
+
+For example:
+
+   $job->spawn($Config{perlpath}, "perl foo.pl");
+
+In this case, the "perl" is ignored, since perl.exe doesn't use it.
+
+=item 3
+
+%opts
+
+A hash reference for advanced options. This parameter is optional.
+the following keys are recognized:
+
+=over 4
+
+=item cwd
+
+A string specifying the current directory of the new process.
+
+By default, the process shares the parent's current directory, C<.>.
+
+=item new_console
+
+A boolean; if true, the process is started in a new console window.
+
+By default, the process shares the parent's console. This has no effect on GUI
+programs which do not interact with the console.
+
+=item window_attr
+
+Either C<minimized>, which displays the new window minimized; C<maximimzed>,
+which shows the new window maximized; or C<hidden>, which does not display the
+new window.
+
+By default, the window is displayed using its application's defaults.
+
+=item new_group
+
+A boolean; if true, the process is the root of a new process group. This
+process group includes all descendents of the child.
+
+By default, the process is in the parent's process group (but in a new job).
+
+=item no_window
+
+A boolean; if true, the process is run without a console window. This flag is
+only valid when starting a console application, otherwise it is ignored. If you
+are launching a GUI application, use the C<window_attr> tag instead.
+
+By default, the process shares its parent's console.
+
+=item stdin
+
+An open input filehandle, or the name of an existing file. The resulting
+filehandle will be used for the child's standard input handle.
+
+By default, the child process shares the parent's standard input.
+
+=item stdout
+
+An open output filehandle or filename (will be opened for append). The
+resulting filehandle will be used for the child's standard output handle.
+
+By default, the child process shares the parent's standard output.
+
+=item stderr
+
+An open output filehandle or filename (will be opened for append). The
+resulting filehandle will be used for the child's standard error handle.
+
+By default, the child process shares the parent's standard error.
+
+=back
+
+Unrecognized keys are ignored.
+
+=back
+
+=item 3
+
+run()
+
+   run($timeout, $which);
+
+Provides a simple way to run the programs with a time limit. The
+$timeout is in seconds with millisecond accuracy. This call blocks for
+up to $timeout seconds, or until the processes finish.
+
+The $which parameter specifies whether to wait for I<all> processes to
+complete within the $timeout, or whether to wait for I<any> process to
+complete. You should set this to a boolean, where a true value means to
+wait for I<all> the processes to complete, and a false value to wait
+for I<any>. If you do not specify $which, it defaults to true (C<all>).
+
+Returns a boolean indicating whether the processes exited by themselves,
+or whether the time expired. A true return value means the processes
+exited normally; a false value means one or more processes was killed
+will $timeout.
+
+You can get extended information on process exit codes using the
+status() method.
+
+For example, this is how to build two perl modules at the same time,
+with a 5 minute timeout:
+
+   use Win32::Job;
+   $job = Win32::Job->new;
+   $job->spawn("cmd", q{cmd /C "cd Mod1 && nmake"});
+   $job->spawn("cmd", q{cmd /C "cd Mod2 && nmake"});
+   $ok = $job->run(5 * 60);
+   print "Mod1 and Mod2 built ok!\n" if $ok;
+
+=item 4
+
+watch()
+
+   watch(\&handler, $interval, $which);
+
+   handler($job);
+
+Provides more fine-grained control over how to stop the programs.  You specify
+a callback and an interval in seconds, and Win32::Job will call the "watchdog"
+function at this interval, either until the processes finish or your watchdog
+tells Win32::Job to stop. You must return a value indicating whether to stop: a
+true value means to terminate the processes immediately.
+
+The $which parameter has the same meaning as run()'s.
+
+Returns a boolean with the same meaning as run()'s.
+
+The handler may do anything it wants. One useful application of the watch()
+method is to check the filesize of the output file, and terminate the Job if
+the file becomes larger than a certain limit:
+
+   use Win32::Job;
+   $job = Win32::Job->new;
+   $job->spawn("cmd", q{cmd /C "cd Mod1 && nmake"}, {
+       stdin  => 'NUL', # the NUL device
+       stdout => 'stdout.log',
+       stderr => 'stdout.log',
+   });
+   $ok = $job->watch(sub {
+       return 1 if -s "stdout.log" > 1_000_000;
+   }, 1);
+   print "Mod1 built ok!\n" if $ok;
+
+=item 5
+
+status()
+
+   status()
+
+Returns a hash containing information about the processes in the job.
+Only returns valid information I<after> calling either run() or watch();
+returns an empty hash if you have not yet called them. May be called from a
+watch() callback, in which case the C<exitcode> field should be ignored.
+
+The keys of the hash are the process IDs; the values are a subhash
+containing the following keys:
+
+=over 4
+
+=item exitcode
+
+The exit code returned by the process. If the process was killed because
+of a timeout, the value is 293.
+
+=item time
+
+The time accumulated by the process. This is yet another subhash containing
+the subkeys (i) C<user>, the amount of time the process spent in user
+space; (ii) C<kernel>, the amount of time the process spent in kernel space;
+and (iii) C<elapsed>, the total time the process was running.
+
+=back
+
+=item 6
+
+kill()
+
+   kill();
+
+Kills all processes and subprocesses in the Job. Has no return value.
+Sets the exit code to all processes killed to 293, which you can check
+for in the status() return value.
+
+=back
+
+=head1 SEE ALSO
+
+For more information about jobs, see Microsoft's online help at
+
+   http://msdn.microsoft.com/
+
+For other modules which do similar things (but not as well), see:
+
+=over 4
+
+=item 1
+
+Win32::Process
+
+Low-level access to creating processes in Win32. See L<Win32::Process>.
+
+=item 2
+
+Win32::Console
+
+Low-level access to consoles in Win32. See L<Win32::Console>.
+
+=item 3
+
+Win32::ProcFarm
+
+Manage pools of threads to perform CPU-intensive tasks on Windows. See
+L<Win32::ProcFarm>.
+
+=back
+
+=head1 AUTHOR
+
+ActiveState (support@ActiveState.com)
+
+=head1 COPYRIGHT
+
+Copyright (c) 2002, ActiveState Corporation. All Rights Reserved.
+
+=cut
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Mutex.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Mutex.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Mutex.pm	(revision 14139)
@@ -0,0 +1,124 @@
+#---------------------------------------------------------------------
+package Win32::Mutex;
+#
+# Copyright 1998 Christopher J. Madsen
+#
+# Created: 3 Feb 1998 from the ActiveWare version
+#   (c) 1995 Microsoft Corporation. All rights reserved.
+#       Developed by ActiveWare Internet Corp., http://www.ActiveWare.com
+#
+#   Other modifications (c) 1997 by Gurusamy Sarathy <gsar@activestate.com>
+#
+# Author: Christopher J. Madsen <chris_madsen@geocities.com>
+# Version: 1.00 (6-Feb-1998)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the same terms as Perl itself.
+#
+# 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 either the
+# GNU General Public License or the Artistic License for more details.
+#
+# Use Win32 mutex objects for synchronization
+#---------------------------------------------------------------------
+
+$VERSION = '1.02';
+
+use Win32::IPC 1.00 '/./';      # Import everything
+require Exporter;
+require DynaLoader;
+
+@ISA = qw(Exporter DynaLoader Win32::IPC);
+@EXPORT_OK = qw(
+  wait_all wait_any
+);
+
+bootstrap Win32::Mutex;
+
+sub Create  { $_[0] = Win32::Mutex->new(@_[1..2]) }
+sub Open  { $_[0] = Win32::Mutex->open($_[1]) }
+sub Release { &release }
+
+1;
+__END__
+
+=head1 NAME
+
+Win32::Mutex - Use Win32 mutex objects from Perl
+
+=head1 SYNOPSIS
+
+	require Win32::Mutex;
+
+	$mutex = Win32::Mutex->new($initial,$name);
+	$mutex->wait;
+
+=head1 DESCRIPTION
+
+This module allows access to the Win32 mutex objects.  The C<wait>
+method and C<wait_all> & C<wait_any> functions are inherited from the
+L<"Win32::IPC"> module.
+
+=head2 Methods
+
+=over 4
+
+=item $mutex = Win32::Mutex->new([$initial, [$name]])
+
+Constructor for a new mutex object.  If C<$initial> is true, requests
+immediate ownership of the mutex (default false).  If C<$name> is
+omitted, creates an unnamed mutex object.
+
+If C<$name> signifies an existing mutex object, then C<$initial> is
+ignored and the object is opened.
+
+=item $mutex = Win32::Mutex->open($name)
+
+Constructor for opening an existing mutex object.
+
+=item $mutex->release
+
+Release ownership of a C<$mutex>.  You should have obtained ownership
+of the mutex through C<new> or one of the wait functions.  Returns
+true if successful.
+
+=item $mutex->wait([$timeout])
+
+Wait for ownership of C<$mutex>.  See L<"Win32::IPC">.
+
+=back
+
+=head2 Deprecated Functions and Methods
+
+B<Win32::Mutex> still supports the ActiveWare syntax, but its use is
+deprecated.
+
+=over 4
+
+=item Create($MutObj,$Initial,$Name)
+
+Use C<$MutObj = Win32::Mutex-E<gt>new($Initial,$Name)> instead.
+
+=item Open($MutObj,$Name)
+
+Use C<$MutObj = Win32::Mutex-E<gt>open($Name)> instead.
+
+=item $MutObj->Release()
+
+Use C<$MutObj-E<gt>release> instead.
+
+=back
+
+=head1 AUTHOR
+
+Christopher J. Madsen E<lt>F<chris_madsen@geocities.com>E<gt>
+
+Loosely based on the original module by ActiveWare Internet Corp.,
+F<http://www.ActiveWare.com>
+
+=cut
+
+# Local Variables:
+# tmtrack-file-task: "Win32::Mutex"
+# End:
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/NetAdmin.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/NetAdmin.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/NetAdmin.pm	(revision 14139)
@@ -0,0 +1,418 @@
+package Win32::NetAdmin;
+
+#
+#NetAdmin.pm
+#Written by Douglas_Lankshear@ActiveWare.com
+#
+
+$VERSION = '0.08';
+
+require Exporter;
+require DynaLoader;
+
+die "The Win32::NetAdmin module works only on Windows NT" if(!Win32::IsWinNT() );
+
+@ISA= qw( Exporter DynaLoader );
+# Items to export into callers namespace by default. Note: do not export
+# names by default without a very good reason. Use EXPORT_OK instead.
+# Do not simply export all your public functions/methods/constants.
+@EXPORT = qw(
+	DOMAIN_ALIAS_RID_ACCOUNT_OPS
+	DOMAIN_ALIAS_RID_ADMINS
+	DOMAIN_ALIAS_RID_BACKUP_OPS
+	DOMAIN_ALIAS_RID_GUESTS
+	DOMAIN_ALIAS_RID_POWER_USERS
+	DOMAIN_ALIAS_RID_PRINT_OPS
+	DOMAIN_ALIAS_RID_REPLICATOR
+	DOMAIN_ALIAS_RID_SYSTEM_OPS
+	DOMAIN_ALIAS_RID_USERS
+	DOMAIN_GROUP_RID_ADMINS
+	DOMAIN_GROUP_RID_GUESTS
+	DOMAIN_GROUP_RID_USERS
+	DOMAIN_USER_RID_ADMIN
+	DOMAIN_USER_RID_GUEST
+	FILTER_TEMP_DUPLICATE_ACCOUNT
+	FILTER_NORMAL_ACCOUNT
+	FILTER_INTERDOMAIN_TRUST_ACCOUNT
+	FILTER_WORKSTATION_TRUST_ACCOUNT
+	FILTER_SERVER_TRUST_ACCOUNT
+	SV_TYPE_WORKSTATION
+	SV_TYPE_SERVER
+	SV_TYPE_SQLSERVER
+	SV_TYPE_DOMAIN_CTRL
+	SV_TYPE_DOMAIN_BAKCTRL
+	SV_TYPE_TIMESOURCE
+	SV_TYPE_AFP
+	SV_TYPE_NOVELL
+	SV_TYPE_DOMAIN_MEMBER
+	SV_TYPE_PRINT
+	SV_TYPE_PRINTQ_SERVER
+	SV_TYPE_DIALIN
+	SV_TYPE_DIALIN_SERVER
+	SV_TYPE_XENIX_SERVER
+	SV_TYPE_NT
+	SV_TYPE_WFW
+	SV_TYPE_POTENTIAL_BROWSER
+	SV_TYPE_BACKUP_BROWSER
+	SV_TYPE_MASTER_BROWSER
+	SV_TYPE_DOMAIN_MASTER
+	SV_TYPE_DOMAIN_ENUM
+	SV_TYPE_SERVER_UNIX
+	SV_TYPE_SERVER_MFPN
+	SV_TYPE_SERVER_NT
+	SV_TYPE_SERVER_OSF
+	SV_TYPE_SERVER_VMS
+	SV_TYPE_WINDOWS
+	SV_TYPE_DFS
+	SV_TYPE_ALTERNATE_XPORT
+	SV_TYPE_LOCAL_LIST_ONLY
+	SV_TYPE_ALL
+	UF_TEMP_DUPLICATE_ACCOUNT
+	UF_NORMAL_ACCOUNT
+	UF_INTERDOMAIN_TRUST_ACCOUNT
+	UF_WORKSTATION_TRUST_ACCOUNT
+	UF_SERVER_TRUST_ACCOUNT
+	UF_MACHINE_ACCOUNT_MASK
+	UF_ACCOUNT_TYPE_MASK
+	UF_DONT_EXPIRE_PASSWD
+	UF_SETTABLE_BITS
+	UF_SCRIPT
+	UF_ACCOUNTDISABLE
+	UF_HOMEDIR_REQUIRED
+	UF_LOCKOUT
+	UF_PASSWD_NOTREQD
+	UF_PASSWD_CANT_CHANGE
+	USE_FORCE
+	USE_LOTS_OF_FORCE
+	USE_NOFORCE
+	USER_PRIV_MASK
+	USER_PRIV_GUEST
+	USER_PRIV_USER
+	USER_PRIV_ADMIN
+);
+
+@EXPORT_OK = qw(
+    GetError
+    GetDomainController
+    GetAnyDomainController
+    UserCreate
+    UserDelete
+    UserGetAttributes
+    UserSetAttributes
+    UserChangePassword
+    UsersExist
+    GetUsers
+    GroupCreate
+    GroupDelete
+    GroupGetAttributes
+    GroupSetAttributes
+    GroupAddUsers
+    GroupDeleteUsers
+    GroupIsMember
+    GroupGetMembers
+    LocalGroupCreate
+    LocalGroupDelete
+    LocalGroupGetAttributes
+    LocalGroupSetAttributes
+    LocalGroupIsMember
+    LocalGroupGetMembers
+    LocalGroupGetMembersWithDomain
+    LocalGroupAddUsers
+    LocalGroupDeleteUsers
+    GetServers
+    GetTransports
+    LoggedOnUsers
+    GetAliasFromRID
+    GetUserGroupFromRID
+    GetServerDisks
+);
+$EXPORT_TAGS{ALL}= \@EXPORT_OK;
+
+=head1 NAME
+
+Win32::NetAdmin - manage network groups and users in perl
+
+=head1 SYNOPSIS
+
+	use Win32::NetAdmin;
+
+=head1 DESCRIPTION
+
+This module offers control over the administration of groups and users over a
+network.
+
+=head1 FUNCTIONS
+
+=head2 NOTE
+
+All of the functions return false if they fail, unless otherwise noted.
+When a function fails call Win32::NetAdmin::GetError() rather than
+GetLastError() or $^E to retrieve the error code.
+
+C<server> is optional for all the calls below. If not given the local machine is
+assumed.
+
+=over 10
+
+=item GetError()
+
+Returns the error code of the last call to this module.
+
+=item GetDomainController(server, domain, returnedName)
+
+Returns the name of the domain controller for server.
+
+=item GetAnyDomainController(server, domain, returnedName)
+
+Returns the name of any domain controller for a domain that is directly trusted
+by the server.
+
+=item UserCreate(server, userName, password, passwordAge, privilege, homeDir, comment, flags, scriptPath)
+
+Creates a user on server with password, passwordAge, privilege, homeDir, comment,
+flags, and scriptPath.
+
+=item UserDelete(server, user)
+
+Deletes a user from server.
+
+=item UserGetAttributes(server, userName, password, passwordAge, privilege, homeDir, comment, flags, scriptPath)
+
+Gets password, passwordAge, privilege, homeDir, comment, flags, and scriptPath
+for user.
+
+=item UserSetAttributes(server, userName, password, passwordAge, privilege, homeDir, comment, flags, scriptPath)
+
+Sets password, passwordAge, privilege, homeDir, comment, flags, and scriptPath
+for user.
+
+=item UserChangePassword(domainname, username, oldpassword, newpassword)
+
+Changes a users password. Can be run under any account.
+
+=item UsersExist(server, userName)
+
+Checks if a user exists.
+
+=item GetUsers(server, filter, userRef)
+
+Fills userRef with user names if it is an array reference and with the user
+names and the full names if it is a hash reference.
+
+=item GroupCreate(server, group, comment)
+
+Creates a group.
+
+=item GroupDelete(server, group)
+
+Deletes a group.
+
+=item GroupGetAttributes(server, groupName, comment)
+
+Gets the comment.
+
+=item GroupSetAttributes(server, groupName, comment)
+
+Sets the comment.
+
+=item GroupAddUsers(server, groupName, users)
+
+Adds a user to a group.
+
+=item GroupDeleteUsers(server, groupName, users)
+
+Deletes a users from a group.
+
+=item GroupIsMember(server, groupName, user)
+
+Returns TRUE if user is a member of groupName.
+
+=item GroupGetMembers(server, groupName, userArrayRef)
+
+Fills userArrayRef with the members of groupName.
+
+=item LocalGroupCreate(server, group, comment)
+
+Creates a local group.
+
+=item LocalGroupDelete(server, group)
+
+Deletes a local group.
+
+=item LocalGroupGetAttributes(server, groupName, comment)
+
+Gets the comment.
+
+=item LocalGroupSetAttributes(server, groupName, comment)
+
+Sets the comment.
+
+=item LocalGroupIsMember(server, groupName, user)
+
+Returns TRUE if user is a member of groupName.
+
+=item LocalGroupGetMembers(server, groupName, userArrayRef)
+
+Fills userArrayRef with the members of groupName.
+
+=item LocalGroupGetMembersWithDomain(server, groupName, userRef)
+
+This function is similar LocalGroupGetMembers but accepts an array or
+a hash reference. Unlike LocalGroupGetMembers it returns each user name
+as C<DOMAIN\USERNAME>. If a hash reference is given, the function
+returns to each user or group name the type (group, user, alias etc.).
+The possible types are as follows:
+
+  $SidTypeUser = 1;
+  $SidTypeGroup = 2;
+  $SidTypeDomain = 3;
+  $SidTypeAlias = 4;
+  $SidTypeWellKnownGroup = 5;
+  $SidTypeDeletedAccount = 6;
+  $SidTypeInvalid = 7;
+  $SidTypeUnknown = 8;
+
+=item LocalGroupAddUsers(server, groupName, users)
+
+Adds a user to a group.
+
+=item LocalGroupDeleteUsers(server, groupName, users)
+
+Deletes a users from a group.
+
+=item GetServers(server, domain, flags, serverRef)
+
+Gets an array of server names or an hash with the server names and the
+comments as seen in the Network Neighborhood or the server manager.
+For flags, see SV_TYPE_* constants.
+
+=item GetTransports(server, transportRef)
+
+Enumerates the network transports of a computer. If transportRef is an array
+reference, it is filled with the transport names. If transportRef is a hash
+reference then a hash of hashes is filled with the data for the transports.
+
+=item LoggedOnUsers(server, userRef)
+
+Gets an array or hash with the users logged on at the specified computer. If
+userRef is a hash reference, the value is a semikolon separated string of
+username, logon domain and logon server.
+
+=item GetAliasFromRID(server, RID, returnedName)
+
+=item GetUserGroupFromRID(server, RID, returnedName)
+
+Retrieves the name of an alias (i.e local group) or a user group for a RID
+from the specified server. These functions can be used for example to get the
+account name for the administrator account if it is renamed or localized.
+
+Possible values for C<RID>:
+
+  DOMAIN_ALIAS_RID_ACCOUNT_OPS
+  DOMAIN_ALIAS_RID_ADMINS
+  DOMAIN_ALIAS_RID_BACKUP_OPS
+  DOMAIN_ALIAS_RID_GUESTS
+  DOMAIN_ALIAS_RID_POWER_USERS
+  DOMAIN_ALIAS_RID_PRINT_OPS
+  DOMAIN_ALIAS_RID_REPLICATOR
+  DOMAIN_ALIAS_RID_SYSTEM_OPS
+  DOMAIN_ALIAS_RID_USERS
+  DOMAIN_GROUP_RID_ADMINS
+  DOMAIN_GROUP_RID_GUESTS
+  DOMAIN_GROUP_RID_USERS
+  DOMAIN_USER_RID_ADMIN
+  DOMAIN_USER_RID_GUEST
+
+=item GetServerDisks(server, arrayRef)
+
+Returns an array with the disk drives of the specified server. The array
+contains two-character strings (drive letter followed by a colon).
+
+=back
+
+=head1 EXAMPLE
+
+    # Simple script using Win32::NetAdmin to set the login script for
+    # all members of the NT group "Domain Users".  Only works if you
+    # run it on the PDC. (From Robert Spier <rspier@seas.upenn.edu>)
+    #
+    # FILTER_TEMP_DUPLICATE_ACCOUNTS
+    #	Enumerates local user account data on a domain controller.
+    #
+    # FILTER_NORMAL_ACCOUNT
+    #	Enumerates global user account data on a computer.
+    #
+    # FILTER_INTERDOMAIN_TRUST_ACCOUNT
+    #	Enumerates domain trust account data on a domain controller.
+    #
+    # FILTER_WORKSTATION_TRUST_ACCOUNT
+    #	Enumerates workstation or member server account data on a domain
+    #	controller.
+    #
+    # FILTER_SERVER_TRUST_ACCOUNT
+    #	Enumerates domain controller account data on a domain controller.
+
+
+    use Win32::NetAdmin qw(GetUsers GroupIsMember
+			   UserGetAttributes UserSetAttributes);
+
+    my %hash;
+    GetUsers("", FILTER_NORMAL_ACCOUNT , \%hash)
+	or die "GetUsers() failed: $^E";
+
+    foreach (keys %hash) {
+	my ($password, $passwordAge, $privilege,
+	    $homeDir, $comment, $flags, $scriptPath);
+	if (GroupIsMember("", "Domain Users", $_)) {
+	    print "Updating $_ ($hash{$_})\n";
+	    UserGetAttributes("", $_, $password, $passwordAge, $privilege,
+			      $homeDir, $comment, $flags, $scriptPath)
+		or die "UserGetAttributes() failed: $^E";
+	    $scriptPath = "dnx_login.bat"; # this is the new login script
+	    UserSetAttributes("", $_, $password, $passwordAge, $privilege,
+			      $homeDir, $comment, $flags, $scriptPath)
+		or die "UserSetAttributes() failed: $^E";
+	}
+    }
+
+=cut
+
+sub AUTOLOAD {
+    my($constname);
+    ($constname = $AUTOLOAD) =~ s/.*:://;
+    #reset $! to zero to reset any current errors.
+    local $! = 0;
+    my $val = constant($constname);
+    if ($! != 0) {
+	if ($! =~ /Invalid/) {
+	    $AutoLoader::AUTOLOAD = $AUTOLOAD;
+	    goto &AutoLoader::AUTOLOAD;
+	}
+	else {
+	    ($pack,$file,$line) = caller;
+	    die "Your vendor has not defined Win32::NetAdmin macro $constname, used in $file at line $line.";
+	}
+    }
+    eval "sub $AUTOLOAD { $val }";
+    goto &$AUTOLOAD;
+}
+
+$SidTypeUser = 1;
+$SidTypeGroup = 2;
+$SidTypeDomain = 3;
+$SidTypeAlias = 4;
+$SidTypeWellKnownGroup = 5;
+$SidTypeDeletedAccount = 6;
+$SidTypeInvalid = 7;
+$SidTypeUnknown = 8;
+
+sub GetError() {
+    our $__lastError;
+    $__lastError;
+}
+
+bootstrap Win32::NetAdmin;
+
+1;
+__END__
+
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/NetResource.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/NetResource.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/NetResource.pm	(revision 14139)
@@ -0,0 +1,456 @@
+package Win32::NetResource;
+
+require Exporter;
+require DynaLoader;
+require AutoLoader;
+
+$VERSION = '0.053';
+
+@ISA = qw(Exporter DynaLoader);
+# Items to export into callers namespace by default. Note: do not export
+# names by default without a very good reason. Use EXPORT_OK instead.
+# Do not simply export all your public functions/methods/constants.
+@EXPORT = qw(
+    RESOURCEDISPLAYTYPE_DOMAIN
+    RESOURCEDISPLAYTYPE_FILE
+    RESOURCEDISPLAYTYPE_GENERIC
+    RESOURCEDISPLAYTYPE_GROUP
+    RESOURCEDISPLAYTYPE_SERVER
+    RESOURCEDISPLAYTYPE_SHARE
+    RESOURCEDISPLAYTYPE_TREE
+    RESOURCETYPE_ANY
+    RESOURCETYPE_DISK
+    RESOURCETYPE_PRINT
+    RESOURCETYPE_UNKNOWN
+    RESOURCEUSAGE_CONNECTABLE
+    RESOURCEUSAGE_CONTAINER
+    RESOURCEUSAGE_RESERVED
+    RESOURCE_CONNECTED
+    RESOURCE_GLOBALNET
+    RESOURCE_REMEMBERED
+    STYPE_DISKTREE
+    STYPE_PRINTQ
+    STYPE_DEVICE
+    STYPE_IPC
+    STYPE_SPECIAL
+    SHARE_NETNAME_PARMNUM
+    SHARE_TYPE_PARMNUM
+    SHARE_REMARK_PARMNUM
+    SHARE_PERMISSIONS_PARMNUM
+    SHARE_MAX_USES_PARMNUM
+    SHARE_CURRENT_USES_PARMNUM
+    SHARE_PATH_PARMNUM
+    SHARE_PASSWD_PARMNUM
+    SHARE_FILE_SD_PARMNUM
+);
+
+@EXPORT_OK = qw(
+    GetSharedResources
+    AddConnection
+    CancelConnection
+    WNetGetLastError
+    GetError
+    GetUNCName
+    NetShareAdd
+    NetShareCheck
+    NetShareDel
+    NetShareGetInfo
+    NetShareSetInfo
+);
+
+=head1 NAME
+
+Win32::NetResource - manage network resources in perl
+
+=head1 SYNOPSIS
+
+    use Win32::NetResource;
+
+    $ShareInfo = {
+                    'path' => "C:\\MyShareDir",
+                    'netname' => "MyShare",
+                    'remark' => "It is good to share",
+                    'passwd' => "",
+                    'current-users' =>0,
+                    'permissions' => 0,
+                    'maxusers' => -1,
+                    'type'  => 0,
+                    };
+    
+    Win32::NetResource::NetShareAdd( $ShareInfo,$parm )
+        or die "unable to add share";
+
+
+=head1 DESCRIPTION
+
+This module offers control over the network resources of Win32.Disks,
+printers etc can be shared over a network.
+
+=head1 DATA TYPES
+
+There are two main data types required to control network resources.
+In Perl these are represented by hash types.
+
+=over 4
+
+=item %NETRESOURCE
+
+    KEY                    VALUE
+    
+    'Scope'         =>  Scope of an Enumeration
+			RESOURCE_CONNECTED,
+			RESOURCE_GLOBALNET,
+			RESOURCE_REMEMBERED.
+    
+    'Type'          =>  The type of resource to Enum
+			RESOURCETYPE_ANY    All resources
+			RESOURCETYPE_DISK    Disk resources
+			RESOURCETYPE_PRINT    Print resources
+    
+    'DisplayType'   =>  The way the resource should be displayed.
+			RESOURCEDISPLAYTYPE_DOMAIN    
+			The object should be displayed as a domain.
+			RESOURCEDISPLAYTYPE_GENERIC    
+			The method used to display the object does not matter.
+			RESOURCEDISPLAYTYPE_SERVER    
+			The object should be displayed as a server.
+			RESOURCEDISPLAYTYPE_SHARE    
+			The object should be displayed as a sharepoint.
+    
+    'Usage'         =>  Specifies the Resources usage:
+			RESOURCEUSAGE_CONNECTABLE
+			RESOURCEUSAGE_CONTAINER.
+    
+    'LocalName'     =>  Name of the local device the resource is 
+			connected to.
+    
+    'RemoteName'    =>  The network name of the resource.
+    
+    'Comment'       =>  A string comment.
+    
+    'Provider'      =>  Name of the provider of the resource.
+
+=back    
+
+=item %SHARE_INFO
+
+This hash represents the SHARE_INFO_502 struct.
+
+=over 4
+
+    KEY                    VALUE
+    'netname'        =>    Name of the share.
+    'type'           =>    type of share.
+    'remark'         =>    A string comment.
+    'permissions'    =>    Permissions value
+    'maxusers'       =>    the max # of users.
+    'current-users'  =>    the current # of users.
+    'path'           =>    The path of the share.
+    'passwd'         =>    A password if one is req'd
+
+=back
+
+=head1 FUNCTIONS
+
+=head2 NOTE
+
+All of the functions return false if they fail.
+
+=over 4
+
+=item GetSharedResources(\@Resources,dwType,\%NetResource = NULL)
+
+Creates a list in @Resources of %NETRESOURCE hash references.
+
+The return value indicates whether there was an error in accessing
+any of the shared resources.  All the shared resources that were
+encountered (until the point of an error, if any) are pushed into
+@Resources as references to %NETRESOURCE hashes.  See example
+below.  The \%NetResource argument is optional.  If it is not supplied,
+the root (that is, the topmost container) of the network is assumed,
+and all network resources available from the toplevel container will
+be enumerated.
+
+=item AddConnection(\%NETRESOURCE,$Password,$UserName,$Connection)
+
+Makes a connection to a network resource specified by %NETRESOURCE
+
+=item CancelConnection($Name,$Connection,$Force)
+
+Cancels a connection to a network resource connected to local device 
+$name.$Connection is either 1 - persistent connection or 0, non-persistent.
+
+=item WNetGetLastError($ErrorCode,$Description,$Name)
+
+Gets the Extended Network Error.
+
+=item GetError( $ErrorCode )
+
+Gets the last Error for a Win32::NetResource call.
+
+=item GetUNCName( $UNCName, $LocalPath );
+
+Returns the UNC name of the disk share connected to $LocalPath in $UNCName.
+$LocalPath should be a drive based path. e.g. "C:\\share\\subdir"
+
+=back
+
+=head2 NOTE
+
+$servername is optional for all the calls below. (if not given the
+local machine is assumed.)
+
+=over 4
+
+=item NetShareAdd(\%SHARE,$parm_err,$servername = NULL )
+
+Add a share for sharing.
+
+=item NetShareCheck($device,$type,$servername = NULL )
+
+Check if a directory or a device is available for connection from the
+network through a share.  This includes all directories that are
+reachable through a shared directory or device, meaning that if C:\foo
+is shared, C:\foo\bar is also available for sharing.  This means that
+this function is pretty useless, given that by default every disk
+volume has an administrative share such as "C$" associated with its
+root directory.
+
+$device must be a drive name, directory, or a device.  For example,
+"C:", "C:\dir", "LPT1", "D$", "IPC$" are all valid as the $device
+argument.  $type is an output argument that will be set to one of
+the following constants that describe the type of share:
+
+    STYPE_DISKTREE     Disk drive 
+    STYPE_PRINTQ       Print queue 
+    STYPE_DEVICE       Communication device 
+    STYPE_IPC          Interprocess communication (IPC) 
+    STYPE_SPECIAL      Special share reserved for interprocess
+                         communication (IPC$) or remote administration
+                         of the server (ADMIN$). Can also refer to
+                         administrative shares such as C$, D$, etc.
+
+=item NetShareDel( $netname, $servername = NULL )
+
+Remove a share from a machines list of shares.
+
+=item NetShareGetInfo( $netname, \%SHARE,$servername=NULL )
+
+Get the %SHARE_INFO information about the share $netname on the
+server $servername.
+
+=item NetShareSetInfo( $netname,\%SHARE,$parm_err,$servername=NULL)
+
+Set the information for share $netname.
+
+=back
+
+=head1 EXAMPLE
+
+=over 4
+
+=item Enumerating all resources on the network
+
+    #
+    # This example displays all the share points in the entire
+    # visible part of the network.
+    #
+
+    use strict;
+    use Win32::NetResource qw(:DEFAULT GetSharedResources GetError);
+    my $resources = [];
+    unless(GetSharedResources($resources, RESOURCETYPE_ANY)) {
+	my $err;
+	GetError($err);
+	warn Win32::FormatMessage($err);
+    }
+
+    foreach my $href (@$resources) {
+	next if ($$href{DisplayType} != RESOURCEDISPLAYTYPE_SHARE);
+	print "-----\n";
+	foreach( keys %$href){
+	    print "$_: $href->{$_}\n";
+	}
+    }
+
+=item Enumerating all resources on a particular host
+
+    #
+    # This example displays all the share points exported by the local
+    # host.
+    #
+
+    use strict;
+    use Win32::NetResource qw(:DEFAULT GetSharedResources GetError);
+    if (GetSharedResources(my $resources, RESOURCETYPE_ANY,
+			   { RemoteName => "\\\\" . Win32::NodeName() }))
+    {
+	foreach my $href (@$resources) {
+	    print "-----\n";
+	    foreach(keys %$href) { print "$_: $href->{$_}\n"; }
+	}
+    }
+
+=back
+
+=head1 AUTHOR
+
+Jesse Dougherty for Hip Communications.
+
+Additional general cleanups and bug fixes by Gurusamy Sarathy <gsar@activestate.com>.
+
+=cut
+
+sub AUTOLOAD {
+    # This AUTOLOAD is used to 'autoload' constants from the constant()
+    # XS function.  If a constant is not found then control is passed
+    # to the AUTOLOAD in AutoLoader.
+
+    my($constname);
+    ($constname = $AUTOLOAD) =~ s/.*:://;
+    #reset $! to zero to reset any current errors.
+    local $! = 0;
+    my $val = constant($constname, @_ ? $_[0] : 0);
+    if ($! != 0) {
+        if ($! =~ /Invalid/) {
+            $AutoLoader::AUTOLOAD = $AUTOLOAD;
+            goto &AutoLoader::AUTOLOAD;
+        }
+        else {
+            ($pack,$file,$line) = caller;
+            die "Your vendor has not defined Win32::NetResource macro $constname, used at $file line $line.
+";
+        }
+    }
+    eval "sub $AUTOLOAD { $val }";
+    goto &$AUTOLOAD;
+}
+
+sub AddConnection
+{
+    my $h = $_[0];
+    die "AddConnection: HASH reference required" unless ref($h) eq "HASH";
+
+    #
+    # The last four items *must* not be deallocated until the
+    # _AddConnection() completes (since the packed structure is
+    # pointing into these values.
+    #
+    my $netres = pack( 'i4 p4', $h->{Scope},
+    				$h->{Type},
+				$h->{DisplayType},
+				$h->{Usage},
+				$h->{LocalName},
+				$h->{RemoteName},
+				$h->{Comment},
+				$h->{Provider});
+    _AddConnection($netres,$_[1],$_[2],$_[3]);
+}
+
+#use Data::Dumper;
+
+sub GetSharedResources
+{
+    die "GetSharedResources: ARRAY reference required"
+	if defined $_[0] and ref($_[0]) ne "ARRAY";
+
+    my $aref = [];
+
+    # Get the shared resources.
+
+    my $ret;
+
+    if (@_ > 2 and $_[2]) {
+	my $netres = pack('i4 p4', @{$_[2]}{qw(Scope
+					       Type
+					       DisplayType
+					       Usage
+					       LocalName
+					       RemoteName
+					       Comment
+					       Provider)});
+	$ret = _GetSharedResources( $aref , $_[1], $netres );
+    }
+    else {
+	$ret = _GetSharedResources( $aref , $_[1] );
+    }
+    
+    # build the array of hashes in $_[0]
+#   print Dumper($aref);    
+    foreach ( @$aref ) {
+	my %hash;
+	@hash{'Scope',
+	      'Type',
+	      'DisplayType',
+	      'Usage',
+	      'LocalName',
+	      'RemoteName',
+	      'Comment',
+	      'Provider'} = split /\001/, $_;
+	push @{$_[0]}, \%hash;
+    }
+
+    $ret;
+}
+
+sub NetShareAdd
+{
+    my $shareinfo = _hash2SHARE( $_[0] );
+    _NetShareAdd($shareinfo,$_[1], $_[2] || "");
+}
+
+sub NetShareGetInfo
+{
+    my ($netinfo,$val);
+    $val = _NetShareGetInfo( $_[0],$netinfo,$_[2] || "");
+    %{$_[1]} = %{_SHARE2hash( $netinfo )};    
+    $val;
+}
+
+sub NetShareSetInfo
+{
+    my $shareinfo = _hash2SHARE( $_[1] );
+    _NetShareSetInfo( $_[0],$shareinfo,$_[2],$_[3] || "");
+}
+
+
+# These are private functions to work with the ShareInfo structure.
+# please note that the implementation of these calls requires the
+# SHARE_INFO_502 level of information.
+
+sub _SHARE2hash
+{
+    my %hash = ();
+    @hash{'type',
+          'permissions',
+          'maxusers',
+          'current-users',
+          'remark',
+          'netname',
+          'path',
+          'passwd'} = unpack('i4 A257 A81 A257 A257',$_[0]);
+
+    return \%hash;
+}
+
+sub _hash2SHARE
+{
+    my $h = $_[0];
+    die "Argument must be a HASH reference" unless ref($h) eq "HASH";
+
+    return pack 'i4 a257 a81 a257 a257',
+		 @$h{'type',
+		    'permissions',
+		    'maxusers',
+		    'current-users',
+		    'remark',
+		    'netname',
+		    'path',
+		    'passwd'};
+}
+
+
+bootstrap Win32::NetResource;
+
+1;
+__END__
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/ODBC.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/ODBC.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/ODBC.pm	(revision 14139)
@@ -0,0 +1,1493 @@
+package Win32::ODBC;
+
+$VERSION = '0.032';
+
+# Win32::ODBC.pm
+#       +==========================================================+
+#       |                                                          |
+#       |                     ODBC.PM package                      |
+#       |                     ---------------                      |
+#       |                                                          |
+#       | Copyright (c) 1996, 1997 Dave Roth. All rights reserved. |
+#       |   This program is free software; you can redistribute    |
+#       | it and/or modify it under the same terms as Perl itself. |
+#       |                                                          |
+#       +==========================================================+
+#
+#
+#         based on original code by Dan DeMaggio (dmag@umich.edu)
+#
+#	Use under GNU General Public License or Larry Wall's "Artistic License"
+#
+#	Check the README.TXT file that comes with this package for details about
+#	it's history.
+#
+
+require Exporter;
+require DynaLoader;
+
+$ODBCPackage = "Win32::ODBC";
+$ODBCPackage::Version = 970208;
+$::ODBC = $ODBCPackage;
+$CacheConnection = 0;
+
+    #   Reserve ODBC in the main namespace for US!
+*ODBC::=\%Win32::ODBC::;
+
+
+@ISA= qw( Exporter DynaLoader );
+    # Items to export into callers namespace by default. Note: do not export
+    # names by default without a very good reason. Use EXPORT_OK instead.
+    # Do not simply export all your public functions/methods/constants.
+@EXPORT = qw(
+            ODBC_ADD_DSN
+            ODBC_REMOVE_DSN
+            ODBC_CONFIG_DSN
+            ODBC_ADD_SYS_DSN
+            ODBC_REMOVE_SYS_DSN
+            ODBC_CONFIG_SYS_DSN
+
+            SQL_DONT_CLOSE
+            SQL_DROP
+            SQL_CLOSE
+            SQL_UNBIND
+            SQL_RESET_PARAMS
+
+            SQL_FETCH_NEXT
+            SQL_FETCH_FIRST
+            SQL_FETCH_LAST
+            SQL_FETCH_PRIOR
+            SQL_FETCH_ABSOLUTE
+            SQL_FETCH_RELATIVE
+            SQL_FETCH_BOOKMARK
+
+            SQL_COLUMN_COUNT
+            SQL_COLUMN_NAME
+            SQL_COLUMN_TYPE
+            SQL_COLUMN_LENGTH
+            SQL_COLUMN_PRECISION
+            SQL_COLUMN_SCALE
+            SQL_COLUMN_DISPLAY_SIZE
+            SQL_COLUMN_NULLABLE
+            SQL_COLUMN_UNSIGNED
+            SQL_COLUMN_MONEY
+            SQL_COLUMN_UPDATABLE
+            SQL_COLUMN_AUTO_INCREMENT
+            SQL_COLUMN_CASE_SENSITIVE
+            SQL_COLUMN_SEARCHABLE
+            SQL_COLUMN_TYPE_NAME
+            SQL_COLUMN_TABLE_NAME
+            SQL_COLUMN_OWNER_NAME
+            SQL_COLUMN_QUALIFIER_NAME
+            SQL_COLUMN_LABEL
+            SQL_COLATT_OPT_MAX
+            SQL_COLUMN_DRIVER_START
+            SQL_COLATT_OPT_MIN
+            SQL_ATTR_READONLY
+            SQL_ATTR_WRITE
+            SQL_ATTR_READWRITE_UNKNOWN
+            SQL_UNSEARCHABLE
+            SQL_LIKE_ONLY
+            SQL_ALL_EXCEPT_LIKE
+            SQL_SEARCHABLE
+        );
+    #The above are included for backward compatibility
+
+
+sub new
+{
+    my ($n, $self);
+    my ($type) = shift;
+    my ($DSN) = shift;
+    my (@Results) = @_;
+
+    if (ref $DSN){
+        @Results = ODBCClone($DSN->{'connection'});
+    }else{
+        @Results = ODBCConnect($DSN, @Results);
+    }
+    @Results = processError(-1, @Results);
+    if (! scalar(@Results)){
+        return undef;
+    }
+    $self = bless {};
+    $self->{'connection'} = $Results[0];
+    $ErrConn = $Results[0];
+    $ErrText = $Results[1];
+    $ErrNum = 0;
+    $self->{'DSN'} = $DSN;
+    $self;
+}
+
+####
+#   Close this ODBC session (or all sessions)
+####
+sub Close
+{
+    my ($self, $Result) = shift;
+    $Result = DESTROY($self);
+    $self->{'connection'} = -1;
+    return $Result;
+}
+
+####
+#   Auto-Kill an instance of this module
+####
+sub DESTROY
+{
+    my ($self) = shift;
+    my (@Results) = (0);
+    if($self->{'connection'} > -1){
+        @Results = ODBCDisconnect($self->{'connection'});
+        @Results = processError($self, @Results);
+        if ($Results[0]){
+            undef $self->{'DSN'};
+            undef @{$self->{'fnames'}};
+            undef %{$self->{'field'}};
+            undef %{$self->{'connection'}};
+        }
+    }
+    return $Results[0];
+}
+
+
+sub sql{
+    return (Sql(@_));
+}
+
+####
+#   Submit an SQL Execute statement for processing
+####
+sub Sql{
+    my ($self, $Sql, @Results) = @_;
+    @Results = ODBCExecute($self->{'connection'}, $Sql);
+    return updateResults($self, @Results);
+}
+
+####
+#   Retrieve data from a particular field
+####
+sub Data{
+
+        #   Change by JOC 06-APR-96
+        #   Altered by Dave Roth <dave@roth.net> 96.05.07
+    my($self) = shift;
+    my(@Fields) = @_;
+    my(@Results, $Results, $Field);
+
+    if ($self->{'Dirty'}){
+        GetData($self);
+        $self->{'Dirty'} = 0;
+    }
+    @Fields = @{$self->{'fnames'}} if (! scalar(@Fields));
+    foreach $Field (@Fields) {
+        if (wantarray) {
+            push(@Results, data($self, $Field));
+        } else {
+            $Results .= data($self, $Field);
+        }
+    }
+    return wantarray ? @Results : $Results;
+}
+
+sub DataHash{
+    my($self, @Results) = @_;
+    my(%Results, $Element);
+
+    if ($self->{'Dirty'}){
+        GetData($self);
+        $self->{'Dirty'} = 0;
+    }
+    @Results = @{$self->{'fnames'}} if (! scalar(@Results));
+    foreach $Element (@Results) {
+        $Results{$Element} = data($self, $Element);
+    }
+
+    return %Results;
+}
+
+####
+#   Retrieve data from the data buffer
+####
+sub data
+{  $_[0]->{'data'}->{$_[1]}; }
+
+
+sub fetchrow{
+    return (FetchRow(@_));
+}
+####
+#   Put a row from an ODBC data set into data buffer
+####
+sub FetchRow{
+    my ($self, @Results) = @_;
+    my ($item, $num, $sqlcode);
+        # Added by JOC 06-APR-96
+        #   $num = 0;
+    $num = 0;
+    undef $self->{'data'};
+
+
+    @Results = ODBCFetch($self->{'connection'}, @Results);
+    if (! (@Results = processError($self, @Results))){
+        ####
+        #   There should be an innocuous error "No records remain"
+        #   This indicates no more records in the dataset
+        ####
+        return undef;
+    }
+        #   Set the Dirty bit so we will go and extract data via the
+        #   ODBCGetData function. Otherwise use the cache.
+    $self->{'Dirty'} = 1;
+
+        #   Return the array of field Results.
+    return @Results;
+}
+
+sub GetData{
+    my($self) = @_;
+    my @Results;
+    my $num = 0;
+
+    @Results = ODBCGetData($self->{'connection'});
+    if (!(@Results = processError($self, @Results))){
+        return undef;
+    }
+        ####
+        #   This is a special case. Do not call processResults
+        ####
+    ClearError();
+    foreach (@Results){
+        s/ +$// if defined $_; # HACK
+        $self->{'data'}->{ ${$self->{'fnames'}}[$num] } = $_;
+        $num++;
+    }
+        #   return is a hack to interface with a assoc array.
+    return wantarray? (1, 1): 1;
+}
+
+####
+#   See if any more ODBC Results Sets
+#		Added by Brian Dunfordshore <Brian_Dunfordshore@bridge.com> 
+#		96.07.10
+####
+sub MoreResults{
+    my ($self) = @_;
+
+    my(@Results) = ODBCMoreResults($self->{'connection'});
+    return (processError($self, @Results))[0];
+}
+
+####
+#   Retrieve the catalog from the current DSN
+#	NOTE: All Field names are uppercase!!!
+####
+sub Catalog{
+    my ($self) = shift;
+    my ($Qualifier, $Owner, $Name, $Type) = @_;
+    my (@Results) = ODBCTableList($self->{'connection'}, $Qualifier, $Owner, $Name, $Type);
+
+        #   If there was an error return 0 else 1
+    return (updateResults($self, @Results) != 1);
+}
+
+####
+#   Return an array of names from the catalog for the current DSN
+#       TableList($Qualifier, $Owner, $Name, $Type)
+#           Return: (array of names of tables)
+#	NOTE: All Field names are uppercase!!!
+####
+sub TableList{
+    my ($self) = shift;
+    my (@Results) = @_;
+    if (! scalar(@Results)){
+        @Results = ("", "", "%", "TABLE");
+    }
+
+    if (! Catalog($self, @Results)){
+        return undef;
+    }
+    undef @Results;
+    while (FetchRow($self)){
+        push(@Results, Data($self, "TABLE_NAME"));
+    }
+    return sort(@Results);
+}
+
+
+sub fieldnames{
+    return (FieldNames(@_));
+}
+####
+#   Return an array of fieldnames extracted from the current dataset
+####
+sub FieldNames { $self = shift; return @{$self->{'fnames'}}; }
+
+
+####
+#   Closes this connection. This is used mostly for testing. You should
+#   probably use Close().
+####
+sub ShutDown{
+    my($self) = @_;
+    print "\nClosing connection $self->{'connection'}...";
+    $self->Close();
+    print "\nDone\n";
+}
+
+####
+#   Return this connection number
+####
+sub Connection{
+    my($self) = @_;
+    return $self->{'connection'};
+}
+
+####
+#   Returns the current connections that are in use.
+####
+sub GetConnections{
+    return ODBCGetConnections();
+}
+
+####
+#   Set the Max Buffer Size for this connection. This determines just how much
+#   ram can be allocated when a fetch() is performed that requires a HUGE amount
+#   of memory. The default max is 10k and the absolute max is 100k.
+#   This will probably never be used but I put it in because I noticed a fetch()
+#   of a MEMO field in an Access table was something like 4Gig. Maybe I did
+#   something wrong, but after checking several times I decided to impliment
+#   this limit thingie.
+####
+sub SetMaxBufSize{
+    my($self, $Size) = @_;
+    my(@Results) = ODBCSetMaxBufSize($self->{'connection'}, $Size);
+    return (processError($self, @Results))[0];
+}
+
+####
+#   Returns the Max Buffer Size for this connection. See SetMaxBufSize().
+####
+sub GetMaxBufSize{
+    my($self) = @_;
+    my(@Results) = ODBCGetMaxBufSize($self->{'connection'});
+    return (processError($self, @Results))[0];
+}
+
+
+####
+#   Returns the DSN for this connection as an associative array.
+####
+sub GetDSN{
+    my($self, $DSN) = @_;
+    if(! ref($self)){
+        $DSN = $self;
+        $self = 0;
+    }
+    if (! $DSN){
+        $self = $self->{'connection'};
+	}
+    my(@Results) = ODBCGetDSN($self, $DSN);
+    return (processError($self, @Results));
+}
+
+####
+#   Returns an associative array of $XXX{'DSN'}=Description
+####
+sub DataSources{
+    my($self, $DSN) = @_;
+    if(! ref $self){
+        $DSN = $self;
+        $self = 0;
+    }
+    my(@Results) = ODBCDataSources($DSN);
+    return (processError($self, @Results));
+}
+
+####
+#   Returns an associative array of $XXX{'Driver Name'}=Driver Attributes
+####
+sub Drivers{
+    my($self) = @_;
+    if(! ref $self){
+        $self = 0;
+    }
+    my(@Results) = ODBCDrivers();
+    return (processError($self, @Results));
+}
+
+####
+#   Returns the number of Rows that were affected by the previous SQL command.
+####
+sub RowCount{
+    my($self, $Connection) = @_;
+    if (! ref($self)){
+        $Connection = $self;
+        $self = 0;
+    }
+    if (! $Connection){$Connection = $self->{'connection'};}
+    my(@Results) = ODBCRowCount($Connection);
+    return (processError($self, @Results))[0];
+}
+
+####
+#   Returns the Statement Close Type -- how does ODBC Close a statment.
+#       Types:
+#           SQL_DROP
+#           SQL_CLOSE
+#           SQL_UNBIND
+#           SQL_RESET_PARAMS
+####
+sub GetStmtCloseType{
+    my($self, $Connection) = @_;
+    if (! ref($self)){
+        $Connection = $self;
+        $self = 0;
+    }
+    if (! $Connection){$Connection = $self->{'connection'};}
+    my(@Results) = ODBCGetStmtCloseType($Connection);
+    return (processError($self, @Results));
+}
+
+####
+#   Sets the Statement Close Type -- how does ODBC Close a statment.
+#       Types:
+#           SQL_DROP
+#           SQL_CLOSE
+#           SQL_UNBIND
+#           SQL_RESET_PARAMS
+#   Returns the newly set value.
+####
+sub SetStmtCloseType{
+    my($self, $Type, $Connection) = @_;
+    if (! ref($self)){
+        $Connection = $Type;
+        $Type = $self;
+        $self = 0;
+    }
+    if (! $Connection){$Connection = $self->{'connection'};}
+    my(@Results) = ODBCSetStmtCloseType($Connection, $Type);
+    return (processError($self, @Results))[0];
+}
+
+sub ColAttributes{
+    my($self, $Type, @Field) = @_;
+    my(%Results, @Results, $Results, $Attrib, $Connection, $Temp);
+    if (! ref($self)){
+        $Type = $Field;
+        $Field = $self;
+        $self = 0;
+    }
+    $Connection = $self->{'connection'};
+    if (! scalar(@Field)){ @Field = $self->fieldnames;}
+    foreach $Temp (@Field){
+        @Results = ODBCColAttributes($Connection, $Temp, $Type);
+        ($Attrib) = processError($self, @Results);
+        if (wantarray){
+            $Results{$Temp} = $Attrib;
+        }else{
+            $Results .= "$Temp";
+        }
+    }
+    return wantarray? %Results:$Results;
+}
+
+sub GetInfo{
+    my($self, $Type) = @_;
+    my($Connection, @Results);
+    if(! ref $self){
+        $Type = $self;
+        $self = 0;
+        $Connection = 0;
+    }else{
+        $Connection = $self->{'connection'};
+    }
+    @Results = ODBCGetInfo($Connection, $Type);
+    return (processError($self, @Results))[0];
+}
+
+sub GetConnectOption{
+    my($self, $Type) = @_;
+    my(@Results);
+    if(! ref $self){
+        $Type = $self;
+        $self = 0;
+    }
+    @Results = ODBCGetConnectOption($self->{'connection'}, $Type);
+    return (processError($self, @Results))[0];
+}
+
+sub SetConnectOption{
+    my($self, $Type, $Value) = @_;
+    if(! ref $self){
+        $Value = $Type;
+        $Type = $self;
+        $self = 0;
+    }
+    my(@Results) = ODBCSetConnectOption($self->{'connection'}, $Type, $Value);
+    return (processError($self, @Results))[0];
+}
+
+
+sub Transact{
+    my($self, $Type) = @_;
+    my(@Results);
+    if(! ref $self){
+        $Type = $self;
+        $self = 0;
+    }
+    @Results = ODBCTransact($self->{'connection'}, $Type);
+    return (processError($self, @Results))[0];
+}
+
+
+sub SetPos{
+    my($self, @Results) = @_;
+    @Results = ODBCSetPos($self->{'connection'}, @Results);
+    $self->{'Dirty'} = 1;
+    return (processError($self, @Results))[0];
+}
+
+sub ConfigDSN{
+    my($self) = shift @_;
+    my($Type, $Connection);
+    if(! ref $self){
+        $Type = $self;
+        $Connection = 0;
+        $self = 0;
+    }else{
+        $Type = shift @_;
+        $Connection = $self->{'connection'};
+    }
+    my($Driver, @Attributes) = @_;
+    @Results = ODBCConfigDSN($Connection, $Type, $Driver, @Attributes);
+    return (processError($self, @Results))[0];
+}
+
+
+sub Version{
+	my($self, @Packages) = @_;
+    my($Temp, @Results);
+	if (! ref($self)){
+		push(@Packages, $self);
+	}
+	my($ExtName, $ExtVersion) = Info();
+	if (! scalar(@Packages)){
+		@Packages = ("ODBC.PM", "ODBC.PLL");
+	}
+	foreach $Temp (@Packages){
+		if ($Temp =~ /pll/i){
+            push(@Results, "ODBC.PM:$Win32::ODBC::Version");
+		}elsif ($Temp =~ /pm/i){
+            push(@Results, "ODBC.PLL:$ExtVersion");
+		}
+	}
+    return @Results;
+}
+
+
+sub SetStmtOption{
+    my($self, $Option, $Value) = @_;
+    if(! ref $self){
+        $Value = $Option;
+        $Option = $self;
+        $self = 0;
+    }
+    my(@Results) = ODBCSetStmtOption($self->{'connection'}, $Option, $Value);
+    return (processError($self, @Results))[0];
+}
+
+sub GetStmtOption{
+    my($self, $Type) = @_;
+    if(! ref $self){
+        $Type = $self;
+        $self = 0;
+    }
+    my(@Results) = ODBCGetStmtOption($self->{'connection'}, $Type);
+    return (processError($self, @Results))[0];
+}
+
+sub GetFunctions{
+    my($self, @Results)=@_;
+    @Results = ODBCGetFunctions($self->{'connection'}, @Results);
+    return (processError($self, @Results));
+}
+
+sub DropCursor{
+    my($self) = @_;
+    my(@Results) = ODBCDropCursor($self->{'connection'});
+    return (processError($self, @Results))[0];
+}
+
+sub SetCursorName{
+    my($self, $Name) = @_;
+    my(@Results) = ODBCSetCursorName($self->{'connection'}, $Name);
+    return (processError($self, @Results))[0];
+}
+
+sub GetCursorName{
+    my($self) = @_;
+    my(@Results) = ODBCGetCursorName($self->{'connection'});
+    return (processError($self, @Results))[0];
+}
+
+sub GetSQLState{
+    my($self) = @_;
+    my(@Results) = ODBCGetSQLState($self->{'connection'});
+    return (processError($self, @Results))[0];
+}
+
+
+# ----------- R e s u l t   P r o c e s s i n g   F u n c t i o n s ----------
+####
+#   Generic processing of data into associative arrays
+####
+sub updateResults{
+    my ($self, $Error, @Results) = @_;
+
+    undef %{$self->{'field'}};
+
+    ClearError($self);
+    if ($Error){
+        SetError($self, $Results[0], $Results[1]);
+        return ($Error);
+    }
+
+    @{$self->{'fnames'}} = @Results;
+
+    foreach (0..$#{$self->{'fnames'}}){
+        s/ +$//;
+        $self->{'field'}->{${$self->{'fnames'}}[$_]} = $_;
+    }
+    return undef;
+}
+
+# ----------------------------------------------------------------------------
+# ----------------- D e b u g g i n g   F u n c t i o n s --------------------
+
+sub Debug{
+    my($self, $iDebug, $File) = @_;
+    my(@Results);
+    if (! ref($self)){
+        if (defined $self){
+            $File = $iDebug;
+            $iDebug = $self;
+        }
+        $Connection = 0;
+        $self = 0;
+    }else{
+        $Connection = $self->{'connection'};
+    }
+    push(@Results, ($Connection, $iDebug));
+    push(@Results, $File) if ($File ne "");
+    @Results = ODBCDebug(@Results);
+    return (processError($self, @Results))[0];
+}
+
+####
+#   Prints out the current dataset (used mostly for testing)
+####
+sub DumpData {
+    my($self) = @_; my($f, $goo);
+
+        #   Changed by JOC 06-Apr-96
+        #   print "\nDumping Data for connection: $conn->{'connection'}\n";
+    print "\nDumping Data for connection: $self->{'connection'}\n";
+    print "Error: \"";
+    print $self->Error();
+    print "\"\n";
+    if (! $self->Error()){
+       foreach $f ($self->FieldNames){
+            print $f . " ";
+            $goo .= "-" x length($f);
+            $goo .= " ";
+        }
+        print "\n$goo\n";
+        while ($self->FetchRow()){
+            foreach $f ($self->FieldNames){
+                print $self->Data($f) . " ";
+            }
+            print "\n";
+        }
+    }
+}
+
+sub DumpError{
+    my($self) = @_;
+    my($ErrNum, $ErrText, $ErrConn);
+    my($Temp);
+
+    print "\n---------- Error Report: ----------\n";
+    if (ref $self){
+        ($ErrNum, $ErrText, $ErrConn) = $self->Error();
+        ($Temp = $self->GetDSN()) =~ s/.*DSN=(.*?);.*/$1/i;
+        print "Errors for \"$Temp\" on connection " . $self->{'connection'} . ":\n";
+    }else{
+        ($ErrNum, $ErrText, $ErrConn) = Error();
+        print "Errors for the package:\n";
+    }
+
+    print "Connection Number: $ErrConn\nError number: $ErrNum\nError message: \"$ErrText\"\n";
+    print "-----------------------------------\n";
+
+}
+
+####
+#   Submit an SQL statement and print data about it (used mostly for testing)
+####
+sub Run{
+    my($self, $Sql) = @_;
+
+    print "\nExcecuting connection $self->{'connection'}\nsql statement: \"$Sql\"\n";
+    $self->Sql($Sql);
+    print "Error: \"";
+    print $self->error;
+    print "\"\n";
+    print "--------------------\n\n";
+}
+
+# ----------------------------------------------------------------------------
+# ----------- E r r o r   P r o c e s s i n g   F u n c t i o n s ------------
+
+####
+#   Process Errors returned from a call to ODBCxxxx().
+#   It is assumed that the Win32::ODBC function returned the following structure:
+#      ($ErrorNumber, $ResultsText, ...)
+#           $ErrorNumber....0 = No Error
+#                           >0 = Error Number
+#           $ResultsText.....if no error then this is the first Results element.
+#                           if error then this is the error text.
+####
+sub processError{
+    my($self, $Error, @Results) = @_;
+    if ($Error){
+        SetError($self, $Results[0], $Results[1]);
+        undef @Results;
+    }
+    return @Results;
+}
+
+####
+#   Return the last recorded error message
+####
+sub error{
+    return (Error(@_));
+}
+
+sub Error{
+    my($self) = @_;
+    if(ref($self)){
+        if($self->{'ErrNum'}){
+            my($State) = ODBCGetSQLState($self->{'connection'});
+            return (wantarray)? ($self->{'ErrNum'}, $self->{'ErrText'}, $self->{'connection'}, $State) :"[$self->{'ErrNum'}] [$self->{'connection'}] [$State] \"$self->{'ErrText'}\"";
+        }
+    }elsif ($ErrNum){
+        return (wantarray)? ($ErrNum, $ErrText, $ErrConn):"[$ErrNum] [$ErrConn] \"$ErrText\"";
+    }
+    return undef
+}
+
+####
+#   SetError:
+#       Assume that if $self is not a reference then it is just a placeholder
+#       and should be ignored.
+####
+sub SetError{
+    my($self, $Num, $Text, $Conn) = @_;
+    if (ref $self){
+        $self->{'ErrNum'} = $Num;
+        $self->{'ErrText'} = $Text;
+        $Conn = $self->{'connection'} if ! $Conn;
+    }
+    $ErrNum = $Num;
+    $ErrText = $Text;
+
+        ####
+        #   Test Section Begin
+        ####
+#    $! = ($Num, $Text);
+        ####
+        #   Test Section End
+        ####
+
+    $ErrConn = $Conn;
+}
+
+sub ClearError{
+    my($self, $Num, $Text) = @_;
+    if (ref $self){
+        undef $self->{'ErrNum'};
+        undef $self->{'ErrText'};
+    }else{
+        undef $ErrConn;
+        undef $ErrNum;
+        undef $ErrText;
+    }
+    ODBCCleanError();
+    return 1;
+}
+
+
+sub GetError{
+    my($self, $Connection) = @_;
+    my(@Results);
+    if (! ref($self)){
+        $Connection = $self;
+        $self = 0;
+    }else{
+        if (! defined($Connection)){
+            $Connection = $self->{'connection'};
+        }
+    }
+
+    @Results = ODBCGetError($Connection);
+    return @Results;
+}
+
+
+
+
+# ----------------------------------------------------------------------------
+# ------------------ A U T O L O A D   F U N C T I O N -----------------------
+
+sub AUTOLOAD {
+    # This AUTOLOAD is used to 'autoload' constants from the constant()
+    # XS function.  If a constant is not found then control is passed
+    # to the AUTOLOAD in AutoLoader.
+
+    my($constname);
+    ($constname = $AUTOLOAD) =~ s/.*:://;
+    #reset $! to zero to reset any current errors.
+    local $! = 0;
+    $val = constant($constname);
+
+    if ($! != 0) {
+    if ($! =~ /Invalid/) {
+        $AutoLoader::AUTOLOAD = $AUTOLOAD;
+        goto &AutoLoader::AUTOLOAD;
+    }
+    else {
+
+            # Added by JOC 06-APR-96
+            # $pack = 0;
+        $pack = 0;
+        ($pack,$file,$line) = caller;
+            print "Your vendor has not defined Win32::ODBC macro $constname, used in $file at line $line.";
+    }
+    }
+    eval "sub $AUTOLOAD { $val }";
+    goto &$AUTOLOAD;
+}
+
+
+    #   --------------------------------------------------------------
+    #
+    #
+    #   Make sure that we shutdown ODBC and free memory even if we are
+    #   using perlis.dll on Win32 platform!
+END{
+#    ODBCShutDown() unless $CacheConnection;
+}
+
+
+bootstrap Win32::ODBC;
+
+# Preloaded methods go here.
+
+# Autoload methods go after __END__, and are processed by the autosplit program.
+
+1;
+__END__
+
+=head1 NAME
+
+Win32::ODBC - ODBC Extension for Win32
+
+=head1 SYNOPSIS
+
+To use this module, include the following statement at the top of your
+script:
+
+    use Win32::ODBC;
+
+Next, create a data connection to your DSN:
+
+    $Data = new Win32::ODBC("MyDSN");
+
+B<NOTE>: I<MyDSN> can be either the I<DSN> as defined in the ODBC
+Administrator, I<or> it can be an honest-to-God I<DSN Connect String>.
+
+    Example: "DSN=My Database;UID=Brown Cow;PWD=Moo;"
+
+You should check to see if C<$Data> is indeed defined, otherwise there
+has been an error.
+
+You can now send SQL queries and retrieve info to your heart's
+content! See the description of the methods provided by this module
+below and also the file F<TEST.PL> as referred to in L<INSTALLATION
+NOTES> to see how it all works.
+
+Finally, B<MAKE SURE> that you close your connection when you are
+finished:
+
+    $Data->Close();
+
+=head1 DESCRIPTION
+
+=head2 Background
+
+This is a hack of Dan DeMaggio's <dmag@umich.edu> F<NTXS.C> ODBC
+implementation. I have recoded and restructured most of it including
+most of the F<ODBC.PM> package, but its very core is still based on
+Dan's code (thanks Dan!).
+
+The history of this extension is found in the file F<HISTORY.TXT> that
+comes with the original archive (see L<INSTALLATION NOTES> below).
+
+=head2 Benefits
+
+And what are the benefits of this module?
+
+=over
+
+=item *
+
+The number of ODBC connections is limited by memory and ODBC itself
+(have as many as you want!).
+
+=item *
+
+The working limit for the size of a field is 10,240 bytes, but you can
+increase that limit (if needed) to a max of 2,147,483,647 bytes. (You
+can always recompile to increase the max limit.)
+
+=item *
+
+You can open a connection by either specifing a DSN or a connection
+string!
+
+=item *
+
+You can open and close the connections in any order!
+
+=item *
+
+Other things that I can not think of right now... :)
+
+=back
+
+=head1 CONSTANTS
+
+This package defines a number of constants. You may refer to each of
+these constants using the notation C<ODBC::xxxxx>, where C<xxxxx> is
+the constant.
+
+Example:
+
+   print ODBC::SQL_SQL_COLUMN_NAME, "\n";
+
+=head1 SPECIAL NOTATION
+
+For the method documentation that follows, an B<*> following the
+method parameters indicates that that method is new or has been
+modified for this version.
+
+=head1 CONSTRUCTOR
+
+=over
+
+=item new ( ODBC_OBJECT | DSN [, (OPTION1, VALUE1), (OPTION2, VALUE2) ...] )
+*
+
+Creates a new ODBC connection based on C<DSN>, or, if you specify an
+already existing ODBC object, then a new ODBC object will be created
+but using the ODBC Connection specified by C<ODBC_OBJECT>. (The new
+object will be a new I<hstmt> using the I<hdbc> connection in
+C<ODBC_OBJECT>.)
+
+C<DSN> is I<Data Source Name> or a proper C<ODBCDriverConnect> string.
+
+You can specify SQL Connect Options that are implemented before the
+actual connection to the DSN takes place. These option/values are the
+same as specified in C<GetConnectOption>/C<SetConnectOption> (see
+below) and are defined in the ODBC API specs.
+
+Returns a handle to the database on success, or I<undef> on failure.
+
+=back
+
+=head1 METHODS
+
+=over
+
+=item Catalog ( QUALIFIER, OWNER, NAME, TYPE )
+
+Tells ODBC to create a data set that contains table information about
+the DSN. Use C<Fetch> and C<Data> or C<DataHash> to retrieve the data.
+The returned format is:
+
+    [Qualifier] [Owner] [Name] [Type]
+
+Returns I<true> on error.
+
+=item ColAttributes ( ATTRIBUTE [, FIELD_NAMES ] )
+
+Returns the attribute C<ATTRIBUTE> on each of the fields in the list
+C<FIELD_NAMES> in the current record set. If C<FIELD_NAMES> is empty,
+then all fields are assumed. The attributes are returned as an
+associative array.
+
+=item ConfigDSN ( OPTION, DRIVER, ATTRIBUTE1 [, ATTRIBUTE2, ATTRIBUTE3, ...
+] )
+
+Configures a DSN. C<OPTION> takes on one of the following values:
+
+    ODBC_ADD_DSN.......Adds a new DSN.
+    ODBC_MODIFY_DSN....Modifies an existing DSN.
+    ODBC_REMOVE_DSN....Removes an existing DSN.
+
+    ODBC_ADD_SYS_DSN.......Adds a new System DSN.
+    ODBC_MODIFY_SYS_DSN....Modifies an existing System DSN.
+    ODBC_REMOVE_SYS_DSN....Removes an existing System DSN.
+
+You must specify the driver C<DRIVER> (which can be retrieved by using
+C<DataSources> or C<Drivers>).
+
+C<ATTRIBUTE1> B<should> be I<"DSN=xxx"> where I<xxx> is the name of
+the DSN. Other attributes can be any DSN attribute such as:
+
+    "UID=Cow"
+    "PWD=Moo"
+    "Description=My little bitty Data Source Name"
+
+Returns I<true> on success, I<false> on failure.
+
+B<NOTE 1>: If you use C<ODBC_ADD_DSN>, then you must include at least
+I<"DSN=xxx"> and the location of the database.
+
+Example: For MS Access databases, you must specify the
+I<DatabaseQualifier>:
+
+    "DBQ=c:\\...\\MyDatabase.mdb"
+
+B<NOTE 2>: If you use C<ODBC_MODIFY_DSN>, then you need only specify
+the I<"DNS=xxx"> attribute. Any other attribute you include will be
+changed to what you specify.
+
+B<NOTE 3>: If you use C<ODBC_REMOVE_DSN>, then you need only specify
+the I<"DSN=xxx"> attribute.
+
+=item Connection ()
+
+Returns the connection number associated with the ODBC connection.
+
+=item Close ()
+
+Closes the ODBC connection. No return value.
+
+=item Data ( [ FIELD_NAME ] )
+
+Returns the contents of column name C<FIELD_NAME> or the current row
+(if nothing is specified).
+
+=item DataHash ( [ FIELD1, FIELD2, ... ] )
+
+Returns the contents for C<FIELD1, FIELD2, ...> or the entire row (if
+nothing is specified) as an associative array consisting of:
+
+    {Field Name} => Field Data
+
+=item DataSources ()
+
+Returns an associative array of Data Sources and ODBC remarks about them.
+They are returned in the form of:
+
+    $ArrayName{'DSN'}=Driver
+
+where I<DSN> is the Data Source Name and ODBC Driver used.
+
+=item Debug ( [ 1 | 0 ] )
+
+Sets the debug option to on or off. If nothing is specified, then
+nothing is changed.
+
+Returns the debugging value (I<1> or I<0>).
+
+=item Drivers ()
+
+Returns an associative array of ODBC Drivers and their attributes.
+They are returned in the form of:
+
+    $ArrayName{'DRIVER'}=Attrib1;Attrib2;Attrib3;...
+
+where I<DRIVER> is the ODBC Driver Name and I<AttribX> are the
+driver-defined attributes.
+
+=item DropCursor ( [ CLOSE_TYPE ] )
+
+Drops the cursor associated with the ODBC object. This forces the
+cursor to be deallocated. This overrides C<SetStmtCloseType>, but the
+ODBC object does not lose the C<StmtCloseType> setting. C<CLOSE_TYPE>
+can be any valid C<SmtpCloseType> and will perform a close on the stmt
+using the specified close type.
+
+Returns I<true> on success, I<false> on failure.
+
+=item DumpData ()
+
+Dumps to the screen the fieldnames and all records of the current data
+set. Used primarily for debugging. No return value.
+
+=item Error ()
+
+Returns the last encountered error. The returned value is context
+dependent:
+
+If called in a I<scalar> context, then a I<3-element array> is
+returned:
+
+    ( ERROR_NUMBER, ERROR_TEXT, CONNECTION_NUMBER )
+
+If called in a I<string> context, then a I<string> is returned:
+
+    "[ERROR_NUMBER] [CONNECTION_NUMBER] [ERROR_TEXT]"
+
+If debugging is on then two more variables are returned:
+
+    ( ..., FUNCTION, LEVEL )
+
+where C<FUNCTION> is the name of the function in which the error
+occurred, and C<LEVEL> represents extra information about the error
+(usually the location of the error).
+
+=item FetchRow ( [ ROW [, TYPE ] ] )
+
+Retrieves the next record from the keyset. When C<ROW> and/or C<TYPE>
+are specified, the call is made using C<SQLExtendedFetch> instead of
+C<SQLFetch>.
+
+B<NOTE 1>: If you are unaware of C<SQLExtendedFetch> and its
+implications, stay with just regular C<FetchRow> with no parameters.
+
+B<NOTE 2>: The ODBC API explicitly warns against mixing calls to
+C<SQLFetch> and C<SQLExtendedFetch>; use one or the other but not
+both.
+
+If I<ROW> is specified, it moves the keyset B<RELATIVE> C<ROW> number
+of rows.
+
+If I<ROW> is specified and C<TYPE> is B<not>, then the type used is
+B<RELATIVE>.
+
+Returns I<true> when another record is available to read, and I<false>
+when there are no more records.
+
+=item FieldNames ()
+
+Returns an array of fieldnames found in the current data set. There is
+no guarantee on order.
+
+=item GetConnections ()
+
+Returns an array of connection numbers showing what connections are
+currently open.
+
+=item GetConnectOption ( OPTION )
+
+Returns the value of the specified connect option C<OPTION>. Refer to
+ODBC documentation for more information on the options and values.
+
+Returns a string or scalar depending upon the option specified.
+
+=item GetCursorName ()
+
+Returns the name of the current cursor as a string or I<undef>.
+
+=item GetData ()
+
+Retrieves the current row from the dataset. This is not generally
+used by users; it is used internally.
+
+Returns an array of field data where the first element is either
+I<false> (if successful) and I<true> (if B<not> successful).
+
+=item getDSN ( [ DSN ] )
+
+Returns an associative array indicating the configuration for the
+specified DSN.
+
+If no DSN is specified then the current connection is used.
+
+The returned associative array consists of:
+
+    keys=DSN keyword; values=Keyword value. $Data{$Keyword}=Value
+
+=item GetFunctions ( [ FUNCTION1, FUNCTION2, ... ] )
+
+Returns an associative array indicating the ability of the ODBC Driver
+to support the specified functions. If no functions are specified,
+then a 100 element associative array is returned containing all
+possible functions and their values.
+
+C<FUNCTION> must be in the form of an ODBC API constant like
+C<SQL_API_SQLTRANSACT>.
+
+The returned array will contain the results like:
+
+    $Results{SQL_API_SQLTRANSACT}=Value
+
+Example:
+
+    $Results = $O->GetFunctions(
+                                $O->SQL_API_SQLTRANSACT,
+                                SQL_API_SQLSETCONNECTOPTION
+                               );
+    $ConnectOption = $Results{SQL_API_SQLSETCONNECTOPTION};
+    $Transact = $Results{SQL_API_SQLTRANSACT};
+
+=item GetInfo ( OPTION )
+
+Returns a string indicating the value of the particular
+option specified.
+
+=item GetMaxBufSize ()
+
+Returns the current allocated limit for I<MaxBufSize>. For more info,
+see C<SetMaxBufSize>.
+
+=item GetSQLState () *
+
+Returns a string indicating the SQL state as reported by ODBC. The SQL
+state is a code that the ODBC Manager or ODBC Driver returns after the
+execution of a SQL function. This is helpful for debugging purposes.
+
+=item GetStmtCloseType ( [ CONNECTION ] )
+
+Returns a string indicating the type of closure that will be used
+everytime the I<hstmt> is freed. See C<SetStmtCloseType> for details.
+
+By default, the connection of the current object will be used. If
+C<CONNECTION> is a valid connection number, then it will be used.
+
+=item GetStmtOption ( OPTION )
+
+Returns the value of the specified statement option C<OPTION>. Refer
+to ODBC documentation for more information on the options and values.
+
+Returns a string or scalar depending upon the option specified.
+
+=item MoreResults ()
+
+This will report whether there is data yet to be retrieved from the
+query. This can happen if the query was a multiple select.
+
+Example:
+
+    "SELECT * FROM [foo] SELECT * FROM [bar]"
+
+B<NOTE>: Not all drivers support this.
+
+Returns I<1> if there is more data, I<undef> otherwise.
+
+=item RowCount ( CONNECTION )
+
+For I<UPDATE>, I<INSERT> and I<DELETE> statements, the returned value
+is the number of rows affected by the request or I<-1> if the number
+of affected rows is not available.
+
+B<NOTE 1>: This function is not supported by all ODBC drivers! Some
+drivers do support this but not for all statements (e.g., it is
+supported for I<UPDATE>, I<INSERT> and I<DELETE> commands but not for
+the I<SELECT> command).
+
+B<NOTE 2>: Many data sources cannot return the number of rows in a
+result set before fetching them; for maximum interoperability,
+applications should not rely on this behavior.
+
+Returns the number of affected rows, or I<-1> if not supported by the
+driver in the current context.
+
+=item Run ( SQL )
+
+Executes the SQL command B<SQL> and dumps to the screen info about
+it. Used primarily for debugging.
+
+No return value.
+
+=item SetConnectOption ( OPTION ) *
+
+Sets the value of the specified connect option B<OPTION>. Refer to
+ODBC documentation for more information on the options and values.
+
+Returns I<true> on success, I<false> otherwise.
+
+=item SetCursorName ( NAME ) *
+
+Sets the name of the current cursor.
+
+Returns I<true> on success, I<false> otherwise.
+
+=item SetPos ( ROW [, OPTION, LOCK ] ) *
+
+Moves the cursor to the row C<ROW> within the current keyset (B<not>
+the current data/result set).
+
+Returns I<true> on success, I<false> otherwise.
+
+=item SetMaxBufSize ( SIZE )
+
+This sets the I<MaxBufSize> for a particular connection. This will
+most likely never be needed but...
+
+The amount of memory that is allocated to retrieve the field data of a
+record is dynamic and changes when it need to be larger. I found that
+a memo field in an MS Access database ended up requesting 4 Gig of
+space. This was a bit much so there is an imposed limit (2,147,483,647
+bytes) that can be allocated for data retrieval.
+
+Since it is possible that someone has a database with field data
+greater than 10,240, you can use this function to increase the limit
+up to a ceiling of 2,147,483,647 (recompile if you need more).
+
+Returns the max number of bytes.
+
+=item SetStmtCloseType ( TYPE [, CONNECTION ] )
+
+Sets a particular I<hstmt> close type for the connection. This is the
+same as C<ODBCFreeStmt(hstmt, TYPE)>. By default, the connection of
+the current object will be used. If C<CONNECTION> is a valid
+connection number, then it will be used.
+
+C<TYPE> may be one of:
+
+    SQL_CLOSE
+    SQL_DROP
+    SQL_UNBIND
+    SQL_RESET_PARAMS
+
+Returns a string indicating the newly set type.
+
+=item SetStmtOption ( OPTION ) *
+
+Sets the value of the specified statement option C<OPTION>. Refer to
+ODBC documentation for more information on the options and values.
+
+Returns I<true> on success, I<false> otherwise.
+
+=item ShutDown ()
+
+Closes the ODBC connection and dumps to the screen info about
+it. Used primarily for debugging.
+
+No return value.
+
+=item Sql ( SQL_STRING )
+
+Executes the SQL command C<SQL_STRING> on the current connection.
+
+Returns I<?> on success, or an error number on failure.
+
+=item TableList ( QUALIFIER, OWNER, NAME, TYPE )
+
+Returns the catalog of tables that are available in the DSN. For an
+unknown parameter, just specify the empty string I<"">.
+
+Returns an array of table names.
+
+=item Transact ( TYPE ) *
+
+Forces the ODBC connection to perform a I<rollback> or I<commit>
+transaction.
+
+C<TYPE> may be one of:
+
+    SQL_COMMIT
+    SQL_ROLLBACK
+
+B<NOTE>: This only works with ODBC drivers that support transactions.
+Your driver supports it if I<true> is returned from:
+
+    $O->GetFunctions($O->SQL_API_SQLTRANSACT)[1]
+
+(See C<GetFunctions> for more details.)
+
+Returns I<true> on success, I<false> otherwise.
+
+=item Version ( PACKAGES )
+
+Returns an array of version numbers for the requested packages
+(F<ODBC.pm> or F<ODBC.PLL>). If the list C<PACKAGES> is empty, then
+all version numbers are returned.
+
+=back
+
+=head1 LIMITATIONS
+
+What known problems does this thing have?
+
+=over
+
+=item *
+
+If the account under which the process runs does not have write
+permission on the default directory (for the process, not the ODBC
+DSN), you will probably get a runtime error during a
+C<SQLConnection>. I don't think that this is a problem with the code,
+but more like a problem with ODBC. This happens because some ODBC
+drivers need to write a temporary file. I noticed this using the MS
+Jet Engine (Access Driver).
+
+=item *
+
+This module has been neither optimized for speed nor optimized for
+memory consumption.
+
+=back
+
+=head1 INSTALLATION NOTES
+
+If you wish to use this module with a build of Perl other than
+ActivePerl, you may wish to fetch the original source distribution for
+this module at:
+
+  ftp://ftp.roth.net:/pub/ntperl/ODBC/970208/Bin/Win32_ODBC_Build_CORE.zip
+
+or one of the other archives at that same location. See the included
+README for hints on installing this module manually, what to do if you
+get a I<parse exception>, and a pointer to a test script for this
+module.
+
+=head1 OTHER DOCUMENTATION
+
+Find a FAQ for Win32::ODBC at:
+
+  http://www.roth.net/odbc/odbcfaq.htm
+
+=head1 AUTHOR
+
+Dave Roth <rothd@roth.net>
+
+=head1 CREDITS
+
+Based on original code by Dan DeMaggio <dmag@umich.edu>
+
+=head1 DISCLAIMER
+
+I do not guarantee B<ANYTHING> with this package. If you use it you
+are doing so B<AT YOUR OWN RISK>! I may or may not support this
+depending on my time schedule.
+
+=head1 HISTORY
+
+Last Modified 1999.09.25.
+
+=head1 COPYRIGHT
+
+Copyright (c) 1996-1998 Dave Roth. All rights reserved.
+
+Courtesy of Roth Consulting:  http://www.roth.net/consult/
+
+Use under GNU General Public License. Details can be found at:
+http://www.gnu.org/copyleft/gpl.html
+
+=cut
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/OLE.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/OLE.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/OLE.pm	(revision 14139)
@@ -0,0 +1,968 @@
+# The documentation is at the __END__
+
+package Win32::OLE;
+
+use strict;
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK @EXPORT_FAIL $AUTOLOAD
+	    $CP $LCID $Warn $LastError $_NewEnum $_Unique);
+
+$VERSION = '0.1701';
+
+use Carp;
+use Exporter;
+use DynaLoader;
+@ISA = qw(Exporter DynaLoader);
+
+@EXPORT = qw();
+@EXPORT_OK = qw(in valof with HRESULT EVENTS OVERLOAD
+                CP_ACP CP_OEMCP CP_MACCP CP_UTF7 CP_UTF8
+		DISPATCH_METHOD DISPATCH_PROPERTYGET
+		DISPATCH_PROPERTYPUT DISPATCH_PROPERTYPUTREF);
+@EXPORT_FAIL = qw(EVENTS OVERLOAD);
+
+sub export_fail {
+    shift;
+    my @unknown;
+    while (@_) {
+	my $symbol = shift;
+	if ($symbol eq 'OVERLOAD') {
+	    eval <<'OVERLOAD';
+	        use overload '""'     => \&valof,
+	                     '0+'     => \&valof,
+	                     fallback => 1;
+OVERLOAD
+	}
+	elsif ($symbol eq 'EVENTS') {
+	    Win32::OLE->Initialize(Win32::OLE::COINIT_OLEINITIALIZE());
+	}
+	else {
+	    push @unknown, $symbol;
+	}
+    }
+    return @unknown;
+}
+
+unless (defined &Dispatch) {
+    # Use regular DynaLoader if XS part is not yet initialized
+    bootstrap Win32::OLE;
+    require Win32::OLE::Lite;
+}
+
+1;
+
+########################################################################
+
+__END__
+
+=head1 NAME
+
+Win32::OLE - OLE Automation extensions
+
+=head1 SYNOPSIS
+
+    $ex = Win32::OLE->new('Excel.Application') or die "oops\n";
+    $ex->Amethod("arg")->Bmethod->{'Property'} = "foo";
+    $ex->Cmethod(undef,undef,$Arg3);
+    $ex->Dmethod($RequiredArg1, {NamedArg1 => $Value1, NamedArg2 => $Value2});
+
+    $wd = Win32::OLE->GetObject("D:\\Data\\Message.doc");
+    $xl = Win32::OLE->GetActiveObject("Excel.Application");
+
+=head1 DESCRIPTION
+
+This module provides an interface to OLE Automation from Perl.
+OLE Automation brings VisualBasic like scripting capabilities and
+offers powerful extensibility and the ability to control many Win32
+applications from Perl scripts.
+
+The Win32::OLE module uses the IDispatch interface exclusively.  It is
+not possible to access a custom OLE interface.  OLE events and OCX's are
+currently not supported.
+
+Actually, that's no longer strictly true.  This module now contains
+B<ALPHA> level support for OLE events.  This is largely untested and the
+specific interface might still change in the future.
+
+=head2 Methods
+
+=over 8
+
+=item Win32::OLE->new(PROGID[, DESTRUCTOR])
+
+The new() class method starts a new instance of an OLE Automation object.
+It returns a reference to this object or C<undef> if the creation failed.
+
+The PROGID argument must be either the OLE I<program id> or the I<class id>
+of the required application.  The optional DESTRUCTOR specifies a DESTROY-like
+method.  This can be either a CODE reference or a string containing an OLE
+method name.  It can be used to cleanly terminate OLE applications in case the
+Perl program dies.
+
+To create an object via DCOM on a remote server you can use an array
+reference in place of PROGID.  The referenced array must contain the
+machine name and the I<program id> or I<class id>.  For example:
+
+	my $obj = Win32::OLE->new(['my.machine.com', 'Program.Id']);
+
+If the PROGID is a I<program id> then Win32::OLE will try to resolve the
+corresponding I<class id> locally.  If the I<program id> is not registered
+locally then the remote registry is queried.  This will only succeed if
+the local process has read access to the remote registry.  The safest
+(and fastest) method is to specify the C<class id> directly.
+
+=item Win32::OLE->EnumAllObjects([CALLBACK])
+
+This class method returns the number Win32::OLE objects currently in
+existance.  It will call the optional CALLBACK function for each of
+these objects:
+
+	$Count = Win32::OLE->EnumAllObjects(sub {
+	    my $Object = shift;
+	    my $Class = Win32::OLE->QueryObjectType($Object);
+	    printf "# Object=%s Class=%s\n", $Object, $Class;
+	});
+
+The EnumAllObjects() method is primarily a debugging tool.  It can be
+used e.g. in an END block to check if all external connections have
+been properly destroyed.
+
+=item Win32::OLE->FreeUnusedLibraries()
+
+The FreeUnusedLibraries() class method unloads all unused OLE
+resources.  These are the libraries of those classes of which all
+existing objects have been destroyed.  The unloading of object
+libraries is really only important for long running processes that
+might instantiate a huge number of B<different> objects over time.
+
+Be aware that objects implemented in Visual Basic have a buggy
+implementation of this functionality: They pretend to be unloadable
+while they are actually still running their cleanup code.  Unloading
+the DLL at that moment typically produces an access violation.  The
+probability for this problem can be reduced by calling the
+SpinMessageLoop() method and sleep()ing for a few seconds.
+
+=item Win32::OLE->GetActiveObject(CLASS[, DESTRUCTOR])
+
+The GetActiveObject() class method returns an OLE reference to a
+running instance of the specified OLE automation server.  It returns
+C<undef> if the server is not currently active.  It will croak if
+the class is not even registered.  The optional DESTRUCTOR method takes
+either a method name or a code reference.  It is executed when the last
+reference to this object goes away.  It is generally considered C<impolite>
+to stop applications that you did not start yourself.
+
+=item Win32::OLE->GetObject(MONIKER[, DESTRUCTOR])
+
+The GetObject() class method returns an OLE reference to the specified
+object.  The object is specified by a pathname optionally followed by
+additional item subcomponent separated by exclamation marks '!'.  The
+optional DESTRUCTOR argument has the same semantics as the DESTRUCTOR in
+new() or GetActiveObject().
+
+=item Win32::OLE->Initialize([COINIT])
+
+The Initialize() class method can be used to specify an alternative
+apartment model for the Perl thread.  It must be called B<before> the
+first OLE object is created.  If the C<Win32::OLE::Const> module is
+used then the call to the Initialize() method must be made from a BEGIN
+block before the first C<use> statement for the C<Win32::OLE::Const>
+module.
+
+Valid values for COINIT are:
+
+  Win32::OLE::COINIT_APARTMENTTHREADED  - single threaded
+  Win32::OLE::COINIT_MULTITHREADED      - the default
+  Win32::OLE::COINIT_OLEINITIALIZE      - single threaded, additional OLE stuff
+
+COINIT_OLEINITIALIZE is sometimes needed when an OLE object uses
+additional OLE compound document technologies not available from the
+normal COM subsystem (for example MAPI.Session seems to require it).
+Both COINIT_OLEINITIALIZE and COINIT_APARTMENTTHREADED create a hidden
+top level window and a message queue for the Perl process.  This may
+create problems with other application, because Perl normally doesn't
+process its message queue.  This means programs using synchronous
+communication between applications (such as DDE initiation), may hang
+until Perl makes another OLE method call/property access or terminates.
+This applies to InstallShield setups and many things started to shell
+associations.  Please try to utilize the C<Win32::OLE-E<gt>SpinMessageLoop>
+and C<Win32::OLE-E<gt>Uninitialize> methods if you can not use the default
+COINIT_MULTITHREADED model.
+
+=item OBJECT->Invoke(METHOD[, ARGS])
+
+The Invoke() object method is an alternate way to invoke OLE
+methods.  It is normally equivalent to C<$OBJECT->METHOD(@ARGS)>.  This
+function must be used if the METHOD name contains characters not valid
+in a Perl variable name (like foreign language characters).  It can
+also be used to invoke the default method of an object even if the
+default method has not been given a name in the type library.  In this
+case use <undef> or C<''> as the method name.  To invoke an OLE objects
+native Invoke() method (if such a thing exists), please use:
+
+	$Object->Invoke('Invoke', @Args);
+
+=item Win32::OLE->LastError()
+
+The LastError() class method returns the last recorded OLE
+error.  This is a dual value like the C<$!> variable: in a numeric
+context it returns the error number and in a string context it returns
+the error message.  The error number is a signed HRESULT value.  Please
+use the L<HRESULT(ERROR)> function to convert an unsigned hexadecimal
+constant to a signed HRESULT.
+
+The last OLE error is automatically reset by a successful OLE
+call.  The numeric value can also explicitly be set by a call (which will
+discard the string value):
+
+	Win32::OLE->LastError(0);
+
+=item OBJECT->LetProperty(NAME,ARGS,VALUE)
+
+In Win32::OLE property assignment using the hash syntax is equivalent
+to the Visual Basic C<Set> syntax (I<by reference> assignment):
+
+	$Object->{Property} = $OtherObject;
+
+corresponds to this Visual Basic statement:
+
+	Set Object.Property = OtherObject
+
+To get the I<by value> treatment of the Visual Basic C<Let> statement
+
+	Object.Property = OtherObject
+
+you have to use the LetProperty() object method in Perl:
+
+	$Object->LetProperty($Property, $OtherObject);
+
+LetProperty() also supports optional arguments for the property assignment.
+See L<OBJECT->SetProperty(NAME,ARGS,VALUE)> for details.
+
+=item Win32::OLE->MessageLoop()
+
+The MessageLoop() class method will run a standard Windows message
+loop, dispatching messages until the QuitMessageLoop() class method is
+called.  It is used to wait for OLE events.
+
+=item Win32::OLE->Option(OPTION)
+
+The Option() class method can be used to inspect and modify
+L<Module Options>.  The single argument form retrieves the value of
+an option:
+
+	my $CP = Win32::OLE->Option('CP');
+
+A single call can be used to set multiple options simultaneously:
+
+	Win32::OLE->Option(CP => CP_ACP, Warn => 3);
+
+=item Win32::OLE->QueryObjectType(OBJECT)
+
+The QueryObjectType() class method returns a list of the type library
+name and the objects class name.  In a scalar context it returns the
+class name only.  It returns C<undef> when the type information is not
+available.
+
+=item Win32::OLE->QuitMessageLoop()
+
+The QuitMessageLoop() class method posts a (user-level) "Quit" message
+to the current threads message loop.  QuitMessageLoop() is typically
+called from an event handler.  The MessageLoop() class method will
+return when it receives this "Quit" method.
+
+=item OBJECT->SetProperty(NAME,ARGS,VALUE)
+
+The SetProperty() method allows to modify properties with arguments,
+which is not supported by the hash syntax.  The hash form
+
+	$Object->{Property} = $Value;
+
+is equivalent to
+
+	$Object->SetProperty('Property', $Value);
+
+Arguments must be specified between the property name and the new value:
+
+	$Object->SetProperty('Property', @Args, $Value);
+
+It is not possible to use "named argument" syntax with this function
+because the new value must be the last argument to SetProperty().
+
+This method hides any native OLE object method called SetProperty().
+The native method will still be available through the Invoke() method:
+
+	$Object->Invoke('SetProperty', @Args);
+
+=item Win32::OLE->SpinMessageLoop
+
+This class method retrieves all pending messages from the message queue
+and dispatches them to their respective window procedures.  Calling this
+method is only necessary when not using the COINIT_MULTITHREADED model.
+All OLE method calls and property accesses automatically process the
+message queue.
+
+=item Win32::OLE->Uninitialize
+
+The Uninitialize() class method uninitializes the OLE subsystem.  It
+also destroys the hidden top level window created by OLE for single
+threaded apartments.  All OLE objects will become invalid after this call!
+It is possible to call the Initialize() class method again with a different
+apartment model after shutting down OLE with Uninitialize().
+
+=item Win32::OLE->WithEvents(OBJECT[, HANDLER[, INTERFACE]])
+
+This class method enables and disables the firing of events by the
+specified OBJECT.  If no HANDLER is specified, then events are
+disconnected.  For some objects Win32::OLE is not able to
+automatically determine the correct event interface.  In this case the
+INTERFACE argument must contain either the COCLASS name of the OBJECT
+or the name of the event DISPATCH interface.  Please read the L<Events>
+section below for detailed explanation of the Win32::OLE event
+support.
+
+=back
+
+Whenever Perl does not find a method name in the Win32::OLE package it
+is automatically used as the name of an OLE method and this method call
+is dispatched to the OLE server.
+
+There is one special hack built into the module: If a method or property
+name could not be resolved with the OLE object, then the default method
+of the object is called with the method name as its first parameter.  So
+
+	my $Sheet = $Worksheets->Table1;
+or
+	my $Sheet = $Worksheets->{Table1};
+
+is resolved as
+
+	my $Sheet = $Worksheet->Item('Table1');
+
+provided that the $Worksheets object doesnot have a C<Table1> method
+or property.  This hack has been introduced to call the default method
+of collections which did not name the method in their type library.  The
+recommended way to call the "unnamed" default method is:
+
+	my $Sheet = $Worksheets->Invoke('', 'Table1');
+
+This special hack is disabled under C<use strict 'subs';>.
+
+=head2 Object methods and properties
+
+The object returned by the new() method can be used to invoke
+methods or retrieve properties in the same fashion as described
+in the documentation for the particular OLE class (eg. Microsoft
+Excel documentation describes the object hierarchy along with the
+properties and methods exposed for OLE access).
+
+Optional parameters on method calls can be omitted by using C<undef>
+as a placeholder.  A better way is to use named arguments, as the
+order of optional parameters may change in later versions of the OLE
+server application.  Named parameters can be specified in a reference
+to a hash as the last parameter to a method call.
+
+Properties can be retrieved or set using hash syntax, while methods
+can be invoked with the usual perl method call syntax.  The C<keys>
+and C<each> functions can be used to enumerate an object's properties.
+Beware that a property is not always writable or even readable (sometimes
+raising exceptions when read while being undefined).
+
+If a method or property returns an embedded OLE object, method
+and property access can be chained as shown in the examples below.
+
+=head2 Functions
+
+The following functions are not exported by default.
+
+=over 8
+
+=item HRESULT(ERROR)
+
+The HRESULT() function converts an unsigned number into a signed HRESULT
+error value as used by OLE internally.  This is necessary because Perl
+treats all hexadecimal constants as unsigned.  To check if the last OLE
+function returned "Member not found" (0x80020003) you can write:
+
+	if (Win32::OLE->LastError == HRESULT(0x80020003)) {
+	    # your error recovery here
+	}
+
+=item in(COLLECTION)
+
+If COLLECTION is an OLE collection object then C<in $COLLECTION>
+returns a list of all members of the collection.  This is a shortcut
+for C<Win32::OLE::Enum->All($COLLECTION)>.  It is most commonly used in
+a C<foreach> loop:
+
+	foreach my $value (in $collection) {
+	    # do something with $value here
+	}
+
+=item valof(OBJECT)
+
+Normal assignment of Perl OLE objects creates just another reference
+to the OLE object.  The valof() function explictly dereferences the
+object (through the default method) and returns the value of the object.
+
+	my $RefOf = $Object;
+	my $ValOf = valof $Object;
+        $Object->{Value} = $NewValue;
+
+Now $ValOf still contains the old value wheras $RefOf would
+resolve to the $NewValue because it is still a reference to
+$Object.
+
+The valof() function can also be used to convert Win32::OLE::Variant
+objects to Perl values.
+
+=item with(OBJECT, PROPERTYNAME => VALUE, ...)
+
+This function provides a concise way to set the values of multiple
+properties of an object.  It iterates over its arguments doing
+C<$OBJECT->{PROPERTYNAME} = $VALUE> on each trailing pair.
+
+=back
+
+=head2 Overloading
+
+The Win32::OLE objects can be overloaded to automatically convert to
+their values whenever they are used in a bool, numeric or string
+context.  This is not enabled by default.  You have to request it
+through the OVERLOAD pseudoexport:
+
+	use Win32::OLE qw(in valof with OVERLOAD);
+
+You can still get the original string representation of an object
+(C<Win32::OLE=0xDEADBEEF>), e.g. for debugging, by using the
+C<overload::StrVal()> method:
+
+	print overload::StrVal($object), "\n";
+
+Please note that C<OVERLOAD> is a global setting.  If any module enables
+Win32::OLE overloading then it's active everywhere.
+
+=head2 Events
+
+The Win32::OLE module now contains B<ALPHA> level event support.  This
+support is only available when Perl is running in a single threaded
+apartment.  This can most easily be assured by using the C<EVENTS>
+pseudo-import:
+
+	use Win32::OLE qw(EVENTS);
+
+which implicitly does something like:
+
+	use Win32::OLE;
+	Win32::OLE->Initialize(Win32::OLE::COINIT_OLEINITIALIZE);
+
+The current interface to OLE events should be considered experimental
+and is subject to change.  It works as expected for normal OLE
+applications, but OLE control events often don't seem to work yet.
+
+Events must be enabled explicitly for an OLE object through the
+Win32::OLE->WithEvents() class method.  The Win32::OLE module uses the
+IProvideClassInfo2 interface to determine the default event source of
+the object.  If this interface is not supported, then the user must
+specify the name of the event source explicitly in the WithEvents()
+method call.  It is also possible to specify the class name of the
+object as the third parameter.  In this case Win32::OLE will try to
+look up the default source interface for this COCLASS.
+
+The HANDLER argument to Win32::OLE->WithEvents() can either be a CODE
+reference or a package name.  In the first case, all events will invoke
+this particular function.  The first two arguments to this function will
+be the OBJECT itself and the name of the event.  The remaining arguments
+will be event specific.
+
+	sub Event {
+	    my ($Obj,$Event,@Args) = @_;
+	    print "Event triggered: '$Event'\n";
+	}
+	Win32::OLE->WithEvents($Obj, \&Event);
+
+Alternatively the HANDLER argument can specify a package name.  When the
+OBJECT fires an event, Win32::OLE will try to find a function of the same
+name as the event in this package.  This function will be called with the
+OBJECT as the first argument followed again by the event specific parameters:
+
+	package MyEvents;
+	sub EventName1 {
+	    my ($Obj,@Args) = @_;
+	    print "EventName1 event triggered\n";
+	}
+
+	package main;
+	Win32::OLE->WithEvents($Obj, 'MyEvents', 'IEventInterface');
+
+If Win32::OLE doesn't find a function with the name of the event then nothing
+happens.
+
+Event parameters passed I<by reference> are handled specially.  They are not
+converted to the corresponding Perl datatype but passed as Win32::OLE::Variant
+objects.  You can assign a new value to these objects with the help of the
+Put() method.  This value will be passed back to the object when the event
+function returns:
+
+	package MyEvents;
+	sub BeforeClose {
+	    my ($self,$Cancel) = @_;
+	    $Cancel->Put(1) unless $MayClose;
+	}
+
+Direct assignment to $Cancel would have no effect on the original value and
+would therefore not command the object to abort the closing action.
+
+=head2 Module Options
+
+The following module options can be accessed and modified with the
+C<Win32::OLE->Option> class method.  In earlier versions of the Win32::OLE
+module these options were manipulated directly as class variables.  This
+practice is now deprecated.
+
+=over 8
+
+=item CP
+
+This variable is used to determine the codepage used by all
+translations between Perl strings and Unicode strings used by the OLE
+interface.  The default value is CP_ACP, which is the default ANSI
+codepage.  Other possible values are CP_OEMCP, CP_MACCP, CP_UTF7 and
+CP_UTF8.  These constants are not exported by default.
+
+=item LCID
+
+This variable controls the locale idnetifier used for all OLE calls.
+It is set to LOCALE_NEUTRAL by default.  Please check the
+L<Win32::OLE::NLS> module for other locale related information.
+
+=item Variant
+
+This options controls how method calls and property accessors return
+values of type VT_CY and VT_DECIMAL are being returned.  By default
+VT_CY values are turned into strings and VT_DECIMAL values into
+floating point numbers.  If the C<Variant> option is enabled, these
+values are returned as Win32::OLE::Variant objects, just like VT_DATE
+and VT_ERROR values.  If the Win32::OLE::Variant module is also
+loaded, then all values should still behave as before in string and in
+numeric context.
+
+The only reason that the C<Variant> behavior is not the default is that
+this is an incompatible change that might break existing programs.
+
+=item Warn
+
+This variable determines the behavior of the Win32::OLE module when
+an error happens.  Valid values are:
+
+	0	Ignore error, return undef
+	1	Carp::carp if $^W is set (-w option)
+	2	always Carp::carp
+	3	Carp::croak
+
+The error number and message (without Carp line/module info) are
+available through the C<Win32::OLE->LastError> class method.
+
+Alternatively the Warn option can be set to a CODE reference.  E.g.
+
+    Win32::OLE->Option(Warn => 3);
+
+is equivalent to
+
+    Win32::OLE->Option(Warn => \&Carp::croak);
+
+This can even be used to emulate the VisualBasic C<On Error Goto
+Label> construct:
+
+    Win32::OLE->Option(Warn =>  sub {goto CheckError});
+    # ... your normal OLE code here ...
+
+  CheckError:
+    # ... your error handling code here ...
+
+=item _NewEnum
+
+This option enables additional enumeration support for collection
+objects.  When the C<_NewEnum> option is set, all collections will
+receive one additional property: C<_NewEnum>.  The value of this
+property will be a reference to an array containing all the elements
+of the collection.  This option can be useful when used in conjunction
+with an automatic tree traversal program, like C<Data::Dumper> or an
+object tree browser.  The value of this option should be either 1
+(enabled) or 0 (disabled, default).
+
+    Win32::OLE->Option(_NewEnum => 1);
+    # ...
+    my @sheets = @{$Excel->Worksheets->{_NewEnum}};
+
+In normal application code, this would be better written as:
+
+    use Win32::OLE qw(in);
+    # ...
+    my @sheets = in $Excel->Worksheets;
+
+=item _Unique
+
+The C<_Unique> options guarantees that Win32::OLE will maintain a
+one-to-one mapping between Win32::OLE objects and the native COM/OLE
+objects.  Without this option, you can query the same property twice
+and get two different Win32::OLE objects for the same underlying COM
+object.
+
+Using a unique proxy makes life easier for tree traversal algorithms
+to recognize they already visited a particular node.  This option
+comes at a price: Win32::OLE has to maintain a global hash of all
+outstanding objects and their corresponding proxies.  Identity checks
+on COM objects can also be expensive if the objects reside
+out-of-process or even on a different computer.  Therefore this option
+is off by default unless the program is being run in the debugger.
+
+Unfortunately, this option doesn't always help.  Some programs will
+return new COM objects for even the same property when asked for it
+multiple times (especially for collections).  In this case, there is
+nothing Win32::OLE can do to detect that these objects are in fact
+identical (because they aren't at the COM level).
+
+The C<_Unique> option can be set to either 1 (enabled) or 0 (disabled,
+default).
+
+=back
+
+=head1 EXAMPLES
+
+Here is a simple Microsoft Excel application.
+
+	use Win32::OLE;
+
+	# use existing instance if Excel is already running
+	eval {$ex = Win32::OLE->GetActiveObject('Excel.Application')};
+	die "Excel not installed" if $@;
+	unless (defined $ex) {
+	    $ex = Win32::OLE->new('Excel.Application', sub {$_[0]->Quit;})
+		    or die "Oops, cannot start Excel";
+	}
+
+        # get a new workbook
+        $book = $ex->Workbooks->Add;
+
+	# write to a particular cell
+	$sheet = $book->Worksheets(1);
+	$sheet->Cells(1,1)->{Value} = "foo";
+
+        # write a 2 rows by 3 columns range
+        $sheet->Range("A8:C9")->{Value} = [[ undef, 'Xyzzy', 'Plugh' ],
+                                           [ 42,    'Perl',  3.1415  ]];
+
+        # print "XyzzyPerl"
+        $array = $sheet->Range("A8:C9")->{Value};
+	for (@$array) {
+	    for (@$_) {
+		print defined($_) ? "$_|" : "<undef>|";
+	    }
+	    print "\n";
+	}
+
+	# save and exit
+        $book->SaveAs( 'test.xls' );
+	undef $book;
+	undef $ex;
+
+Please note the destructor specified on the Win32::OLE->new method.  It ensures
+that Excel will shutdown properly even if the Perl program dies.  Otherwise
+there could be a process leak if your application dies after having opened
+an OLE instance of Excel.  It is the responsibility of the module user to
+make sure that all OLE objects are cleaned up properly!
+
+Here is an example of using Variant data types.
+
+	use Win32::OLE;
+	use Win32::OLE::Variant;
+	$ex = Win32::OLE->new('Excel.Application', \&OleQuit) or die "oops\n";
+	$ex->{Visible} = 1;
+	$ex->Workbooks->Add;
+	# should generate a warning under -w
+	$ovR8 = Variant(VT_R8, "3 is a good number");
+	$ex->Range("A1")->{Value} = $ovR8;
+	$ex->Range("A2")->{Value} = Variant(VT_DATE, 'Jan 1,1970');
+
+	sub OleQuit {
+	    my $self = shift;
+	    $self->Quit;
+	}
+
+The above will put value "3" in cell A1 rather than the string
+"3 is a good number".  Cell A2 will contain the date.
+
+Similarly, to invoke a method with some binary data, you can
+do the following:
+
+	$obj->Method( Variant(VT_UI1, "foo\000b\001a\002r") );
+
+Here is a wrapper class that basically delegates everything but
+new() and DESTROY().  The wrapper class shown here is another way to
+properly shut down connections if your application is liable to die
+without proper cleanup.  Your own wrappers will probably do something
+more specific to the particular OLE object you may be dealing with,
+like overriding the methods that you may wish to enhance with your
+own.
+
+	package Excel;
+	use Win32::OLE;
+
+	sub new {
+	    my $s = {};
+	    if ($s->{Ex} = Win32::OLE->new('Excel.Application')) {
+		return bless $s, shift;
+	    }
+	    return undef;
+	}
+
+	sub DESTROY {
+	    my $s = shift;
+	    if (exists $s->{Ex}) {
+		print "# closing connection\n";
+		$s->{Ex}->Quit;
+		return undef;
+	    }
+	}
+
+	sub AUTOLOAD {
+	    my $s = shift;
+	    $AUTOLOAD =~ s/^.*:://;
+	    $s->{Ex}->$AUTOLOAD(@_);
+	}
+
+	1;
+
+The above module can be used just like Win32::OLE, except that
+it takes care of closing connections in case of abnormal exits.
+Note that the effect of this specific example can be easier accomplished
+using the optional destructor argument of Win32::OLE::new:
+
+	my $Excel = Win32::OLE->new('Excel.Application', sub {$_[0]->Quit;});
+
+Note that the delegation shown in the earlier example is not the same as
+true subclassing with respect to further inheritance of method calls in your
+specialized object.  See L<perlobj>, L<perltoot> and L<perlbot> for details.
+True subclassing (available by setting C<@ISA>) is also feasible,
+as the following example demonstrates:
+
+	#
+	# Add error reporting to Win32::OLE
+	#
+
+	package Win32::OLE::Strict;
+	use Carp;
+	use Win32::OLE;
+
+	use strict qw(vars);
+	use vars qw($AUTOLOAD @ISA);
+	@ISA = qw(Win32::OLE);
+
+	sub AUTOLOAD {
+	    my $obj = shift;
+	    $AUTOLOAD =~ s/^.*:://;
+	    my $meth = $AUTOLOAD;
+	    $AUTOLOAD = "SUPER::" . $AUTOLOAD;
+	    my $retval = $obj->$AUTOLOAD(@_);
+	    unless (defined($retval) || $AUTOLOAD eq 'DESTROY') {
+		my $err = Win32::OLE::LastError();
+		croak(sprintf("$meth returned OLE error 0x%08x",$err))
+		  if $err;
+	    }
+	    return $retval;
+	}
+
+	1;
+
+This package inherits the constructor new() from the Win32::OLE
+package.  It is important to note that you cannot later rebless a
+Win32::OLE object as some information about the package is cached by
+the object.  Always invoke the new() constructor through the right
+package!
+
+Here's how the above class will be used:
+
+	use Win32::OLE::Strict;
+	my $Excel = Win32::OLE::Strict->new('Excel.Application', 'Quit');
+	my $Books = $Excel->Workbooks;
+	$Books->UnknownMethod(42);
+
+In the sample above the call to UnknownMethod() will be caught with
+
+	UnknownMethod returned OLE error 0x80020009 at test.pl line 5
+
+because the Workbooks object inherits the class C<Win32::OLE::Strict> from the
+C<$Excel> object.
+
+=head1 NOTES
+
+=head2 Hints for Microsoft Office automation
+
+=over 8
+
+=item Documentation
+
+The object model for the Office applications is defined in the Visual Basic
+reference guides for the various applications.  These are typically not
+installed by default during the standard installation.  They can be added
+later by rerunning the setup program with the custom install option.
+
+=item Class, Method and Property names
+
+The names have been changed between different versions of Office.  For
+example C<Application> was a method in Office 95 and is a property in
+Office97.  Therefore it will not show up in the list of property names
+C<keys %$object> when querying an Office 95 object.
+
+The class names are not always identical to the method/property names
+producing the object.  E.g. the C<Workbook> method returns an object of
+type C<Workbook> in Office 95 and C<_Workbook> in Office 97.
+
+=item Moniker (GetObject support)
+
+Office applications seem to implement file monikers only.  For example
+it seems to be impossible to retrieve a specific worksheet object through
+C<GetObject("File.XLS!Sheet")>.  Furthermore, in Excel 95 the moniker starts
+a Worksheet object and in Excel 97 it returns a Workbook object.  You can use
+either the Win32::OLE::QueryObjectType class method or the $object->{Version}
+property to write portable code.
+
+=item Enumeration of collection objects
+
+Enumerations seem to be incompletely implemented.  Office 95 application don't
+seem to support neither the Reset() nor the Clone() methods.  The Clone()
+method is still unimplemented in Office 97.  A single walk through the
+collection similar to Visual Basics C<for each> construct does work however.
+
+=item Localization
+
+Starting with Office 97 Microsoft has changed the localized class, method and
+property names back into English.  Note that string, date and currency
+arguments are still subject to locale specific interpretation.  Perl uses the
+system default locale for all OLE transaction whereas Visual Basic uses a
+type library specific locale.  A Visual Basic script would use "R1C1" in string
+arguments to specify relative references.  A Perl script running on a German
+language Windows would have to use "Z1S1".  Set the LCID module option
+to an English locale to write portable scripts.  This variable should
+not be changed after creating the OLE objects; some methods seem to randomly
+fail if the locale is changed on the fly.
+
+=item SaveAs method in Word 97 doesn't work
+
+This is an known bug in Word 97.  Search the MS knowledge base for Word /
+Foxpro incompatibility.  That problem applies to the Perl OLE interface as
+well.  A workaround is to use the WordBasic compatibility object.  It doesn't
+support all the options of the native method though.
+
+    $Word->WordBasic->FileSaveAs($file);
+
+The problem seems to be fixed by applying the Office 97 Service Release 1.
+
+=item Randomly failing method calls
+
+It seems like modifying objects that are not selected/activated is sometimes
+fragile.  Most of these problems go away if the chart/sheet/document is
+selected or activated before being manipulated (just like an interactive
+user would automatically do it).
+
+=back
+
+=head2 Incompatibilities
+
+There are some incompatibilities with the version distributed by Activeware
+(as of build 306).
+
+=over 8
+
+=item 1
+
+The package name has changed from "OLE" to "Win32::OLE".
+
+=item 2
+
+All functions of the form "Win32::OLEFoo" are now "Win32::OLE::Foo",
+though the old names are temporarily accomodated.  Win32::OLECreateObject()
+was changed to Win32::OLE::CreateObject(), and is now called
+Win32::OLE::new() bowing to established convention for naming constructors.
+The old names should be considered deprecated, and will be removed in the
+next version.
+
+=item 3
+
+Package "OLE::Variant" is now "Win32::OLE::Variant".
+
+=item 4
+
+The Variant function is new, and is exported by default.  So are
+all the VT_XXX type constants.
+
+=item 5
+
+The support for collection objects has been moved into the package
+Win32::OLE::Enum.  The C<keys %$object> method is now used to enumerate
+the properties of the object.
+
+=back
+
+=head2 Bugs and Limitations
+
+=over 8
+
+=item *
+
+To invoke a native OLE method with the same name as one of the
+Win32::OLE methods (C<Dispatch>, C<Invoke>, C<SetProperty>, C<DESTROY>,
+etc.), you have to use the C<Invoke> method:
+
+	$Object->Invoke('Dispatch', @AdditionalArgs);
+
+The same is true for names exported by the Exporter or the Dynaloader
+modules, e.g.: C<export>, C<export_to_level>, C<import>,
+C<_push_tags>, C<export_tags>, C<export_ok_tags>, C<export_fail>,
+C<require_version>, C<dl_load_flags>,
+C<croak>, C<bootstrap>, C<dl_findfile>, C<dl_expandspec>,
+C<dl_find_symbol_anywhere>, C<dl_load_file>, C<dl_find_symbol>,
+C<dl_undef_symbols>, C<dl_install_xsub> and C<dl_error>.
+
+=back
+
+=head1 SEE ALSO
+
+The documentation for L<Win32::OLE::Const>, L<Win32::OLE::Enum>,
+L<Win32::OLE::NLS> and L<Win32::OLE::Variant> contains additional
+information about OLE support for Perl on Win32.
+
+=head1 AUTHORS
+
+Originally put together by the kind people at Hip and Activeware.
+
+Gurusamy Sarathy <gsar@activestate.com> subsequently fixed several
+major bugs, memory leaks, and reliability problems, along with some
+redesign of the code.
+
+Jan Dubois <jand@activestate.com> pitched in with yet more massive redesign,
+added support for named parameters, and other significant enhancements.
+He's been hacking on it ever since.
+
+Please send questions about problems with this module to the
+Perl-Win32-Users mailinglist at ActiveState.com.  The mailinglist charter
+requests that you put an [OLE] tag somewhere on the subject line (for OLE
+related questions only, of course).
+
+=head1 COPYRIGHT
+
+    (c) 1995 Microsoft Corporation. All rights reserved.
+    Developed by ActiveWare Internet Corp., now known as
+    ActiveState Tool Corp., http://www.ActiveState.com
+
+    Other modifications Copyright (c) 1997-2000 by Gurusamy Sarathy
+    <gsar@activestate.com> and Jan Dubois <jand@activestate.com>
+
+    You may distribute under the terms of either the GNU General Public
+    License or the Artistic License, as specified in the README file.
+
+=head1 VERSION
+
+Version 0.1701	  28 August 2003
+
+=cut
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/OLE/Const.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/OLE/Const.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/OLE/Const.pm	(revision 14139)
@@ -0,0 +1,197 @@
+# The documentation is at the __END__
+
+package Win32::OLE::Const;
+
+use strict;
+use Carp;
+use Win32::OLE;
+
+my $Typelibs;
+sub _Typelib {
+    my ($clsid,$title,$version,$langid,$filename) = @_;
+    # Filenames might have a resource index appended to it.
+    $filename = $1 if $filename =~ /^(.*\.(?:dll|exe))(\\\d+)$/i;
+    # Ignore if it looks like a file but doesn't exist.
+    # We don't verify existance of monikers or filenames
+    # without a full pathname.
+    return unless -f $filename || $filename !~ /^\w:\\.*\.(exe|dll)$/;
+    push @$Typelibs, \@_;
+}
+__PACKAGE__->_Typelibs;
+
+sub import {
+    my ($self,$name,$major,$minor,$language,$codepage) = @_;
+    return unless defined($name) && $name !~ /^\s*$/;
+    $self->Load($name,$major,$minor,$language,$codepage,scalar caller);
+}
+
+sub EnumTypeLibs {
+    my ($self,$callback) = @_;
+    foreach (@$Typelibs) { &$callback(@$_) }
+    return;
+}
+
+sub Load {
+    my ($self,$name,$major,$minor,$language,$codepage,$caller) = @_;
+
+    if (UNIVERSAL::isa($name,'Win32::OLE')) {
+	my $typelib = $name->GetTypeInfo->GetContainingTypeLib;
+	return _Constants($typelib, undef);
+    }
+
+    undef $minor unless defined $major;
+    my $typelib = $self->LoadRegTypeLib($name,$major,$minor,
+					$language,$codepage);
+    return _Constants($typelib, $caller);
+}
+
+sub LoadRegTypeLib {
+    my ($self,$name,$major,$minor,$language,$codepage) = @_;
+    undef $minor unless defined $major;
+
+    unless (defined($name) && $name !~ /^\s*$/) {
+	carp "Win32::OLE::Const->Load: No or invalid type library name";
+	return;
+    }
+
+    my @found;
+    foreach my $Typelib (@$Typelibs) {
+	my ($clsid,$title,$version,$langid,$filename) = @$Typelib;
+	next unless $title =~ /^$name/;
+	next unless $version =~ /^([0-9a-fA-F]+)\.([0-9a-fA-F]+)$/;
+	my ($maj,$min) = (hex($1), hex($2));
+	next if defined($major) && $maj != $major;
+	next if defined($minor) && $min < $minor;
+	next if defined($language) && $language != $langid;
+	push @found, [$clsid,$maj,$min,$langid,$filename];
+    }
+
+    unless (@found) {
+	carp "No type library matching \"$name\" found";
+	return;
+    }
+
+    @found = sort {
+	# Prefer greater version number
+	my $res = $b->[1] <=> $a->[1];
+	$res = $b->[2] <=> $a->[2] if $res == 0;
+	# Prefer default language for equal version numbers
+	$res = -1 if $res == 0 && $a->[3] == 0;
+	$res =  1 if $res == 0 && $b->[3] == 0;
+	$res;
+    } @found;
+
+    #printf "Loading %s\n", join(' ', @{$found[0]});
+    return _LoadRegTypeLib(@{$found[0]},$codepage);
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Win32::OLE::Const - Extract constant definitions from TypeLib
+
+=head1 SYNOPSIS
+
+    use Win32::OLE::Const 'Microsoft Excel';
+    printf "xlMarkerStyleDot = %d\n", xlMarkerStyleDot;
+
+    my $wd = Win32::OLE::Const->Load("Microsoft Word 8\\.0 Object Library");
+    foreach my $key (keys %$wd) {
+        printf "$key = %s\n", $wd->{$key};
+    }
+
+=head1 DESCRIPTION
+
+This modules makes all constants from a registered OLE type library
+available to the Perl program.  The constant definitions can be
+imported as functions, providing compile time name checking.
+Alternatively the constants can be returned in a hash reference
+which avoids defining lots of functions of unknown names.
+
+=head2 Functions/Methods
+
+=over 4
+
+=item use Win32::OLE::Const
+
+The C<use> statement can be used to directly import the constant names
+and values into the users namespace.
+
+    use Win32::OLE::Const (TYPELIB,MAJOR,MINOR,LANGUAGE);
+
+The TYPELIB argument specifies a regular expression for searching
+through the registry for the type library.  Note that this argument is
+implicitly prefixed with C<^> to speed up matches in the most common
+cases.  Use a typelib name like ".*Excel" to match anywhere within the
+description.  TYPELIB is the only required argument.
+
+The MAJOR and MINOR arguments specify the requested version of
+the type specification.  If the MAJOR argument is used then only
+typelibs with exactly this major version number will be matched.  The
+MINOR argument however specifies the minimum acceptable minor version.
+MINOR is ignored if MAJOR is undefined.
+
+If the LANGUAGE argument is used then only typelibs with exactly this
+language id will be matched.
+
+The module will select the typelib with the highest version number
+satisfying the request.  If no language id is specified then a the default
+language (0) will be preferred over the others.
+
+Note that only constants with valid Perl variable names will be exported,
+i.e. names matching this regexp: C</^[a-zA-Z_][a-zA-Z0-9_]*$/>.
+
+=item Win32::OLE::Const->Load
+
+The Win32::OLE::Const->Load method returns a reference to a hash of
+constant definitions.
+
+    my $const = Win32::OLE::Const->Load(TYPELIB,MAJOR,MINOR,LANGUAGE);
+
+The parameters are the same as for the C<use> case.
+
+This method is generally preferrable when the typelib uses a non-english
+language and the constant names contain locale specific characters not
+allowed in Perl variable names.
+
+Another advantage is that all available constants can now be enumerated.
+
+The load method also accepts an OLE object as a parameter.  In this case
+the OLE object is queried about its containing type library and no registry
+search is done at all.  Interestingly this seems to be slower.
+
+=back
+
+=head1 EXAMPLES
+
+The first example imports all Excel constants names into the main namespace
+and prints the value of xlMarkerStyleDot (-4118).
+
+    use Win32::OLE::Const ('Microsoft Excel 8.0 Object Library');
+    print "xlMarkerStyleDot = %d\n", xlMarkerStyleDot;
+
+The second example returns all Word constants in a hash ref.
+
+    use Win32::OLE::Const;
+    my $wd = Win32::OLE::Const->Load("Microsoft Word 8.0 Object Library");
+    foreach my $key (keys %$wd) {
+        printf "$key = %s\n", $wd->{$key};
+    }
+    printf "wdGreen = %s\n", $wd->{wdGreen};
+
+The last example uses an OLE object to specify the type library:
+
+    use Win32::OLE;
+    use Win32::OLE::Const;
+    my $Excel = Win32::OLE->new('Excel.Application', 'Quit');
+    my $xl = Win32::OLE::Const->Load($Excel);
+
+
+=head1 AUTHORS/COPYRIGHT
+
+This module is part of the Win32::OLE distribution.
+
+=cut
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/OLE/Enum.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/OLE/Enum.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/OLE/Enum.pm	(revision 14139)
@@ -0,0 +1,95 @@
+# The documentation is at the __END__
+
+package Win32::OLE::Enum;
+1;
+
+# everything is pure XS in Win32::OLE::Enum
+# - new
+# - DESTROY
+#
+# - All
+# - Clone
+# - Next
+# - Reset
+# - Skip
+
+__END__
+
+=head1 NAME
+
+Win32::OLE::Enum - OLE Automation Collection Objects
+
+=head1 SYNOPSIS
+
+    my $Sheets = $Excel->Workbooks(1)->Worksheets;
+    my $Enum = Win32::OLE::Enum->new($Sheets);
+    my @Sheets = $Enum->All;
+
+    while (defined(my $Sheet = $Enum->Next)) { ... }
+
+=head1 DESCRIPTION
+
+This module provides an interface to OLE collection objects from
+Perl.  It defines an enumerator object closely mirroring the
+functionality of the IEnumVARIANT interface.
+
+Please note that the Reset() method is not available in all implementations
+of OLE collections (like Excel 7).  In that case the Enum object is good
+only for a single walk through of the collection.
+
+=head2 Functions/Methods
+
+=over 8
+
+=item Win32::OLE::Enum->new($object)
+
+Creates an enumerator for $object, which must be a valid OLE collection
+object.  Note that correctly implemented collection objects must support
+the C<Count> and C<Item> methods, so creating an enumerator is not always
+necessary.
+
+=item $Enum->All()
+
+Returns a list of all objects in the collection.  You have to call
+$Enum->Reset() before the enumerator can be used again.  The previous
+position in the collection is lost.
+
+This method can also be called as a class method:
+
+	my @list = Win32::OLE::Enum->All($Collection);
+
+=item $Enum->Clone()
+
+Returns a clone of the enumerator maintaining the current position within
+the collection (if possible).  Note that the C<Clone> method is often not
+implemented.  Use $Enum->Clone() in an eval block to avoid dying if you
+are not sure that Clone is supported.
+
+=item $Enum->Next( [$count] )
+
+Returns the next element of the collection.  In a list context the optional
+$count argument specifies the number of objects to be returned.  In a scalar
+context only the last of at most $count retrieved objects is returned.  The
+default for $count is 1.
+
+=item $Enum->Reset()
+
+Resets the enumeration sequence to the beginning.  There is no guarantee that
+the exact same set of objects will be enumerated again (e.g. when enumerating
+files in a directory).  The methods return value indicates the success of the
+operation.  (Note that the Reset() method seems to be unimplemented in some
+applications like Excel 7.  Use it in an eval block to avoid dying.)
+
+=item $Enum->Skip( [$count] )
+
+Skip the next $count elements of the enumeration.  The default for $count is 1.
+The functions returns TRUE if at least $count elements could be skipped.  It
+returns FALSE if not enough elements were left.
+
+=back
+
+=head1 AUTHORS/COPYRIGHT
+
+This module is part of the Win32::OLE distribution.
+
+=cut
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/OLE/Lite.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/OLE/Lite.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/OLE/Lite.pm	(revision 14139)
@@ -0,0 +1,224 @@
+package Win32::OLE;
+
+sub _croak { require Carp; Carp::croak(@_) }
+
+unless (defined &Dispatch) {
+    DynaLoader::boot_DynaLoader('DynaLoader')
+	    unless defined(&DynaLoader::dl_load_file);
+    my $file;
+    foreach my $dir (@INC) {
+	my $try = "$dir/auto/Win32/OLE/OLE.dll";
+	last if $file = (-f $try && $try);
+    }
+    _croak("Can't locate loadable object for module Win32::OLE".
+	   " in \@INC (\@INC contains: @INC)")
+	unless $file;	# wording similar to error from 'require'
+
+    my $libref = DynaLoader::dl_load_file($file, 0) or
+	_croak("Can't load '$file' for module Win32::OLE: ".
+	       DynaLoader::dl_error()."\n");
+
+    my $boot_symbol_ref = DynaLoader::dl_find_symbol($libref, "boot_Win32__OLE")
+	or _croak("Can't find 'boot_Win32__OLE' symbol in $file\n");
+
+    my $xs = DynaLoader::dl_install_xsub("Win32::OLE::bootstrap",
+					 $boot_symbol_ref, $file);
+    &$xs('Win32::OLE');
+}
+
+if (defined &DB::sub && !defined $_Unique) {
+    warn "Win32::OLE operating in debugging mode: _Unique => 1\n";
+    $_Unique = 1;
+}
+
+$Warn = 1;
+
+sub CP_ACP   {0;}     # ANSI codepage
+sub CP_OEMCP {1;}     # OEM codepage
+sub CP_MACCP {2;}
+sub CP_UTF7  {65000;}
+sub CP_UTF8  {65001;}
+
+sub DISPATCH_METHOD          {1;}
+sub DISPATCH_PROPERTYGET     {2;}
+sub DISPATCH_PROPERTYPUT     {4;}
+sub DISPATCH_PROPERTYPUTREF  {8;}
+
+sub COINIT_MULTITHREADED     {0;}  # Default
+sub COINIT_APARTMENTTHREADED {2;}  # Use single threaded apartment model
+
+# Bogus COINIT_* values to indicate special cases:
+sub COINIT_OLEINITIALIZE     {-1;} # Use OleInitialize instead of CoInitializeEx
+sub COINIT_NO_INITIALIZE     {-2;} # We are already initialized, just believe me
+
+sub HRESULT {
+    my $hr = shift;
+    $hr -= 2**32 if $hr & 0x80000000;
+    return $hr;
+}
+
+# CreateObject is defined here only because it is documented in the
+# "Learning Perl on Win32 Systems" Gecko book. Please use Win32::OLE->new().
+sub CreateObject {
+    if (ref($_[0]) && UNIVERSAL::isa($_[0],'Win32::OLE')) {
+	$AUTOLOAD = ref($_[0]) . '::CreateObject';
+	goto &AUTOLOAD;
+    }
+
+    # Hack to allow C<$obj = CreateObject Win32::OLE 'My.App';>. Although this
+    # is contrary to the Gecko, we just make it work since it doesn't hurt.
+    return Win32::OLE->new($_[1]) if $_[0] eq 'Win32::OLE';
+
+    # Gecko form: C<$success = Win32::OLE::CreateObject('My.App',$obj);>
+    $_[1] = Win32::OLE->new($_[0]);
+    return defined $_[1];
+}
+
+sub LastError {
+    unless (defined $_[0]) {
+	# Win32::OLE::LastError() will always return $Win32::OLE::LastError
+	return $LastError;
+    }
+
+    if (ref($_[0]) && UNIVERSAL::isa($_[0],'Win32::OLE')) {
+	$AUTOLOAD = ref($_[0]) . '::LastError';
+	goto &AUTOLOAD;
+    }
+
+    #no strict 'refs';
+    my $LastError = "$_[0]::LastError";
+    $$LastError = $_[1] if defined $_[1];
+    return $$LastError;
+}
+
+my $Options = "^(?:CP|LCID|Warn|Variant|_NewEnum|_Unique)\$";
+
+sub Option {
+    if (ref($_[0]) && UNIVERSAL::isa($_[0],'Win32::OLE')) {
+	$AUTOLOAD = ref($_[0]) . '::Option';
+	goto &AUTOLOAD;
+    }
+
+    my $class = shift;
+
+    if (@_ == 1) {
+	my $option = shift;
+	return ${"${class}::$option"} if $option =~ /$Options/o;
+	_croak("Invalid $class option: $option");
+    }
+
+    while (@_) {
+	my ($option,$value) = splice @_, 0, 2;
+	_croak("Invalid $class option: $option") if $option !~ /$Options/o;
+	${"${class}::$option"} = $value;
+	$class->_Unique() if $option eq "_Unique";
+    }
+}
+
+sub Invoke {
+    my ($self,$method,@args) = @_;
+    $self->Dispatch($method, my $retval, @args);
+    return $retval;
+}
+
+sub LetProperty {
+    my ($self,$method,@args) = @_;
+    $self->Dispatch([DISPATCH_PROPERTYPUT, $method], my $retval, @args);
+    return $retval;
+}
+
+sub SetProperty {
+    my ($self,$method,@args) = @_;
+    my $wFlags = DISPATCH_PROPERTYPUT;
+    if (@args) {
+	# If the value is an object then it will be set by reference!
+	my $value = $args[-1];
+	if (UNIVERSAL::isa($value, 'Win32::OLE')) {
+	    $wFlags = DISPATCH_PROPERTYPUTREF;
+	}
+	elsif (UNIVERSAL::isa($value,'Win32::OLE::Variant')) {
+	    my $type = $value->Type & ~0xfff; # VT_TYPEMASK
+	    # VT_DISPATCH and VT_UNKNOWN represent COM objects
+	    $wFlags = DISPATCH_PROPERTYPUTREF if $type == 9 || $type == 13;
+	}
+    }
+    $self->Dispatch([$wFlags, $method], my $retval, @args);
+    return $retval;
+}
+
+sub AUTOLOAD {
+    my $self = shift;
+    my $autoload = substr $AUTOLOAD, rindex($AUTOLOAD, ':')+1;
+    _croak("Cannot autoload class method \"$autoload\"")
+	unless ref($self) && UNIVERSAL::isa($self, 'Win32::OLE');
+    my $success = $self->Dispatch($autoload, my $retval, @_);
+    unless (defined $success || ($^H & 0x200) != 0) {
+	# Retry default method if C<no strict 'subs';>
+	$self->Dispatch(undef, $retval, $autoload, @_);
+    }
+    return $retval;
+}
+
+sub in {
+    my @res;
+    while (@_) {
+	my $this = shift;
+	if (UNIVERSAL::isa($this, 'Win32::OLE')) {
+	    push @res, Win32::OLE::Enum->All($this);
+	}
+	elsif (ref($this) eq 'ARRAY') {
+	    push @res, @$this;
+	}
+	else {
+	    push @res, $this;
+	}
+    }
+    return @res;
+}
+
+sub valof {
+    my $arg = shift;
+    if (UNIVERSAL::isa($arg, 'Win32::OLE')) {
+	require Win32::OLE::Variant;
+	my ($class) = overload::StrVal($arg) =~ /^([^=]+)=/;
+	#no strict 'refs';
+	local $Win32::OLE::CP = ${"${class}::CP"};
+	local $Win32::OLE::LCID = ${"${class}::LCID"};
+	#use strict 'refs';
+	# VT_EMPTY variant for return code
+	my $variant = Win32::OLE::Variant->new;
+	$arg->Dispatch(undef, $variant);
+	return $variant->Value;
+    }
+    $arg = $arg->Value if UNIVERSAL::can($arg, 'Value');
+    return $arg;
+}
+
+sub with {
+    my $object = shift;
+    while (@_) {
+	my $property = shift;
+	$object->{$property} = shift;
+    }
+}
+
+########################################################################
+
+package Win32::OLE::Tie;
+
+# Only retry default method under C<no strict 'subs';>
+sub FETCH {
+    my ($self,$key) = @_;
+    if ($key eq "_NewEnum") {
+	(my $class = ref $self) =~ s/::Tie$//;
+	return [Win32::OLE::Enum->All($self)] if ${"${class}::_NewEnum"};
+    }
+    $self->Fetch($key, !$Win32::OLE::Strict);
+}
+
+sub STORE {
+    my ($self,$key,$value) = @_;
+    $self->Store($key, $value, !$Win32::OLE::Strict);
+}
+
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/OLE/NEWS.pod
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/OLE/NEWS.pod	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/OLE/NEWS.pod	(revision 14139)
@@ -0,0 +1,380 @@
+=pod
+
+=head1 NAME
+
+Win32::OLE::NEWS - What's new in Win32::OLE
+
+This file contains a history of user visible changes to the
+Win32::OLE::* modules. Only new features and major bug fixes that
+might affect backwards compatibility are included.
+
+=head1 Version 0.18
+
+=head2 VT_CY and VT_DECIMAL return values handled differently
+
+The new C<Variant> option enables values of VT_CY or VT_DECIMAL type
+to be returned as Win32::OLE::Variant objects instead of being
+converted into strings and numbers respectively.  This is similar to
+the change in Win32::OLE version 0.12 to VT_DATE and VT_ERROR values.
+The Win32::OLE::Variant module must be included to make sure that
+VT_CY and VT_DECIMAL values behave as before in numeric or string
+contexts.
+
+Because the new behavior is potentially incompatible, it must be
+explicitly enabled:
+
+    Win32::OLE->Option(Variant => 1);
+
+
+=head1 Version 0.17
+
+=head2 New nullstring() function in Win32::OLE::Variant
+
+The nullstring() function returns a VT_BSTR variant containing a NULL
+string pointer.  Note that this is not the same as a VT_BSTR variant
+containing the empty string "".
+
+The nullstring() return value is equivalent to the Visual Basic
+C<vbNullString> constant.
+
+
+=head1 Version 0.16
+
+=head2 Improved Unicode support
+
+Passing Unicode strings to methods and properties as well as returning
+Unicode strings back to Perl works now with both Perl 5.6 and 5.8.
+Note that the Unicode support in 5.8 is much more complete than in 5.6
+or 5.6.1.
+
+C<Unicode::String> objects can now be passed to methods or assigned to
+properties.
+
+You must enable Unicode support by switching Win32::OLE to the UTF8
+codepage:
+
+    Win32::OLE->Option(CP => Win32::OLE::CP_UTF8());
+
+
+=head1 Version 0.13
+
+=head2 New nothing() function in Win32::OLE::Variant
+
+The nothing() function returns an empty VT_DISPATCH variant.  It can be
+used to clear an object reference stored in a property
+
+	use Win32::OLE::Variant qw(:DEFAULT nothing);
+	# ...
+	$object->{Property} = nothing;
+
+This has the same effect as the Visual Basic statement
+
+	Set object.Property = Nothing
+
+=head2 New _NewEnum and _Unique options
+
+There are two new options available for the Win32::OLE->Option class
+method: C<_NewEnum> provides the elements of a collection object
+directly as the value of a C<_NewEnum> property.  The C<_Unique>
+option guarantees that Win32::OLE will not create multiple proxy
+objects for the same underlying COM/OLE object.
+
+Both options are only really useful to tree traversal programs or
+during debugging.
+
+
+=head1 Version 0.12
+
+=head2 Additional error handling functionality
+
+The Warn option can now be set to a CODE reference too.  For example,
+
+    Win32::OLE->Option(Warn => 3);
+
+could now be written as
+
+    Win32::OLE->Option(Warn => \&Carp::croak);
+
+This can even be used to emulate the VisualBasic C<On Error Goto
+Label> construct:
+
+    Win32::OLE->Option(Warn =>  sub {goto CheckError});
+    # ... your normal OLE code here ...
+
+  CheckError:
+    # ... your error handling code here ...
+
+=head2 Builtin event loop
+
+Processing OLE events required a polling loop before, e.g.
+
+    my $Quit;
+    #...
+    until ($Quit) {
+        Win32::OLE->SpinMessageLoop;
+        Win32::Sleep(100);
+    }
+    package BrowserEvents;
+    sub OnQuit { $Quit = 1 }
+
+This is inefficient and a bit odd.  This version of Win32::OLE now
+supports a standard messageloop:
+
+    Win32::OLE->MessageLoop();
+
+    package BrowserEvents;
+    sub OnQuit { Win32::OLE->QuitMessageLoop }
+
+=head2 Free unused OLE libraries
+
+Previous versions of Win32::OLE would call the CoFreeUnusedLibraries()
+API whenever an OLE object was destroyed.  This made sure that OLE
+libraries would be unloaded as soon as they were no longer needed.
+Unfortunately, objects implemented in Visual Basic tend to crash
+during this call, as they pretend to be ready for unloading, when in
+fact, they aren't.
+
+The unloading of object libraries is really only important for long
+running processes that might instantiate a huge number of B<different>
+objects over time.  Therefore this API is no longer called
+automatically.  The functionality is now available explicitly to those
+who want or need it by calling a Win32::OLE class method:
+
+    Win32::OLE->FreeUnusedLibraries();
+
+=head2 The "Win32::OLE" article from "The Perl Journal #10"
+
+The article is Copyright 1998 by I<The Perl
+Journal>. http://www.tpj.com
+
+It originally appeared in I<The Perl Journal> # 10 and appears here
+courtesy of Jon Orwant and I<The Perl Journal>.  The sample code from
+the article is in the F<eg/tpj.pl> file.
+
+=head2 VARIANT->Put() bug fixes
+
+The Put() method didn't work correctly for arrays of type VT_BSTR,
+VT_DISPATH or VT_UNKNOWN.  This has been fixed.
+
+=head2 Error message fixes
+
+Previous versions of Win32::OLE gave a wrong argument index for some
+OLE error messages (the number was too large by 1).  This should be
+fixed now.
+
+=head2 VT_DATE and VT_ERROR return values handled differently
+
+Method calls and property accesses returning a VT_DATE or VT_ERROR
+value would previously translate the value to string or integer
+format.  This has been changed to return a Win32::OLE::Variant object.
+The return values will behave as before if the Win32::OLE::Variant
+module is being used.  This module overloads the conversion of
+the objects to strings and numbers.
+
+
+=head1 Version 0.11 (changes since 0.1008)
+
+=head2 new DHTML typelib browser
+
+The Win32::OLE distribution now contains a type library browser.  It
+is written in PerlScript, generating dynamic HTML.  It requires
+Internet Explorer 4.0 or later.  You'll find it in
+F<browser/Browser.html>.  It should be available in the ActivePerl
+HTML help under Win32::OLE::Browser.
+
+After selecting a library, type or member you can press F1 to call up
+the corresponding help file at the appropriate location.
+
+=head2 VT_DECIMAL support
+
+The Win32::OLE::Variant module now supports VT_DECIMAL variants too.
+They are not "officially" allowed in OLE Automation calls, but even
+Microsoft's "ActiveX Data Objects" sometimes returns VT_DECIMAL
+values.
+
+VT_DECIMAL variables are stored as 96-bit integers scaled by a
+variable power of 10.  The power of 10 scaling factor specifies the
+number of digits to the right of the decimal point, and ranges from 0
+to 28.  With a scale of 0 (no decimal places), the largest possible
+value is +/-79,228,162,514,264,337,593,543,950,335.  With a 28 decimal
+places, the largest value is +/-7.9228162514264337593543950335 and the
+smallest, non-zero value is +/-0.0000000000000000000000000001.
+
+=head1 Version 0.1008
+
+=head2 new LetProperty() object method
+
+In Win32::OLE property assignment using the hash syntax is equivalent
+to the Visual Basic C<Set> syntax (I<by reference> assignment):
+
+  $Object->{Property} = $OtherObject;
+
+corresponds to this Visual Basic statement:
+
+  Set Object.Property = OtherObject
+
+To get the I<by value> treatment of the Visual Basic C<Let> statement
+
+  Object.Property = OtherObject
+
+you have to use the LetProperty() object method in Perl:
+
+  $Object->LetProperty($Property, $OtherObject);
+
+=head2 new HRESULT() function
+
+The HRESULT() function converts an unsigned number into a signed HRESULT
+error value as used by OLE internally. This is necessary because Perl
+treats all hexadecimal constants as unsigned. To check if the last OLE
+function returned "Member not found" (0x80020003) you can write:
+
+  if (Win32::OLE->LastError == HRESULT(0x80020003)) {
+      # your error recovery here
+  }
+
+=head1 Version 0.1007 (changes since 0.1005)
+
+=head2 OLE Event support
+
+This version of Win32::OLE contains B<ALPHA> level support for OLE events. The
+userinterface is still subject to change. There are ActiveX objects / controls
+that don't fire events under the current implementation.
+
+Events are enabled for a specific object with the Win32::OLE->WithEvents()
+class method:
+
+  Win32::OLE->WithEvents(OBJECT, HANDLER, INTERFACE)
+
+Please read further documentation in Win32::OLE.
+
+=head2 GetObject() and GetActiveObject() now support optional DESTRUCTOR argument
+
+It is now possible to specify a DESTRUCTOR argument to the GetObject() and
+GetActiveObject() class methods. They work identical to the new() DESTRUCTOR
+argument.
+
+=head2 Remote object instantiation via DCOM
+
+This has actually been in Win32::OLE since 0.0608, but somehow never got
+documented. You can provide an array reference in place of the usual PROGID
+parameter to Win32::OLE->new():
+
+  OBJ = Win32::OLE->new([MACHINE, PRODID]);
+
+The array must contain two elements: the name of the MACHINE and the PROGID.
+This will try to create the object on the remote MACHINE.
+
+=head2 Enumerate all Win32::OLE objects
+
+This class method returns the number Win32::OLE objects currently in
+existance. It will call the optional CALLBACK function for each of
+these objects:
+
+  $Count = Win32::OLE->EnumAllObjects(sub {
+      my $Object = shift;
+      my $Class = Win32::OLE->QueryObjectType($Object);
+      printf "# Object=%s Class=%s\n", $Object, $Class;
+  });
+
+The EnumAllObjects() method is primarily a debugging tool. It can be
+used e.g. in an END block to check if all external connections have
+been properly destroyed.
+
+=head2 The VARIANT->Put() method now returns the VARIANT object itself
+
+This allows chaining of Put() method calls to set multiple values in an
+array variant:
+
+  $Array->Put(0,0,$First_value)->Put(0,1,$Another_value);
+
+=head2 The VARIANT->Put(ARRAYREF) form allows assignment to a complete SAFEARRAY
+
+This allows automatic conversion from a list of lists to a SAFEARRAY.
+You can now write:
+
+  my $Array = Variant(VT_ARRAY|VT_R8, [1,2], 2);
+  $Array->Put([[1,2], [3,4]]);
+
+instead of the tedious:
+
+  $Array->Put(1,0,1);
+  $Array->Put(1,1,2);
+  $Array->Put(2,0,3);
+  $Array->Put(2,1,4);
+
+=head2 New Variant formatting methods
+
+There are four new methods for formatting variant values: Currency(), Date(),
+Number() and Time(). For example:
+
+  my $v = Variant(VT_DATE, "April 1 99");
+  print $v->Date(DATE_LONGDATE), "\n";
+  print $v->Date("ddd',' MMM dd yy"), "\n";
+
+will print:
+
+  Thursday, April 01, 1999
+  Thu, Apr 01 99
+
+=head2 new Win32::OLE::NLS methods: SendSettingChange() and SetLocaleInfo()
+
+SendSettingChange() sends a WM_SETTINGCHANGE message to all top level windows.
+
+SetLocaleInfo() allows changing elements in the user override section of the
+locale database. Unfortunately these changes are not automatically available
+to further Variant formatting; you have to call SendSettingChange() first.
+
+=head2 Win32::OLE::Const now correctly treats version numbers as hex
+
+The minor and major version numbers of type libraries have been treated as
+decimal. This was wrong. They are now correctly decoded as hex.
+
+=head2 more robust global destruction of Win32::OLE objects
+
+The final destruction of Win32::OLE objects has always been somewhat fragile.
+The reason for this is that Perl doesn't honour reference counts during global
+destruction but destroys objects in seemingly random order. This can lead
+to leaked database connections or unterminated external objects. The only
+solution was to make all objects lexical and hope that no object would be
+trapped in a closure. Alternatively all objects could be explicitly set to
+C<undef>, which doesn't work very well with exception handling.
+
+With version 0.1007 of Win32::OLE this problem should be gone: The module
+keeps a list of active Win32::OLE objects. It uses an END block to destroy
+all objects at program termination I<before> the Perl's global destruction
+starts. Objects still existing at program termination are now destroyed in
+reverse order of creation. The effect is similar to explicitly calling
+Win32::OLE->Uninitialize() just prior to termination.
+
+=head1 Version 0.1005 (changes since 0.1003)
+
+Win32::OLE 0.1005 has been release with ActivePerl build 509. It is also
+included in the I<Perl Resource Kit for Win32> Update.
+
+=head2 optional DESTRUCTOR for GetActiveObject() GetObject() class methods
+
+The GetActiveObject() and GetObject() class method now also support an
+optional DESTRUCTOR parameter just like Win32::OLE->new(). The DESTRUCTOR
+is executed when the last reference to this object goes away. It is
+generally considered C<impolite> to stop applications that you did not
+start yourself.
+
+=head2 new Variant object method: $object->Copy()
+
+See L<Win32::OLE::Variant/Copy([DIM])>.
+
+=head2 new Win32::OLE->Option() class method
+
+The Option() class method can be used to inspect and modify
+L<Win32::OLE/Module Options>. The single argument form retrieves
+the value of an option:
+
+  my $CP = Win32::OLE->Option('CP');
+
+A single call can be used to set multiple options simultaneously:
+
+  Win32::OLE->Option(CP => CP_ACP, Warn => 3);
+
+Currently the following options exist: CP, LCID and C<Warn>.
+
+=cut
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/OLE/NLS.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/OLE/NLS.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/OLE/NLS.pm	(revision 14139)
@@ -0,0 +1,968 @@
+# The documentation is at the __END__
+
+package Win32::OLE::NLS;
+require Win32::OLE;  # Make sure the XS bootstrap has been called
+
+use strict;
+use vars qw(@EXPORT @EXPORT_OK %EXPORT_TAGS @ISA);
+
+use Exporter;
+@ISA = qw(Exporter);
+
+@EXPORT = qw(
+	     CompareString
+	     LCMapString
+	     GetLocaleInfo
+	     GetStringType
+	     GetSystemDefaultLangID
+	     GetSystemDefaultLCID
+	     GetUserDefaultLangID
+	     GetUserDefaultLCID
+
+	     MAKELANGID
+	     PRIMARYLANGID
+	     SUBLANGID
+	     LANG_SYSTEM_DEFAULT
+	     LANG_USER_DEFAULT
+	     MAKELCID
+	     LANGIDFROMLCID
+	     LOCALE_SYSTEM_DEFAULT
+	     LOCALE_USER_DEFAULT
+	    );
+
+@EXPORT_OK = qw(SetLocaleInfo SendSettingChange);
+
+%EXPORT_TAGS =
+(
+ CT	 => [qw(CT_CTYPE1 CT_CTYPE2 CT_CTYPE3)],
+ C1	 => [qw(C1_UPPER C1_LOWER C1_DIGIT C1_SPACE C1_PUNCT
+		C1_CNTRL C1_BLANK C1_XDIGIT C1_ALPHA)],
+ C2	 => [qw(C2_LEFTTORIGHT C2_RIGHTTOLEFT C2_EUROPENUMBER
+		C2_EUROPESEPARATOR C2_EUROPETERMINATOR C2_ARABICNUMBER
+		C2_COMMONSEPARATOR C2_BLOCKSEPARATOR C2_SEGMENTSEPARATOR
+		C2_WHITESPACE C2_OTHERNEUTRAL C2_NOTAPPLICABLE)],
+ C3	 => [qw(C3_NONSPACING C3_DIACRITIC C3_VOWELMARK C3_SYMBOL C3_KATAKANA
+		C3_HIRAGANA C3_HALFWIDTH C3_FULLWIDTH C3_IDEOGRAPH C3_KASHIDA
+		C3_ALPHA C3_NOTAPPLICABLE)],
+ NORM	 => [qw(NORM_IGNORECASE NORM_IGNORENONSPACE NORM_IGNORESYMBOLS
+		NORM_IGNOREWIDTH NORM_IGNOREKANATYPE NORM_IGNOREKASHIDA)],
+ LCMAP	 => [qw(LCMAP_LOWERCASE LCMAP_UPPERCASE LCMAP_SORTKEY LCMAP_HALFWIDTH
+		LCMAP_FULLWIDTH LCMAP_HIRAGANA LCMAP_KATAKANA)],
+ LANG	 => [qw(LANG_NEUTRAL LANG_ALBANIAN LANG_ARABIC LANG_BAHASA
+		LANG_BULGARIAN LANG_CATALAN LANG_CHINESE LANG_CZECH LANG_DANISH
+		LANG_DUTCH LANG_ENGLISH LANG_FINNISH LANG_FRENCH LANG_GERMAN
+		LANG_GREEK LANG_HEBREW LANG_HUNGARIAN LANG_ICELANDIC
+		LANG_ITALIAN LANG_JAPANESE LANG_KOREAN LANG_NORWEGIAN
+		LANG_POLISH LANG_PORTUGUESE LANG_RHAETO_ROMAN LANG_ROMANIAN
+		LANG_RUSSIAN LANG_SERBO_CROATIAN LANG_SLOVAK LANG_SPANISH
+		LANG_SWEDISH LANG_THAI LANG_TURKISH LANG_URDU)],
+ SUBLANG => [qw(SUBLANG_NEUTRAL SUBLANG_DEFAULT SUBLANG_SYS_DEFAULT
+		SUBLANG_CHINESE_SIMPLIFIED SUBLANG_CHINESE_TRADITIONAL
+		SUBLANG_DUTCH SUBLANG_DUTCH_BELGIAN SUBLANG_ENGLISH_US
+		SUBLANG_ENGLISH_UK SUBLANG_ENGLISH_AUS SUBLANG_ENGLISH_CAN
+		SUBLANG_ENGLISH_NZ SUBLANG_ENGLISH_EIRE SUBLANG_FRENCH
+		SUBLANG_FRENCH_BELGIAN SUBLANG_FRENCH_CANADIAN
+		SUBLANG_FRENCH_SWISS SUBLANG_GERMAN SUBLANG_GERMAN_SWISS
+		SUBLANG_GERMAN_AUSTRIAN SUBLANG_ITALIAN SUBLANG_ITALIAN_SWISS
+		SUBLANG_NORWEGIAN_BOKMAL SUBLANG_NORWEGIAN_NYNORSK
+		SUBLANG_PORTUGUESE SUBLANG_PORTUGUESE_BRAZILIAN
+		SUBLANG_SERBO_CROATIAN_CYRILLIC SUBLANG_SERBO_CROATIAN_LATIN
+		SUBLANG_SPANISH SUBLANG_SPANISH_MEXICAN
+		SUBLANG_SPANISH_MODERN)],
+ CTRY	 => [qw(CTRY_DEFAULT CTRY_AUSTRALIA CTRY_AUSTRIA CTRY_BELGIUM
+		CTRY_BRAZIL CTRY_CANADA CTRY_DENMARK CTRY_FINLAND CTRY_FRANCE
+		CTRY_GERMANY CTRY_ICELAND CTRY_IRELAND CTRY_ITALY CTRY_JAPAN
+		CTRY_MEXICO CTRY_NETHERLANDS CTRY_NEW_ZEALAND CTRY_NORWAY
+		CTRY_PORTUGAL CTRY_PRCHINA CTRY_SOUTH_KOREA CTRY_SPAIN
+		CTRY_SWEDEN CTRY_SWITZERLAND CTRY_TAIWAN CTRY_UNITED_KINGDOM
+		CTRY_UNITED_STATES)],
+ LOCALE	 => [qw(LOCALE_NOUSEROVERRIDE LOCALE_ILANGUAGE LOCALE_SLANGUAGE
+		LOCALE_SENGLANGUAGE LOCALE_SABBREVLANGNAME
+		LOCALE_SNATIVELANGNAME LOCALE_ICOUNTRY LOCALE_SCOUNTRY
+		LOCALE_SENGCOUNTRY LOCALE_SABBREVCTRYNAME LOCALE_SNATIVECTRYNAME
+		LOCALE_IDEFAULTLANGUAGE LOCALE_IDEFAULTCOUNTRY
+		LOCALE_IDEFAULTCODEPAGE LOCALE_IDEFAULTANSICODEPAGE LOCALE_SLIST
+		LOCALE_IMEASURE LOCALE_SDECIMAL LOCALE_STHOUSAND
+		LOCALE_SGROUPING LOCALE_IDIGITS LOCALE_ILZERO LOCALE_INEGNUMBER
+		LOCALE_SNATIVEDIGITS LOCALE_SCURRENCY LOCALE_SINTLSYMBOL
+		LOCALE_SMONDECIMALSEP LOCALE_SMONTHOUSANDSEP LOCALE_SMONGROUPING
+		LOCALE_ICURRDIGITS LOCALE_IINTLCURRDIGITS LOCALE_ICURRENCY
+		LOCALE_INEGCURR LOCALE_SDATE LOCALE_STIME LOCALE_SSHORTDATE
+		LOCALE_SLONGDATE LOCALE_STIMEFORMAT LOCALE_IDATE LOCALE_ILDATE
+		LOCALE_ITIME LOCALE_ITIMEMARKPOSN LOCALE_ICENTURY LOCALE_ITLZERO
+		LOCALE_IDAYLZERO LOCALE_IMONLZERO LOCALE_S1159 LOCALE_S2359
+		LOCALE_ICALENDARTYPE LOCALE_IOPTIONALCALENDAR
+		LOCALE_IFIRSTDAYOFWEEK LOCALE_IFIRSTWEEKOFYEAR LOCALE_SDAYNAME1
+		LOCALE_SDAYNAME2 LOCALE_SDAYNAME3 LOCALE_SDAYNAME4
+		LOCALE_SDAYNAME5 LOCALE_SDAYNAME6 LOCALE_SDAYNAME7
+		LOCALE_SABBREVDAYNAME1 LOCALE_SABBREVDAYNAME2
+		LOCALE_SABBREVDAYNAME3 LOCALE_SABBREVDAYNAME4
+		LOCALE_SABBREVDAYNAME5 LOCALE_SABBREVDAYNAME6
+		LOCALE_SABBREVDAYNAME7 LOCALE_SMONTHNAME1 LOCALE_SMONTHNAME2
+		LOCALE_SMONTHNAME3 LOCALE_SMONTHNAME4 LOCALE_SMONTHNAME5
+		LOCALE_SMONTHNAME6 LOCALE_SMONTHNAME7 LOCALE_SMONTHNAME8
+		LOCALE_SMONTHNAME9 LOCALE_SMONTHNAME10 LOCALE_SMONTHNAME11
+		LOCALE_SMONTHNAME12 LOCALE_SMONTHNAME13 LOCALE_SABBREVMONTHNAME1
+		LOCALE_SABBREVMONTHNAME2 LOCALE_SABBREVMONTHNAME3
+		LOCALE_SABBREVMONTHNAME4 LOCALE_SABBREVMONTHNAME5
+		LOCALE_SABBREVMONTHNAME6 LOCALE_SABBREVMONTHNAME7
+		LOCALE_SABBREVMONTHNAME8 LOCALE_SABBREVMONTHNAME9
+		LOCALE_SABBREVMONTHNAME10 LOCALE_SABBREVMONTHNAME11
+		LOCALE_SABBREVMONTHNAME12 LOCALE_SABBREVMONTHNAME13
+		LOCALE_SPOSITIVESIGN LOCALE_SNEGATIVESIGN LOCALE_IPOSSIGNPOSN
+		LOCALE_INEGSIGNPOSN LOCALE_IPOSSYMPRECEDES LOCALE_IPOSSEPBYSPACE
+		LOCALE_INEGSYMPRECEDES LOCALE_INEGSEPBYSPACE)],
+ TIME    => [qw(TIME_NOMINUTESORSECONDS TIME_NOSECONDS TIME_NOTIMEMARKER
+                TIME_FORCE24HOURFORMAT)],
+ DATE    => [qw(DATE_SHORTDATE DATE_LONGDATE DATE_USE_ALT_CALENDAR
+                DATE_YEARMONTH DATE_LTRREADING DATE_RTLREADING)],
+);
+
+foreach my $tag (keys %EXPORT_TAGS) {
+    push @EXPORT_OK, @{$EXPORT_TAGS{$tag}};
+}
+
+# Character Type Flags
+sub CT_CTYPE1                       { 0x0001 }
+sub CT_CTYPE2                       { 0x0002 }
+sub CT_CTYPE3                       { 0x0004 }
+
+# Character Type 1 Bits
+sub C1_UPPER                        { 0x0001 }
+sub C1_LOWER                        { 0x0002 }
+sub C1_DIGIT                        { 0x0004 }
+sub C1_SPACE                        { 0x0008 }
+sub C1_PUNCT                        { 0x0010 }
+sub C1_CNTRL                        { 0x0020 }
+sub C1_BLANK                        { 0x0040 }
+sub C1_XDIGIT                       { 0x0080 }
+sub C1_ALPHA                        { 0x0100 }
+
+# Character Type 2 Bits
+sub C2_LEFTTORIGHT                  { 0x1 }
+sub C2_RIGHTTOLEFT                  { 0x2 }
+sub C2_EUROPENUMBER                 { 0x3 }
+sub C2_EUROPESEPARATOR              { 0x4 }
+sub C2_EUROPETERMINATOR             { 0x5 }
+sub C2_ARABICNUMBER                 { 0x6 }
+sub C2_COMMONSEPARATOR              { 0x7 }
+sub C2_BLOCKSEPARATOR               { 0x8 }
+sub C2_SEGMENTSEPARATOR             { 0x9 }
+sub C2_WHITESPACE                   { 0xA }
+sub C2_OTHERNEUTRAL                 { 0xB }
+sub C2_NOTAPPLICABLE                { 0x0 }
+
+# Character Type 3 Bits
+sub C3_NONSPACING                   { 0x0001 }
+sub C3_DIACRITIC                    { 0x0002 }
+sub C3_VOWELMARK                    { 0x0004 }
+sub C3_SYMBOL                       { 0x0008 }
+sub C3_KATAKANA                     { 0x0010 }
+sub C3_HIRAGANA                     { 0x0020 }
+sub C3_HALFWIDTH                    { 0x0040 }
+sub C3_FULLWIDTH                    { 0x0080 }
+sub C3_IDEOGRAPH                    { 0x0100 }
+sub C3_KASHIDA                      { 0x0200 }
+sub C3_ALPHA                        { 0x8000 }
+sub C3_NOTAPPLICABLE                { 0x0 }
+
+# String Flags
+sub NORM_IGNORECASE                 { 0x0001 }
+sub NORM_IGNORENONSPACE             { 0x0002 }
+sub NORM_IGNORESYMBOLS              { 0x0004 }
+sub NORM_IGNOREWIDTH                { 0x0008 }
+sub NORM_IGNOREKANATYPE             { 0x0040 }
+sub NORM_IGNOREKASHIDA              { 0x40000}
+
+# Locale Dependent Mapping Flags
+sub LCMAP_LOWERCASE                 { 0x0100 }
+sub LCMAP_UPPERCASE                 { 0x0200 }
+sub LCMAP_SORTKEY                   { 0x0400 }
+sub LCMAP_HALFWIDTH                 { 0x0800 }
+sub LCMAP_FULLWIDTH                 { 0x1000 }
+sub LCMAP_HIRAGANA                  { 0x2000 }
+sub LCMAP_KATAKANA                  { 0x4000 }
+
+# Primary Language Identifier
+sub LANG_NEUTRAL                    { 0x00 }
+sub LANG_ALBANIAN                   { 0x1c }
+sub LANG_ARABIC                     { 0x01 }
+sub LANG_BAHASA                     { 0x21 }
+sub LANG_BULGARIAN                  { 0x02 }
+sub LANG_CATALAN                    { 0x03 }
+sub LANG_CHINESE                    { 0x04 }
+sub LANG_CZECH                      { 0x05 }
+sub LANG_DANISH                     { 0x06 }
+sub LANG_DUTCH                      { 0x13 }
+sub LANG_ENGLISH                    { 0x09 }
+sub LANG_FINNISH                    { 0x0b }
+sub LANG_FRENCH                     { 0x0c }
+sub LANG_GERMAN                     { 0x07 }
+sub LANG_GREEK                      { 0x08 }
+sub LANG_HEBREW                     { 0x0d }
+sub LANG_HUNGARIAN                  { 0x0e }
+sub LANG_ICELANDIC                  { 0x0f }
+sub LANG_ITALIAN                    { 0x10 }
+sub LANG_JAPANESE                   { 0x11 }
+sub LANG_KOREAN                     { 0x12 }
+sub LANG_NORWEGIAN                  { 0x14 }
+sub LANG_POLISH                     { 0x15 }
+sub LANG_PORTUGUESE                 { 0x16 }
+sub LANG_RHAETO_ROMAN               { 0x17 }
+sub LANG_ROMANIAN                   { 0x18 }
+sub LANG_RUSSIAN                    { 0x19 }
+sub LANG_SERBO_CROATIAN             { 0x1a }
+sub LANG_SLOVAK                     { 0x1b }
+sub LANG_SPANISH                    { 0x0a }
+sub LANG_SWEDISH                    { 0x1d }
+sub LANG_THAI                       { 0x1e }
+sub LANG_TURKISH                    { 0x1f }
+sub LANG_URDU                       { 0x20 }
+
+# Sublanguage Identifier
+sub SUBLANG_NEUTRAL                 { 0x00 }
+sub SUBLANG_DEFAULT                 { 0x01 }
+sub SUBLANG_SYS_DEFAULT             { 0x02 }
+sub SUBLANG_CHINESE_SIMPLIFIED      { 0x02 }
+sub SUBLANG_CHINESE_TRADITIONAL     { 0x01 }
+sub SUBLANG_DUTCH                   { 0x01 }
+sub SUBLANG_DUTCH_BELGIAN           { 0x02 }
+sub SUBLANG_ENGLISH_US              { 0x01 }
+sub SUBLANG_ENGLISH_UK              { 0x02 }
+sub SUBLANG_ENGLISH_AUS             { 0x03 }
+sub SUBLANG_ENGLISH_CAN             { 0x04 }
+sub SUBLANG_ENGLISH_NZ              { 0x05 }
+sub SUBLANG_ENGLISH_EIRE            { 0x06 }
+sub SUBLANG_FRENCH                  { 0x01 }
+sub SUBLANG_FRENCH_BELGIAN          { 0x02 }
+sub SUBLANG_FRENCH_CANADIAN         { 0x03 }
+sub SUBLANG_FRENCH_SWISS            { 0x04 }
+sub SUBLANG_GERMAN                  { 0x01 }
+sub SUBLANG_GERMAN_SWISS            { 0x02 }
+sub SUBLANG_GERMAN_AUSTRIAN         { 0x03 }
+sub SUBLANG_ITALIAN                 { 0x01 }
+sub SUBLANG_ITALIAN_SWISS           { 0x02 }
+sub SUBLANG_NORWEGIAN_BOKMAL        { 0x01 }
+sub SUBLANG_NORWEGIAN_NYNORSK       { 0x02 }
+sub SUBLANG_PORTUGUESE              { 0x02 }
+sub SUBLANG_PORTUGUESE_BRAZILIAN    { 0x01 }
+sub SUBLANG_SERBO_CROATIAN_CYRILLIC { 0x02 }
+sub SUBLANG_SERBO_CROATIAN_LATIN    { 0x01 }
+sub SUBLANG_SPANISH                 { 0x01 }
+sub SUBLANG_SPANISH_MEXICAN         { 0x02 }
+sub SUBLANG_SPANISH_MODERN          { 0x03 }
+
+# Country codes
+sub CTRY_DEFAULT                    { 0   }
+sub CTRY_AUSTRALIA                  { 61  }
+sub CTRY_AUSTRIA                    { 43  }
+sub CTRY_BELGIUM                    { 32  }
+sub CTRY_BRAZIL                     { 55  }
+sub CTRY_CANADA                     { 2   }
+sub CTRY_DENMARK                    { 45  }
+sub CTRY_FINLAND                    { 358 }
+sub CTRY_FRANCE                     { 33  }
+sub CTRY_GERMANY                    { 49  }
+sub CTRY_ICELAND                    { 354 }
+sub CTRY_IRELAND                    { 353 }
+sub CTRY_ITALY                      { 39  }
+sub CTRY_JAPAN                      { 81  }
+sub CTRY_MEXICO                     { 52  }
+sub CTRY_NETHERLANDS                { 31  }
+sub CTRY_NEW_ZEALAND                { 64  }
+sub CTRY_NORWAY                     { 47  }
+sub CTRY_PORTUGAL                   { 351 }
+sub CTRY_PRCHINA                    { 86  }
+sub CTRY_SOUTH_KOREA                { 82  }
+sub CTRY_SPAIN                      { 34  }
+sub CTRY_SWEDEN                     { 46  }
+sub CTRY_SWITZERLAND                { 41  }
+sub CTRY_TAIWAN                     { 886 }
+sub CTRY_UNITED_KINGDOM             { 44  }
+sub CTRY_UNITED_STATES              { 1   }
+
+# Locale Types
+sub LOCALE_NOUSEROVERRIDE           { 0x80000000 }
+sub LOCALE_ILANGUAGE                { 0x0001 }
+sub LOCALE_SLANGUAGE                { 0x0002 }
+sub LOCALE_SENGLANGUAGE             { 0x1001 }
+sub LOCALE_SABBREVLANGNAME          { 0x0003 }
+sub LOCALE_SNATIVELANGNAME          { 0x0004 }
+sub LOCALE_ICOUNTRY                 { 0x0005 }
+sub LOCALE_SCOUNTRY                 { 0x0006 }
+sub LOCALE_SENGCOUNTRY              { 0x1002 }
+sub LOCALE_SABBREVCTRYNAME          { 0x0007 }
+sub LOCALE_SNATIVECTRYNAME          { 0x0008 }
+sub LOCALE_IDEFAULTLANGUAGE         { 0x0009 }
+sub LOCALE_IDEFAULTCOUNTRY          { 0x000A }
+sub LOCALE_IDEFAULTCODEPAGE         { 0x000B }
+sub LOCALE_IDEFAULTANSICODEPAGE     { 0x1004 }
+sub LOCALE_SLIST                    { 0x000C }
+sub LOCALE_IMEASURE                 { 0x000D }
+sub LOCALE_SDECIMAL                 { 0x000E }
+sub LOCALE_STHOUSAND                { 0x000F }
+sub LOCALE_SGROUPING                { 0x0010 }
+sub LOCALE_IDIGITS                  { 0x0011 }
+sub LOCALE_ILZERO                   { 0x0012 }
+sub LOCALE_INEGNUMBER               { 0x1010 }
+sub LOCALE_SNATIVEDIGITS            { 0x0013 }
+sub LOCALE_SCURRENCY                { 0x0014 }
+sub LOCALE_SINTLSYMBOL              { 0x0015 }
+sub LOCALE_SMONDECIMALSEP           { 0x0016 }
+sub LOCALE_SMONTHOUSANDSEP          { 0x0017 }
+sub LOCALE_SMONGROUPING             { 0x0018 }
+sub LOCALE_ICURRDIGITS              { 0x0019 }
+sub LOCALE_IINTLCURRDIGITS          { 0x001A }
+sub LOCALE_ICURRENCY                { 0x001B }
+sub LOCALE_INEGCURR                 { 0x001C }
+sub LOCALE_SDATE                    { 0x001D }
+sub LOCALE_STIME                    { 0x001E }
+sub LOCALE_SSHORTDATE               { 0x001F }
+sub LOCALE_SLONGDATE                { 0x0020 }
+sub LOCALE_STIMEFORMAT              { 0x1003 }
+sub LOCALE_IDATE                    { 0x0021 }
+sub LOCALE_ILDATE                   { 0x0022 }
+sub LOCALE_ITIME                    { 0x0023 }
+sub LOCALE_ITIMEMARKPOSN            { 0x1005 }
+sub LOCALE_ICENTURY                 { 0x0024 }
+sub LOCALE_ITLZERO                  { 0x0025 }
+sub LOCALE_IDAYLZERO                { 0x0026 }
+sub LOCALE_IMONLZERO                { 0x0027 }
+sub LOCALE_S1159                    { 0x0028 }
+sub LOCALE_S2359                    { 0x0029 }
+sub LOCALE_ICALENDARTYPE            { 0x1009 }
+sub LOCALE_IOPTIONALCALENDAR        { 0x100B }
+sub LOCALE_IFIRSTDAYOFWEEK          { 0x100C }
+sub LOCALE_IFIRSTWEEKOFYEAR         { 0x100D }
+sub LOCALE_SDAYNAME1                { 0x002A }
+sub LOCALE_SDAYNAME2                { 0x002B }
+sub LOCALE_SDAYNAME3                { 0x002C }
+sub LOCALE_SDAYNAME4                { 0x002D }
+sub LOCALE_SDAYNAME5                { 0x002E }
+sub LOCALE_SDAYNAME6                { 0x002F }
+sub LOCALE_SDAYNAME7                { 0x0030 }
+sub LOCALE_SABBREVDAYNAME1          { 0x0031 }
+sub LOCALE_SABBREVDAYNAME2          { 0x0032 }
+sub LOCALE_SABBREVDAYNAME3          { 0x0033 }
+sub LOCALE_SABBREVDAYNAME4          { 0x0034 }
+sub LOCALE_SABBREVDAYNAME5          { 0x0035 }
+sub LOCALE_SABBREVDAYNAME6          { 0x0036 }
+sub LOCALE_SABBREVDAYNAME7          { 0x0037 }
+sub LOCALE_SMONTHNAME1              { 0x0038 }
+sub LOCALE_SMONTHNAME2              { 0x0039 }
+sub LOCALE_SMONTHNAME3              { 0x003A }
+sub LOCALE_SMONTHNAME4              { 0x003B }
+sub LOCALE_SMONTHNAME5              { 0x003C }
+sub LOCALE_SMONTHNAME6              { 0x003D }
+sub LOCALE_SMONTHNAME7              { 0x003E }
+sub LOCALE_SMONTHNAME8              { 0x003F }
+sub LOCALE_SMONTHNAME9              { 0x0040 }
+sub LOCALE_SMONTHNAME10             { 0x0041 }
+sub LOCALE_SMONTHNAME11             { 0x0042 }
+sub LOCALE_SMONTHNAME12             { 0x0043 }
+sub LOCALE_SMONTHNAME13             { 0x100E }
+sub LOCALE_SABBREVMONTHNAME1        { 0x0044 }
+sub LOCALE_SABBREVMONTHNAME2        { 0x0045 }
+sub LOCALE_SABBREVMONTHNAME3        { 0x0046 }
+sub LOCALE_SABBREVMONTHNAME4        { 0x0047 }
+sub LOCALE_SABBREVMONTHNAME5        { 0x0048 }
+sub LOCALE_SABBREVMONTHNAME6        { 0x0049 }
+sub LOCALE_SABBREVMONTHNAME7        { 0x004A }
+sub LOCALE_SABBREVMONTHNAME8        { 0x004B }
+sub LOCALE_SABBREVMONTHNAME9        { 0x004C }
+sub LOCALE_SABBREVMONTHNAME10       { 0x004D }
+sub LOCALE_SABBREVMONTHNAME11       { 0x004E }
+sub LOCALE_SABBREVMONTHNAME12       { 0x004F }
+sub LOCALE_SABBREVMONTHNAME13       { 0x100F }
+sub LOCALE_SPOSITIVESIGN            { 0x0050 }
+sub LOCALE_SNEGATIVESIGN            { 0x0051 }
+sub LOCALE_IPOSSIGNPOSN             { 0x0052 }
+sub LOCALE_INEGSIGNPOSN             { 0x0053 }
+sub LOCALE_IPOSSYMPRECEDES          { 0x0054 }
+sub LOCALE_IPOSSEPBYSPACE           { 0x0055 }
+sub LOCALE_INEGSYMPRECEDES          { 0x0056 }
+sub LOCALE_INEGSEPBYSPACE           { 0x0057 }
+
+# GetTimeFormat Flags
+sub TIME_NOMINUTESORSECONDS         { 0x0001 }
+sub TIME_NOSECONDS                  { 0x0002 }
+sub TIME_NOTIMEMARKER               { 0x0004 }
+sub TIME_FORCE24HOURFORMAT          { 0x0008 }
+
+# GetDateFormat Flags
+sub DATE_SHORTDATE		    { 0x0001 }
+sub DATE_LONGDATE                   { 0x0002 }
+sub DATE_USE_ALT_CALENDAR           { 0x0004 }
+sub DATE_YEARMONTH                  { 0x0008 }
+sub DATE_LTRREADING                 { 0x0010 }
+sub DATE_RTLREADING                 { 0x0020 }
+
+# Language Identifier Functions
+sub MAKELANGID	   { my ($p,$s) = @_; (($s & 0xffff) << 10) | ($p & 0xffff); }
+sub PRIMARYLANGID  { my $lgid = shift; $lgid & 0x3ff; }
+sub SUBLANGID	   { my $lgid = shift; ($lgid >> 10) & 0x3f; }
+
+sub LANG_SYSTEM_DEFAULT { MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT); }
+sub LANG_USER_DEFAULT   { MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT); }
+
+# Locale Identifier Functions
+sub MAKELCID	   { my $lgid = shift; $lgid & 0xffff; }
+sub LANGIDFROMLCID { my $lcid = shift; $lcid & 0xffff; }
+
+sub LOCALE_SYSTEM_DEFAULT { MAKELCID(LANG_SYSTEM_DEFAULT); }
+sub LOCALE_USER_DEFAULT   { MAKELCID(LANG_USER_DEFAULT); }
+
+1;
+
+__END__
+
+=head1 NAME
+
+Win32::OLE::NLS - OLE National Language Support
+
+=head1 SYNOPSIS
+
+	missing
+
+=head1 DESCRIPTION
+
+This module provides access to the national language support features
+in the F<OLENLS.DLL>.
+
+=head2 Functions
+
+=over 8
+
+=item CompareString(LCID,FLAGS,STR1,STR2)
+
+Compare STR1 and STR2 in the LCID locale.  FLAGS indicate the character
+traits to be used or ignored when comparing the two strings.
+
+	NORM_IGNORECASE		Ignore case
+	NORM_IGNOREKANATYPE	Ignore hiragana/katakana character differences
+	NORM_IGNORENONSPACE	Ignore accents, diacritics, and vowel marks
+	NORM_IGNORESYMBOLS	Ignore symbols
+	NORM_IGNOREWIDTH	Ignore character width
+
+Possible return values are:
+
+	0	Function failed
+	1	STR1 is less than STR2
+	2	STR1 is equal to STR2
+	3	STR1 is greater than STR2
+
+Note that you can subtract 2 from the return code to get values
+comparable to the C<cmp> operator.
+
+=item LCMapString(LCID,FLAGS,STR)
+
+LCMapString translates STR using LCID dependent translation.
+Flags contains a combination of the following options:
+
+	LCMAP_LOWERCASE		Lowercase
+	LCMAP_UPPERCASE		Uppercase
+	LCMAP_HALFWIDTH		Narrow characters
+	LCMAP_FULLWIDTH		Wide characters
+	LCMAP_HIRAGANA		Hiragana
+	LCMAP_KATAKANA		Katakana
+	LCMAP_SORTKEY		Character sort key
+
+The following normalization options can be combined with C<LCMAP_SORTKEY>:
+
+	NORM_IGNORECASE		Ignore case
+	NORM_IGNOREKANATYPE	Ignore hiragana/katakana character differences
+	NORM_IGNORENONSPACE	Ignore accents, diacritics, and vowel marks
+	NORM_IGNORESYMBOLS	Ignore symbols
+	NORM_IGNOREWIDTH	Ignore character width
+
+The return value is the translated string.
+
+=item GetLocaleInfo(LCID,LCTYPE)
+
+Retrieve locale setting LCTYPE from the locale specified by LCID.  Use
+LOCALE_NOUSEROVERRIDE | LCTYPE to always query the locale database.
+Otherwise user changes to C<win.ini> through the windows control panel
+take precedence when retrieving values for the system default locale.
+See the documentation below for a list of valid LCTYPE values.
+
+The return value is the contents of the requested locale setting.
+
+=item GetStringType(LCID,TYPE,STR)
+
+Retrieve type information from locale LCID about each character in STR.
+The requested TYPE can be one of the following 3 levels:
+
+	CT_CTYPE1		ANSI C and POSIX type information
+	CT_CTYPE2		Text layout type information
+	CT_CTYPE3		Text processing type information
+
+The return value is a list of values, each of wich is a bitwise OR of
+the applicable type bits from the corresponding table below:
+
+	@ct = GetStringType(LOCALE_SYSTEM_DEFAULT, CT_CTYPE1, "String");
+
+ANSI C and POSIX character type information:
+
+	C1_UPPER		Uppercase
+	C1_LOWER		Lowercase
+	C1_DIGIT		Decimal digits
+	C1_SPACE		Space characters
+	C1_PUNCT		Punctuation
+	C1_CNTRL		Control characters
+	C1_BLANK		Blank characters
+	C1_XDIGIT		Hexadecimal digits
+	C1_ALPHA		Any letter
+
+Text layout type information:
+
+	C2_LEFTTORIGHT		Left to right
+	C2_RIGHTTOLEFT		Right to left
+	C2_EUROPENUMBER		European number, European digit
+	C2_EUROPESEPARATOR	European numeric separator
+	C2_EUROPETERMINATOR	European numeric terminator
+	C2_ARABICNUMBER		Arabic number
+	C2_COMMONSEPARATOR	Common numeric separator
+	C2_BLOCKSEPARATOR	Block separator
+	C2_SEGMENTSEPARATOR	Segment separator
+	C2_WHITESPACE		White space
+	C2_OTHERNEUTRAL		Other neutrals
+	C2_NOTAPPLICABLE	No implicit direction (e.g. ctrl codes)
+
+Text precessing type information:
+
+	C3_NONSPACING		Nonspacing mark
+	C3_DIACRITIC		Diacritic nonspacing mark
+	C3_VOWELMARK		Vowel nonspacing mark
+	C3_SYMBOL		Symbol
+	C3_KATAKANA		Katakana character
+	C3_HIRAGANA		Hiragana character
+	C3_HALFWIDTH		Narrow character
+	C3_FULLWIDTH		Wide character
+	C3_IDEOGRAPH		Ideograph
+	C3_ALPHA		Any letter
+	C3_NOTAPPLICABLE	Not applicable
+
+
+=item GetSystemDefaultLangID()
+
+Returns the system default language identifier.
+
+=item GetSystemDefaultLCID()
+
+Returns the system default locale identifier.
+
+=item GetUserDefaultLangID()
+
+Returns the user default language identifier.
+
+=item GetUserDefaultLCID()
+
+Returns the user default locale identifier.
+
+=item SendSettingChange()
+
+Sends a WM_SETTINGCHANGE message to all top level windows.
+
+=item SetLocaleInfo(LCID, LCTYPE, LCDATA)
+
+Changes an item in the user override part of the locale setting LCID.
+It doesn't change the system default database.  The following LCTYPEs are
+changeable:
+
+	LOCALE_ICALENDARTYPE	LOCALE_SDATE
+	LOCALE_ICURRDIGITS	LOCALE_SDECIMAL
+	LOCALE_ICURRENCY	LOCALE_SGROUPING
+	LOCALE_IDIGITS		LOCALE_SLIST
+	LOCALE_IFIRSTDAYOFWEEK	LOCALE_SLONGDATE
+	LOCALE_IFIRSTWEEKOFYEAR	LOCALE_SMONDECIMALSEP
+	LOCALE_ILZERO		LOCALE_SMONGROUPING
+	LOCALE_IMEASURE		LOCALE_SMONTHOUSANDSEP
+	LOCALE_INEGCURR		LOCALE_SNEGATIVESIGN
+	LOCALE_INEGNUMBER	LOCALE_SPOSITIVESIGN
+	LOCALE_IPAPERSIZE	LOCALE_SSHORTDATE
+	LOCALE_ITIME		LOCALE_STHOUSAND
+	LOCALE_S1159		LOCALE_STIME
+	LOCALE_S2359		LOCALE_STIMEFORMAT
+	LOCALE_SCURRENCY	LOCALE_SYEARMONTH
+
+You have to call SendSettingChange() to activate these changes for
+subsequent Win32::OLE::Variant object formatting because the OLE
+subsystem seems to cache locale information.
+
+=item MAKELANGID(LANG,SUBLANG)
+
+Creates a lnguage identifier from a primary language and a sublanguage.
+
+=item PRIMARYLANGID(LANGID)
+
+Retrieves the primary language from a language identifier.
+
+=item SUBLANGID(LANGID)
+
+Retrieves the sublanguage from a language identifier.
+
+=item MAKELCID(LANGID)
+
+Creates a locale identifies from a language identifier.
+
+=item LANGIDFROMLCID(LCID)
+
+Retrieves a language identifier from a locale identifier.
+
+=back
+
+=head2 Locale Types
+
+=over 8
+
+=item LOCALE_ILANGUAGE
+
+The language identifier (in hex).
+
+=item LOCALE_SLANGUAGE
+
+The localized name of the language.
+
+=item LOCALE_SENGLANGUAGE
+
+The ISO Standard 639 English name of the language.
+
+=item LOCALE_SABBREVLANGNAME
+
+The three-letter abbreviated name of the language.  The first two
+letters are from the ISO Standard 639 language name abbreviation.  The
+third letter indicates the sublanguage type.
+
+=item LOCALE_SNATIVELANGNAME
+
+The native name of the language.
+
+=item LOCALE_ICOUNTRY
+
+The country code, which is based on international phone codes.
+
+=item LOCALE_SCOUNTRY
+
+The localized name of the country.
+
+=item LOCALE_SENGCOUNTRY
+
+The English name of the country.
+
+=item LOCALE_SABBREVCTRYNAME
+
+The ISO Standard 3166 abbreviated name of the country.
+
+=item LOCALE_SNATIVECTRYNAME
+
+The native name of the country.
+
+=item LOCALE_IDEFAULTLANGUAGE
+
+Language identifier for the principal language spoken in this
+locale.
+
+=item LOCALE_IDEFAULTCOUNTRY
+
+Country code for the principal country in this locale.
+
+=item LOCALE_IDEFAULTANSICODEPAGE
+
+The ANSI code page associated with this locale.  Format: 4 Unicode
+decimal digits plus a Unicode null terminator.
+
+XXX This should be translated by GetLocaleInfo. XXX
+
+=item LOCALE_IDEFAULTCODEPAGE
+
+The OEM code page associated with the country.
+
+=item LOCALE_SLIST
+
+Characters used to separate list items (often a comma).
+
+=item LOCALE_IMEASURE
+
+Default measurement system:
+
+	0	metric system (S.I.)
+	1	U.S. system
+
+=item LOCALE_SDECIMAL
+
+Characters used for the decimal separator (often a dot).
+
+=item LOCALE_STHOUSAND
+
+Characters used as the separator between groups of digits left of the decimal.
+
+=item LOCALE_SGROUPING
+
+Sizes for each group of digits to the left of the decimal.  An explicit
+size is required for each group.  Sizes are separated by semicolons.  If
+the last value is 0, the preceding value is repeated.  To group
+thousands, specify 3;0.
+
+=item LOCALE_IDIGITS
+
+The number of fractional digits.
+
+=item LOCALE_ILZERO
+
+Whether to use leading zeros in decimal fields.  A setting of 0
+means use no leading zeros; 1 means use leading zeros.
+
+=item LOCALE_SNATIVEDIGITS
+
+The ten characters that are the native equivalent of the ASCII 0-9.
+
+=item LOCALE_INEGNUMBER
+
+Negative number mode.
+
+	0 	(1.1)
+	1 	-1.1
+	2 	-1.1
+	3 	1.1
+	4 	1.1
+
+=item LOCALE_SCURRENCY
+
+The string used as the local monetary symbol.
+
+=item LOCALE_SINTLSYMBOL
+
+Three characters of the International monetary symbol specified in ISO
+4217, Codes for the Representation of Currencies and Funds, followed
+by the character separating this string from the amount.
+
+=item LOCALE_SMONDECIMALSEP
+
+Characters used for the monetary decimal separators.
+
+=item LOCALE_SMONTHOUSANDSEP
+
+Characters used as monetary separator between groups of digits left of
+the decimal.
+
+=item LOCALE_SMONGROUPING
+
+Sizes for each group of monetary digits to the left of the decimal.  An
+explicit size is needed for each group.  Sizes are separated by
+semicolons.  If the last value is 0, the preceding value is
+repeated.  To group thousands, specify 3;0.
+
+=item LOCALE_ICURRDIGITS
+
+Number of fractional digits for the local monetary format.
+
+=item LOCALE_IINTLCURRDIGITS
+
+Number of fractional digits for the international monetary format.
+
+=item LOCALE_ICURRENCY
+
+Positive currency mode.
+
+	0	Prefix, no separation.
+	1	Suffix, no separation.
+	2	Prefix, 1-character separation.
+	3	Suffix, 1-character separation.
+
+=item LOCALE_INEGCURR
+
+Negative currency mode.
+
+	0	($1.1)
+	1	-$1.1
+	2	$-1.1
+	3	$1.1-
+	4	$(1.1$)
+	5	-1.1$
+	6	1.1-$
+	7	1.1$-
+	8	-1.1 $ (space before $)
+	9	-$ 1.1 (space after $)
+	10	1.1 $- (space before $)
+
+=item LOCALE_ICALENDARTYPE
+
+The type of calendar currently in use.
+
+	1	Gregorian (as in U.S.)
+	2	Gregorian (always English strings)
+	3	Era: Year of the Emperor (Japan)
+	4	Era: Year of the Republic of China
+	5	Tangun Era (Korea)
+
+=item LOCALE_IOPTIONALCALENDAR
+
+The additional calendar types available for this LCID.  Can be a
+null-separated list of all valid optional calendars.  Value is
+0 for "None available" or any of the LOCALE_ICALENDARTYPE settings.
+
+XXX null separated list should be translated by GetLocaleInfo XXX
+
+=item LOCALE_SDATE
+
+Characters used for the date separator.
+
+=item LOCALE_STIME
+
+Characters used for the time separator.
+
+=item LOCALE_STIMEFORMAT
+
+Time-formatting string.
+
+=item LOCALE_SSHORTDATE
+
+Short Date_Time formatting strings for this locale.
+
+=item LOCALE_SLONGDATE
+
+Long Date_Time formatting strings for this locale.
+
+=item LOCALE_IDATE
+
+Short Date format-ordering specifier.
+
+	0	Month - Day - Year
+	1	Day - Month - Year
+	2	Year - Month - Day
+
+=item LOCALE_ILDATE
+
+Long Date format ordering specifier.  Value can be any of the valid
+LOCALE_IDATE settings.
+
+=item LOCALE_ITIME
+
+Time format specifier.
+
+	0	AM/PM 12-hour format.
+	1	24-hour format.
+
+=item LOCALE_ITIMEMARKPOSN
+
+Whether the time marker string (AM|PM) precedes or follows the time
+string.
+	0 Suffix (9:15 AM).
+	1 Prefix (AM 9:15).
+
+=item LOCALE_ICENTURY
+
+Whether to use full 4-digit century.
+
+	0	Two digit.
+	1	Full century.
+
+=item LOCALE_ITLZERO
+
+Whether to use leading zeros in time fields.
+
+	0	No leading zeros.
+	1	Leading zeros for hours.
+
+=item LOCALE_IDAYLZERO
+
+Whether to use leading zeros in day fields.  Values as for
+LOCALE_ITLZERO.
+
+=item LOCALE_IMONLZERO
+
+Whether to use leading zeros in month fields.  Values as for
+LOCALE_ITLZERO.
+
+=item LOCALE_S1159
+
+String for the AM designator.
+
+=item LOCALE_S2359
+
+String for the PM designator.
+
+=item LOCALE_IFIRSTWEEKOFYEAR
+
+Specifies which week of the year is considered first.
+
+	0	Week containing 1/1 is the first week of the year.
+	1	First full week following 1/1is the first week of the year.
+	2	First week with at least 4 days is the first week of the year.
+
+=item LOCALE_IFIRSTDAYOFWEEK
+
+Specifies the day considered first in the week.  Value "0" means
+SDAYNAME1 and value "6" means SDAYNAME7.
+
+=item LOCALE_SDAYNAME1 .. LOCALE_SDAYNAME7
+
+Long name for Monday .. Sunday.
+
+=item LOCALE_SABBREVDAYNAME1 .. LOCALE_SABBREVDAYNAME7
+
+Abbreviated name for Monday .. Sunday.
+
+=item LOCALE_SMONTHNAME1 .. LOCALE_SMONTHNAME12
+
+Long name for January .. December.
+
+=item LOCALE_SMONTHNAME13
+
+Native name for 13th month, if it exists.
+
+=item LOCALE_SABBREVMONTHNAME1 .. LOCALE_SABBREVMONTHNAME12
+
+Abbreviated name for January .. December.
+
+=item LOCALE_SABBREVMONTHNAME13
+
+Native abbreviated name for 13th month, if it exists.
+
+=item LOCALE_SPOSITIVESIGN
+
+String value for the positive sign.
+
+=item LOCALE_SNEGATIVESIGN
+
+String value for the negative sign.
+
+=item LOCALE_IPOSSIGNPOSN
+
+Formatting index for positive values.
+
+	0 Parentheses surround the amount and the monetary symbol.
+	1 The sign string precedes the amount and the monetary symbol.
+	2 The sign string precedes the amount and the monetary symbol.
+	3 The sign string precedes the amount and the monetary symbol.
+	4 The sign string precedes the amount and the monetary symbol.
+
+=item LOCALE_INEGSIGNPOSN
+
+Formatting index for negative values.  Values as for LOCALE_IPOSSIGNPOSN.
+
+=item LOCALE_IPOSSYMPRECEDES
+
+If the monetary symbol precedes, 1.  If it succeeds a positive amount, 0.
+
+=item LOCALE_IPOSSEPBYSPACE
+
+If the monetary symbol is separated by a space from a positive amount,
+1.  Otherwise, 0.
+
+=item LOCALE_INEGSYMPRECEDES
+
+If the monetary symbol precedes, 1.  If it succeeds a negative amount, 0.
+
+=item LOCALE_INEGSEPBYSPACE
+
+If the monetary symbol is separated by a space from a negative amount,
+1.  Otherwise, 0.
+
+=back
+
+=head1 AUTHORS/COPYRIGHT
+
+This module is part of the Win32::OLE distribution.
+
+=cut
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/OLE/TPJ.pod
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/OLE/TPJ.pod	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/OLE/TPJ.pod	(revision 14139)
@@ -0,0 +1,799 @@
+=pod
+
+=head1 NAME
+
+The Perl Journal #10 - Win32::OLE by Jan Dubois
+
+=head1 INTRODUCTION
+
+Suppose you're composing a document with Microsoft Word. You want to
+include an Excel spreadsheet. You could save the spreadsheet in some
+image format that Word can understand, and import it into your
+document. But if the spreadsheet changes, your document will be out of
+date.
+
+Microsoft's OLE (Object Linking and Embedding, pronounced "olay") lets
+one program use objects from another. In the above scenario, the
+spreadsheet is the object. As long as Excel makes that spreadsheet
+available as an OLE object, and Word knows to treat it like one, your
+document will always be current.
+
+You can control OLE objects from Perl with the Win32::OLE module, and
+that's what this article is about. First, I'll show you how to "think
+OLE," which mostly involves a lot of jargon. Next, I'll show you the
+mechanics involved in using Win32::OLE. Then we'll go through a Perl
+program that uses OLE to manipulate Microsoft Excel, Microsoft Access,
+and Lotus Notes. Finally, I'll talk about Variants, an internal OLE
+data type.
+
+
+=head1 THE OLE MINDSET
+
+When an application makes an OLE object available for other
+applications to use, that's called OLE I<automation>. The program
+using the object is called the I<controller>, and the application
+providing the object is called the I<server>. OLE automation is guided
+by the OLE Component Object Model (COM) which specifies how those
+objects must behave if they are to be used by other processes and
+machines.
+
+There are two different types of OLE automation servers. I<In-process>
+servers are implemented as dynamic link libraries (DLLs) and run in
+the same process space as the controller. I<Out-of-process> servers
+are more interesting; they are standalone executables that exist as
+separate processes - possibly on a different computer.
+
+The Win32::OLE module lets your Perl program act as an OLE
+controller. It allows Perl to be used in place of other languages like
+Visual Basic or Java to control OLE objects. This makes all OLE
+automation servers immediately available as Perl modules.
+
+Don't confuse ActiveState OLE with Win32::OLE. ActiveState OLE is
+completely different, although future builds of ActiveState Perl (500
+and up) will work with Win32::OLE.
+
+Objects can expose OLE methods, properties, and events to the outside
+world. Methods are functions that the controller can call to make the
+object do something; properties describe the state of the object; and
+events let the controller know about external events affecting the
+object, such as the user clicking on a button. Since events involve
+asynchronous communication with their objects, they require either
+threads or an event loop. They are not yet supported by the Win32::OLE
+module, and for the same reason ActiveX controls (OCXs) are currently
+unsupported as well.
+
+=head1 WORKING WITH WIN32::OLE
+
+The Win32::OLE module doesn't let your Perl program create OLE
+objects. What it does do is let your Perl program act like a remote
+control for other applications-it lets your program be an OLE
+controller. You can take an OLE object from another application
+(Access, Notes, Excel, or anything else that speaks OLE) and invoke
+its methods or manipulate its properties.
+
+=head2 THE FIRST STEP: CREATING AN OLE SERVER OBJECT
+
+First, we need to create a Perl object to represent the OLE
+server. This is a weird idea; what it amounts to is that if we want to
+control OLE objects produced by, say, Excel, we have to create a Perl
+object that represents Excel. So even though our program is an OLE
+controller, it'll contain objects that represent OLE servers.
+
+You can create a new OLE I<server object> with C<< Win32::OLE->new >>.
+This takes a program ID (a human readable string like
+C<'Speech.VoiceText'>) and returns a server object:
+
+  my $server = Win32::OLE->new('Excel.Application', 'Quit');
+
+Some server objects (particularly those for Microsoft Office
+applications) don't automatically terminate when your program no
+longer needs them. They need some kind of Quit method, and that's just
+what our second argument is. It can be either a code reference or a
+method name to be invoked when the object is destroyed. This lets you
+ensure that objects will be properly cleaned up even when the Perl
+program dies abnormally.
+
+To access a server object on a different computer, replace the first
+argument with a reference to a list of the server name and program ID:
+
+  my $server = Win32::OLE->new(['foo.bar.com',
+                                'Excel.Application']);
+
+(To get the requisite permissions, you'll need to configure your
+security settings with F<DCOMCNFG.EXE>.)
+
+You can also directly attach your program to an already running OLE
+server:
+
+  my $server = Win32::OLE->GetActiveObject('Excel.Application');
+
+This fails (returning C<undef>) if no server exists, or if the server
+refuses the connection for some reason. It is also possible to use a
+persistent object moniker (usually a filename) to start the associated
+server and load the object into memory:
+
+  my $doc = Win32::OLE->GetObject("MyDocument.Doc");
+
+=head2 METHOD CALLS
+
+Once you've created one of these server objects, you need to call its
+methods to make the OLE objects sing and dance. OLE methods are
+invoked just like normal Perl object methods:
+
+  $server->Foo(@Arguments);
+
+This is a Perl method call - but it also triggers an OLE method call
+in the object. After your program executes this statement, the
+C<$server> object will execute its Foo() method. The available methods
+are typically documented in the application's I<object model>.
+
+B<Parameters.> By default, all parameters are positional
+(e.g. C<foo($first, $second, $third)>) rather than named (e.g.
+C<< foo(-name => "Yogi", -title => "Coach") >>). The required parameters
+come first, followed by the optional parameters; if you need to
+provide a dummy value for an optional parameter, use undef.
+
+Positional parameters get cumbersome if a method takes a lot of
+them. You can use named arguments instead if you go to a little extra
+trouble - when the last argument is a reference to a hash, the
+key/value pairs of the hash are treated as named parameters:
+
+  $server->Foo($Pos1, $Pos2, {Name1 => $Value1,
+                              Name2 => $Value2});
+
+B<Foreign Languages and Default Methods.> Sometimes OLE servers use
+method and property names that are specific to a non-English
+locale. That means they might have non-ASCII characters, which aren't
+allowed in Perl variable names. In German, you might see C<Öffnen> used
+instead of C<Open>. In these cases, you can use the Invoke() method:
+
+  $server->Invoke('Öffnen', @Arguments);
+
+This is necessary because C<< $Server->Öffnen(@Arguments) >> is a syntax
+error in current versions of Perl.
+
+=head2 PROPERTIES
+
+As I said earlier, objects can expose three things to the outside
+world: methods, properties, and events. We've covered methods, and
+Win32::OLE can't handle events. That leaves properties. But as it
+turns out, properties and events are largely interchangeable. Most
+methods have corresponding properties, and vice versa.
+
+An object's properties can be accessed with a hash reference:
+
+  $server->{Bar} = $value;
+  $value = $server->{Bar};
+
+This example sets and queries the value of the property named
+C<Bar>. You could also have called the object's Bar() method to
+achieve the same effect:
+
+  $value = $server->Bar;
+
+However, you can't write the first line as C<< $server->Bar = $value >>,
+because you can't assign to the return value of a method call. In
+Visual Basic, OLE automation distinguishes between assigning the name
+of an object and assigning its value:
+
+  Set Object = OtherObject
+
+  Let Value = Object
+
+The C<Set> statement shown here makes C<Object> refer to the same object as
+C<OtherObject>. The C<Let> statement copies the value instead. (The value of
+an OLE object is what you get when you call the object's default
+method.
+
+In Perl, saying C<< $server1 = $server2 >> always creates another reference,
+just like the C<Set> in Visual Basic. If you want to assign the value
+instead, use the valof() function:
+
+  my $value = valof $server;
+
+This is equivalent to
+
+  my $value = $server->Invoke('');
+
+=head2 SAMPLE APPLICATION
+
+Let's look at how all of this might be used. In Listing: 1 you'll see
+F<T-Bond.pl>, a program that uses Win32::OLE for an almost-real world
+application.
+
+The developer of this application, Mary Lynch, is a financial futures
+broker. Every afternoon, she connects to the Chicago Board of Trade
+(CBoT) web site at http://www.cbot.com and collects the time and sales
+information for U.S. T-bond futures. She wants her program to create a
+chart that depicts the data in 15-minute intervals, and then she wants
+to record the data in a database for later analysis. Then she wants
+her program to send mail to her clients.
+
+Mary's program will use Microsoft Access as a database, Microsoft
+Excel to produce the chart, and Lotus Notes to send the mail. It will
+all be controlled from a single Perl program using OLE automation. In
+this section, we'll go through T-Bond. pl step by step so you can see
+how Win32::OLE lets you control these applications.
+
+=head2 DOWNLOADING A WEB PAGE WITH LWP
+
+However, Mary first needs to amass the raw T-bond data by having her
+Perl program automatically download and parse a web page. That's the
+perfect job for LWP, the libwww-perl bundle available on the CPAN. LWP
+has nothing to do with OLE. But this is a real-world application, and
+it's just what Mary needs to download her data from the Chicago Board
+of Trade.
+
+  use LWP::Simple;
+  my $URL = 'http://www.cbot.com/mplex/quotes/tsfut';
+  my $text = get("$URL/tsf$Contract.htm");
+
+She could also have used the Win32::Internet module:
+
+  use Win32::Internet;
+  my $URL = 'http://www.cbot.com/mplex/quotes/tsfut';
+  my $text = $Win32::Internet->new->FetchURL("$URL/tsf$Contract.htm");
+
+Mary wants to condense the ticker data into 15 minute bars. She's
+interested only in lines that look like this:
+
+  03/12/1998 US 98Mar 12116 15:28:34 Open
+
+A regular expression can be used to determine whether a line looks
+like this. If it does, the regex can split it up into individual
+fields. The price quoted above, C<12116>, really means 121 16/32, and
+needs to be converted to 121.5. The data is then condensed into 15
+minute intervals and only the first, last, highest, and lowest price
+during each interval are kept. The time series is stored in the array
+C<@Bars>. Each entry in C<@Bars> is a reference to a list of 5 elements:
+Time, Open, High, Low, and Close.
+
+  foreach (split "\n", $text) {
+      # 03/12/1998 US 98Mar 12116 15:28:34 Open
+      my ($Date,$Price,$Hour,$Min,$Sec,$Ind) =
+           m|^\s*(\d+/\d+/\d+) # " 03/12/1998"
+              \s+US\s+\S+\s+(\d+) # " US 98Mar 12116"
+              \s+(\d+):(\d+):(\d+) # " 12:42:40"
+              \s*(.*)$|x; # " Ask"
+      next unless defined $Date;
+      $Day = $Date;
+
+      # Convert from fractional to decimal format
+      $Price = int($Price/100) + ($Price%100)/32;
+
+      # Round up time to next multiple of 15 minutes
+      my $NewTime = int(($Sec+$Min*60+$Hour*3600)/900+1)*900;
+      unless (defined $Time && $NewTime == $Time) {
+          push @Bars, [$hhmm, $Open, $High, $Low, $Close]
+                                            if defined $Time;
+          $Open = $High = $Low = $Close = undef;
+          $Time = $NewTime;
+          my $Hour = int($Time/3600);
+          $hhmm = sprintf "%02d:%02d", $Hour, $Time/60-$Hour*60;
+      }
+
+      # Update 15 minute bar values
+      $Close = $Price;
+      $Open = $Price unless defined $Open;
+      $High = $Price unless defined $High && $High > $Price;
+      $Low = $Price unless defined $Low && $Low > $Price;
+  }
+
+  die "No data found" unless defined $Time;
+  push @Bars, [$hhmm, $Open, $High, $Low, $Close];
+
+=head2 MICROSOFT ACCESS
+
+Now that Mary has her T-bond quotes, she's ready to use Win32::OLE to
+store them into a Microsoft Access database. This has the advantage
+that she can copy the database to her lap-top and work with it on her
+long New York commute. She's able to create an Access database as
+follows:
+
+  use Win32::ODBC;
+  use Win32::OLE;
+
+  # Include the constants for the Microsoft Access
+  # "Data Access Object".
+
+  use Win32::OLE::Const 'Microsoft DAO';
+
+  my $DSN      = 'T-Bonds';
+  my $Driver   = 'Microsoft Access Driver (*.mdb)';
+  my $Desc     = 'US T-Bond Quotes';
+  my $Dir      = 'i:\tmp\tpj';
+  my $File     = 'T-Bonds.mdb';
+  my $Fullname = "$Dir\\$File";
+
+  # Remove old database and dataset name
+  unlink $Fullname if -f $Fullname;
+  Win32::ODBC::ConfigDSN(ODBC_REMOVE_DSN, $Driver, "DSN=$DSN")
+                         if Win32::ODBC::DataSources($DSN);
+
+  # Create new database
+  my $Access = Win32::OLE->new('Access.Application', 'Quit');
+  my $Workspace = $Access->DBEngine->CreateWorkspace('', 'Admin', '');
+  my $Database = $Workspace->CreateDatabase($Fullname, dbLangGeneral);
+
+  # Add new database name
+  Win32::ODBC::ConfigDSN(ODBC_ADD_DSN, $Driver,
+          "DSN=$DSN", "Description=$Desc", "DBQ=$Fullname",
+          "DEFAULTDIR=$Dir", "UID=", "PWD=");
+
+This uses Win32::ODBC (described in TPJ #9) to remove and create
+F<T-Bonds.mdb>. This lets Mary use the same script on her workstation
+and on her laptop even when the database is stored in different
+locations on each. The program also uses Win32::OLE to make Microsoft
+Access create an empty database.
+
+Every OLE server has some constants that your Perl program will need
+to use, made accessible by the Win32::OLE::Const module. For instance,
+to grab the Excel constants, say C<use Win32::OLE::Const 'Microsoft
+Excel'>.
+
+In the above example, we imported the Data Access Object con-stants
+just so we could use C<dbLangGeneral>.
+
+=head2 MICROSOFT EXCEL
+
+Now Mary uses Win32::OLE a second time, to have Microsoft Excel create
+the chart shown below.
+
+  Figure 1: T-Bond data generated by MicroSoft Excel via Win32::OLE
+
+  # Start Excel and create new workbook with a single sheet
+  use Win32::OLE qw(in valof with);
+  use Win32::OLE::Const 'Microsoft Excel';
+  use Win32::OLE::NLS qw(:DEFAULT :LANG :SUBLANG);
+
+  my $lgid = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
+  $Win32::OLE::LCID = MAKELCID($lgid);
+
+  $Win32::OLE::Warn = 3;
+
+Here, Mary sets the locale to American English, which lets her do
+things like use American date formats (e.g. C<"12-30-98"> rather than
+C<"30-12-98">) in her program. It will continue to work even when she's
+visiting one of her international customers and has to run this
+program on their computers.
+
+The value of C<$Win32::OLE::Warn> determines what happens when an OLE
+error occurs. If it's 0, the error is ignored. If it's 2, or if it's 1
+and the script is running under C<-w>, the Win32::OLE module invokes
+C<Carp::carp()>. If C<$Win32::OLE::Warn> is set to 3, C<Carp::croak()>
+is invoked and the program dies immediately.
+
+Now the data can be put into an Excel spreadsheet to produce the
+chart. The following section of the program launches Excel and creates
+a new workbook with a single worksheet. It puts the column titles
+('Time', 'Open', 'High', 'Low', and 'Close') in a bold font on the
+first row of the sheet. The first column displays the timestamp in
+I<hh:mm> format; the next four display prices.
+
+  my $Excel = Win32::OLE->new('Excel.Application', 'Quit');
+  $Excel->{SheetsInNewWorkbook} = 1;
+  my $Book = $Excel->Workbooks->Add;
+  my $Sheet = $Book->Worksheets(1);
+  $Sheet->{Name} = 'Candle';
+
+  # Insert column titles
+  my $Range = $Sheet->Range("A1:E1");
+  $Range->{Value} = [qw(Time Open High Low Close)];
+  $Range->Font->{Bold} = 1;
+
+  $Sheet->Columns("A:A")->{NumberFormat} = "h:mm";
+  # Open/High/Low/Close to be displayed in 32nds
+  $Sheet->Columns("B:E")->{NumberFormat} = "# ?/32";
+
+  # Add 15 minute data to spreadsheet
+  print "Add data\n";
+  $Range = $Sheet->Range(sprintf "A2:E%d", 2+$#Bars);
+  $Range->{Value} = \@Bars;
+
+The last statement shows how to pass arrays to OLE objects. The
+Win32::OLE module automatically translates each array reference to a
+C<SAFEARRAY>, the internal OLE array data type. This translation first
+determines the maximum nesting level used by the Perl array, and then
+creates a C<SAFEARRAY> of the same dimension. The C<@Bars> array
+already contains the data in the correct form for the spreadsheet:
+
+  ([Time1, Open1, High1, Low1, Close1],
+  ...
+  [TimeN, OpenN, HighN, LowN, CloseN])
+
+Now the table in the spreadsheet can be used to create a candle stick
+chart from our bars. Excel automatically chooses the time axis labels
+if they are selected before the chart is created:
+
+  # Create candle stick chart as new object on worksheet
+  $Sheet->Range("A:E")->Select;
+
+  my $Chart = $Book->Charts->Add;
+  $Chart->{ChartType} = xlStockOHLC;
+  $Chart->Location(xlLocationAsObject, $Sheet->{Name});
+  # Excel bug: the old $Chart is now invalid!
+  $Chart = $Excel->ActiveChart;
+
+We can change the type of the chart from a separate sheet to a chart
+object on the spreadsheet page with the C<< $Chart->Location >>
+method. (This invalidates the chart object handle, which might be
+considered a bug in Excel.) Fortunately, this new chart is still the
+'active' chart, so an object handle to it can be reclaimed simply by
+asking Excel.
+
+At this point, our chart still needs a title, the legend is
+meaningless, and the axis has decimals instead of fractions. We can
+fix those with the following code:
+
+  # Add title, remove legend
+  with($Chart, HasLegend => 0, HasTitle => 1);
+  $Chart->ChartTitle->Characters->{Text} = "US T-Bond";
+
+  # Set up daily statistics
+  $Open  = $Bars[0][1];
+  $High  = $Sheet->Evaluate("MAX(C:C)");
+  $Low   = $Sheet->Evaluate("MIN(D:D)");
+  $Close = $Bars[$#Bars][4];
+
+The with() function partially mimics the Visual Basic With statement,
+but allows only property assignments. It's a convenient shortcut for
+this:
+
+  { # open new scope
+    my $Axis = $Chart->Axes(xlValue);
+    $Axis->{HasMajorGridlines} = 1;
+    $Axis->{HasMinorGridlines} = 1;
+    # etc ...
+  }
+
+The C<$High> and C<$Low> for the day are needed to determine the
+minimum and maximum scaling levels. MIN and MAX are spreadsheet
+functions, and aren't automatically available as methods. However,
+Excel provides an Evaluate() method to calculate arbitrary spreadsheet
+functions, so we can use that.
+
+We want the chart to show major gridlines at every fourth tick and
+minor gridlines at every second tick. The minimum and maximum are
+chosen to be whatever multiples of 1/16 we need to do that.
+
+  # Change tickmark spacing from decimal to fractional
+  with($Chart->Axes(xlValue),
+      HasMajorGridlines => 1,
+      HasMinorGridlines => 1,
+      MajorUnit => 1/8,
+      MinorUnit => 1/16,
+      MinimumScale => int($Low*16)/16,
+      MaximumScale => int($High*16+1)/16
+  );
+
+  # Fat candles with only 5% gaps
+  $Chart->ChartGroups(1)->{GapWidth} = 5;
+
+  sub RGB { $_[0] | ($_[1] >> 8) | ($_[2] >> 16) }
+
+  # White background with a solid border
+
+  $Chart->PlotArea->Border->{LineStyle} = xlContinuous;
+  $Chart->PlotArea->Border->{Color} = RGB(0,0,0);
+  $Chart->PlotArea->Interior->{Color} = RGB(255,255,255);
+
+  # Add 1 hour moving average of the Close series
+  my $MovAvg = $Chart->SeriesCollection(4)->Trendlines
+        ->Add({Type => xlMovingAvg, Period => 4});
+  $MovAvg->Border->{Color} = RGB(255,0,0);
+
+Now the finished workbook can be saved to disk as
+F<i:\tmp\tpj\data.xls>. That file most likely still exists from when the
+program ran yesterday, so we'll remove it. (Otherwise, Excel would pop
+up a dialog with a warning, because the SaveAs() method doesn't like
+to overwrite files.)
+
+
+  # Save workbook to file my $Filename = 'i:\tmp\tpj\data.xls';
+  unlink $Filename if -f $Filename;
+  $Book->SaveAs($Filename);
+  $Book->Close;
+
+=head2 ACTIVEX DATA OBJECTS
+
+Mary stores the daily prices in her T-bonds database, keeping the data
+for the different contracts in separate tables. After creating an ADO
+(ActiveX Data Object) connection to the database, she tries to connect
+a record set to the table for the current contract. If this fails, she
+assumes that the table doesn't exists yet and tries to create it:
+
+  use Win32::OLE::Const 'Microsoft ActiveX Data Objects';
+
+  my $Connection = Win32::OLE->new('ADODB.Connection');
+  my $Recordset = Win32::OLE->new('ADODB.Recordset');
+  $Connection->Open('T-Bonds');
+
+  # Open a record set for the table of this contract
+  {
+    local $Win32::OLE::Warn = 0;
+    $Recordset->Open($Contract, $Connection, adOpenKeyset,
+                         adLockOptimistic, adCmdTable);
+  }
+
+  # Create table and index if it doesn't exist yet
+  if (Win32::OLE->LastError) {
+      $Connection->Execute(>>"SQL");
+        CREATE TABLE $Contract
+        (
+          Day DATETIME,
+          Open DOUBLE, High DOUBLE, Low DOUBLE, Close DOUBLE
+        )
+  SQL
+      $Connection->Execute(>>"SQL");
+        CREATE INDEX $Contract
+        ON $Contract (Day) WITH PRIMARY
+  SQL
+      $Recordset->Open($Contract, $Connection, adOpenKeyset,
+                                adLockOptimistic, adCmdTable);
+  }
+
+C<$Win32::OLE::Warn> is temporarily set to zero, so that if
+C<$Recordset->Open> fails, the failure will be recorded silently without
+terminating the program. C<Win32::OLE->LastError> shows whether the Open
+failed or not. C<LastError> returns the OLE error code in a numeric
+context and the OLE error message in a string context, just like
+Perl's C<$!> variable.
+
+Now Mary can add today's data:
+
+  # Add new record to table
+  use Win32::OLE::Variant;
+  $Win32::OLE::Variant::LCID = $Win32::OLE::LCID;
+
+  my $Fields = [qw(Day Open High Low Close)];
+  my $Values = [Variant(VT_DATE, $Day),
+                $Open, $High, $Low, $Close];
+
+Mary uses the Win32::OLE::Variant module to store C<$Day> as a date
+instead of a mere string. She wants to make sure that it's stored as
+an American-style date, so in the third line shown here she sets the
+locale ID of the Win32::OLE::Variant module to match the Win32::OLE
+module. (C<$Win32::OLE::LCID> had been set earlier to English, since
+that's what the Chicago Board of Trade uses.)
+
+  {
+      local $Win32::OLE::Warn = 0;
+      $Recordset->AddNew($Fields, $Values);
+  }
+
+  # Replace existing record
+  if (Win32::OLE->LastError) {
+      $Recordset->CancelUpdate;
+      $Recordset->Close;
+      $Recordset->Open(>>"SQL",
+                       $Connection, adOpenDynamic);
+          SELECT * FROM $Contract
+          WHERE Day = #$Day#
+  SQL
+      $Recordset->Update($Fields, $Values);
+  }
+
+  $Recordset->Close;
+  $Connection->Close;
+
+The program expects to be able to add a new record to the table. It
+fails if a record for this date already exists, because the Day field
+is the primary index and therefore must be unique. If an error occurs,
+the update operation started by AddNew() must first be cancelled with
+C<< $Recordset->CancelUpdate >>; otherwise the record set won't close.
+
+=head2 LOTUS NOTES
+
+Now Mary can use Lotus Notes to mail updates to all her customers
+interested in the T-bond data. (Lotus Notes doesn't provide its
+constants in the OLE type library, so Mary had to determine them by
+playing around with LotusScript.) The actual task is quite simple: A
+Notes session must be started, the mail database must be opened and
+the mail message must be created. The body of the message is created
+as a rich text field, which lets her mix formatted text with object
+attachments.
+
+In her program, Mary extracts the email addresses from her customer
+database and sends separate message to each. Here, we've simplified it
+somewhat.
+
+  sub EMBED_ATTACHMENT {1454;}     # from LotusScript
+
+  my $Notes = Win32::OLE->new('Notes.NotesSession');
+  my $Database = $Notes->GetDatabase('', '');
+  $Database->OpenMail;
+  my $Document = $Database->CreateDocument;
+
+  $Document->{Form} = 'Memo';
+  $Document->{SendTo} = ['Jon Orwant >orwant@tpj.com>',
+                         'Jan Dubois >jan.dubois@ibm.net>'];
+  $Document->{Subject} = "US T-Bonds Chart for $Day";
+
+  my $Body = $Document->CreateRichtextItem('Body');
+  $Body->AppendText(>>"EOT");
+  I\'ve attached the latest US T-Bond data and chart for $Day.
+  The daily statistics were:
+
+  \tOpen\t$Open
+  \tHigh\t$High
+  \tLow\t$Low
+  \tClose\t$Close
+
+  Kind regards,
+
+  Mary
+  EOT
+
+  $Body->EmbedObject(EMBED_ATTACHMENT, '', $Filename);
+
+  $Document->Send(0);
+
+=head1 VARIANTS
+
+In this final section, I'll talk about Variants, which are the data
+types that you use to talk to OLE objects. We talked about this line
+earlier:
+
+  my $Values = [Variant(VT_DATE, $Day),
+                $Open, $High, $Low, $Close];
+
+Here, the Variant() function creates a Variant object, of type C<VT_DATE>
+and with the value C<$Day>. Variants are similar in many ways to Perl
+scalars. Arguments to OLE methods are transparently converted from
+their internal Perl representation to Variants and back again by the
+Win32::OLE module.
+
+OLE automation uses a generic C<VARIANT> data type to pass
+parameters. This data type contains type information in addition to
+the actual data value. Only the following data types are valid for OLE
+automation:
+
+  B<Data Type     Meaning>
+  VT_EMPTY      Not specified
+  VT_NULL       Null
+  VT_I2         2 byte signed integer
+  VT_I4         4 byte signed integer
+  VT_R4         4 byte real
+  VT_R8         8 byte real
+  VT_CY         Currency
+  VT_DATE       Date
+  VT_BSTR       Unicode string
+  VT_DISPATCH   OLE automation interface
+  VT_ERROR      Error
+  VT_BOOL       Boolean
+  VT_VARIANT    (only valid with VT_BYREF)
+  VT_UNKNOWN    Generic COM interface
+  VT_UI1        Unsigned character
+
+The following two flags can also be used:
+
+  VT_ARRAY      Array of values
+  VT_BYREF      Pass by reference (instead of by value)
+
+B<The Perl to Variant transformation.> The following conversions are
+performed automatically whenever a Perl value must be translated into
+a Variant:
+
+  Perl value                  Variant
+  Integer values              VT_I4
+  Real values                 VT_R8
+  Strings                     VT_BSTR
+  undef                       VT_ERROR (DISP_E_PARAMNOTFOUND)
+  Array reference             VT_VARIANT | VT_ARRAY
+  Win32::OLE object           VT_DISPATCH
+  Win32::OLE::Variant object  Type of the Variant object
+
+What if your Perl value is a list of lists? Those can be irregularly
+shaped in Perl; that is, the subsidiary lists needn't have the same
+number of elements. In this case, the structure will be converted to a
+"rectangular" C<SAFEARRAY> of Variants, with unused slots set to
+C<VT_EMPTY>. Consider this Perl 2-D array:
+
+  [ ["Perl" ],            # one element
+    [1, 3.1215, undef]    # three elements
+  ]
+
+This will be translated to a 2 by 3 C<SAFEARRAY> that looks like this:
+
+  VT_BSTR("Perl") VT_EMPTY      VT_EMPTY
+  VT_I4(1) VT_R8(3.1415)        VT_ERROR(DISP_E_PARAMNOTFOUND)
+
+B<The Variant To Perl Transformation.> Automatic conversion from Variants
+to Perl values happens as follows:
+
+  Variant                Perl value
+  VT_BOOL, VT_ERROR      Integer
+  VT_UI1, VT_I2, VT_I4   Integer
+  VT_R4, VT_R8           Float value
+  VT_BSTR                String
+  VT_DISPATCH            Win32::OLE object
+
+B<The Win32::OLE::Variant module.> This module provides access to the
+Variant data type, which gives you more control over how these
+arguments to OLE methods are encoded. (This is rarely necessary if you
+have a good grasp of the default conversion rules.) A Variant object
+can be created with the C<< Win32::OLE::Variant->new >> method or the
+equivalent Variant() function:
+
+  use Win32::OLE::Variant;
+  my $var1 = Win32::OLE::Variant->new(VT_DATE, 'Jan 1,1970');
+  my $var2 = Variant(VT_BSTR, 'This is an Unicode string');
+
+Several methods let you inspect and manipulate Variant objects: The
+Type() and Value() methods return the variant type and value; the As()
+method returns the value after converting it to a different variant
+type; ChangeType() coerces the Variant into a different type; and
+Unicode() returns the value of a Variant object as an object of the
+Unicode::String class.
+
+These conversions are more interesting if they can be applied directly
+to the return value of an OLE method call without first mutilating the
+value with default conversions. This is possible with the following
+trick:
+
+  my $RetVal = Variant(VT_EMPTY, undef);
+  $Object->Dispatch($Method, $RetVal, @Arguments);
+
+Normally, you wouldn't call Dispatch() directly; it's executed
+implicitly by either AUTOLOAD() or Invoke(). If Dispatch() realizes
+that the return value is already a Win32::OLE::Variant object, the
+return value is not translated into a Perl representation but rather
+copied verbatim into the Variant object.
+
+Whenever a Win32::OLE::Variant object is used in a numeric or string
+context it is automatically converted into the corresponding format.
+
+  printf "Number: %f and String: %s\n",
+         $Var, $Var;
+
+This is equivalent to:
+
+  printf "Number: %f and String: %s\n",
+         $Var->As(VT_R8), $Var->As(VT_BSTR);
+
+For methods that modify their arguments, you need to use the C<VT_BYREF>
+flag. This lets you create number and string Variants that can be
+modified by OLE methods. Here, Corel's GetSize() method takes two
+integers and stores the C<x> and C<y> dimensions in them:
+
+  my $x = Variant( VT_I4 | VT_BYREF, 0);
+  my $y = Variant( VT_I4 | VT_BYREF, 0);
+  $Corel->GetSize($x, $y);
+
+C<VT_BYREF> support for other Variant types might appear in future
+releases of Win32::OLE.
+
+=head1 FURTHER INFORMATION
+
+=head2 DOCUMENTATION AND EXAMPLE CODE
+
+More information about the OLE modules can be found in the
+documentation bundled with Win32::OLE. The distribution also contains
+other code samples.
+
+The object model for Microsoft Office applications can be found in the
+Visual Basic Reference for Microsoft Access, Excel, Word, or
+PowerPoint. These help files are not installed by default, but they
+can be added later by rerunning F<setup.exe> and choosing I<custom
+setup>. The object model for Microsoft Outlook can be found on the
+Microsoft Office Developer Forum at:
+http://www.microsoft.com/OutlookDev/.
+
+Information about the LotusScript object model can be found at:
+http://www.lotus.com/products/lotusscript.nsf.
+
+=head2 OLE AUTOMATION ON OTHER PLATFORMS
+
+Microsoft also makes OLE technology available for the Mac. DCOM is
+already included in Windows NT 4.0 and can be downloaded for Windows
+95. MVS and some Unix systems can use EntireX to get OLE
+functionality; see
+http://www.softwareag.com/corporat/solutions/entirex/entirex.htm.
+
+=head1 COPYRIGHT
+
+Copyright 1998 I<The Perl Journal>. http://www.tpj.com
+
+This article originally appeared in I<The Perl Journal> #10.  It
+appears courtesy of Jon Orwant and I<The Perl Journal>.  This document
+may be distributed under the same terms as Perl itself.
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/OLE/TypeInfo.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/OLE/TypeInfo.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/OLE/TypeInfo.pm	(revision 14139)
@@ -0,0 +1,389 @@
+# This module is still experimental and intentionally undocumented.
+# If you don't know why it is here, then you should probably not use it.
+
+package Win32::OLE::TypeInfo;
+
+use strict;
+use vars qw(@ISA @EXPORT @EXPORT_OK);
+use vars qw(@VT %TYPEFLAGS @TYPEKIND %IMPLTYPEFLAGS %PARAMFLAGS
+            %FUNCFLAGS @CALLCONV @FUNCKIND %INVOKEKIND %VARFLAGS
+	    %LIBFLAGS @SYSKIND);
+
+use Exporter;
+@ISA = qw(Exporter);
+
+@EXPORT = qw(
+  VT_EMPTY VT_NULL VT_I2 VT_I4 VT_R4 VT_R8 VT_CY VT_DATE
+  VT_BSTR VT_DISPATCH VT_ERROR VT_BOOL VT_VARIANT VT_UNKNOWN
+  VT_DECIMAL VT_I1 VT_UI1 VT_UI2 VT_UI4 VT_I8 VT_UI8 VT_INT
+  VT_UINT VT_VOID VT_HRESULT VT_PTR VT_SAFEARRAY VT_CARRAY
+  VT_USERDEFINED VT_LPSTR VT_LPWSTR VT_FILETIME VT_BLOB
+  VT_STREAM VT_STORAGE VT_STREAMED_OBJECT VT_STORED_OBJECT
+  VT_BLOB_OBJECT VT_CF VT_CLSID VT_VECTOR VT_ARRAY VT_BYREF
+  VT_RESERVED VT_ILLEGAL VT_ILLEGALMASKED VT_TYPEMASK
+
+  TYPEFLAG_FAPPOBJECT TYPEFLAG_FCANCREATE TYPEFLAG_FLICENSED
+  TYPEFLAG_FPREDECLID TYPEFLAG_FHIDDEN TYPEFLAG_FCONTROL
+  TYPEFLAG_FDUAL TYPEFLAG_FNONEXTENSIBLE TYPEFLAG_FOLEAUTOMATION
+  TYPEFLAG_FRESTRICTED TYPEFLAG_FAGGREGATABLE TYPEFLAG_FREPLACEABLE
+  TYPEFLAG_FDISPATCHABLE TYPEFLAG_FREVERSEBIND
+
+  TKIND_ENUM TKIND_RECORD TKIND_MODULE TKIND_INTERFACE TKIND_DISPATCH
+  TKIND_COCLASS TKIND_ALIAS TKIND_UNION TKIND_MAX
+
+  IMPLTYPEFLAG_FDEFAULT IMPLTYPEFLAG_FSOURCE IMPLTYPEFLAG_FRESTRICTED
+  IMPLTYPEFLAG_FDEFAULTVTABLE
+
+  PARAMFLAG_NONE PARAMFLAG_FIN PARAMFLAG_FOUT PARAMFLAG_FLCID
+  PARAMFLAG_FRETVAL PARAMFLAG_FOPT PARAMFLAG_FHASDEFAULT
+
+  FUNCFLAG_FRESTRICTED FUNCFLAG_FSOURCE FUNCFLAG_FBINDABLE
+  FUNCFLAG_FREQUESTEDIT FUNCFLAG_FDISPLAYBIND FUNCFLAG_FDEFAULTBIND
+  FUNCFLAG_FHIDDEN FUNCFLAG_FUSESGETLASTERROR FUNCFLAG_FDEFAULTCOLLELEM
+  FUNCFLAG_FUIDEFAULT FUNCFLAG_FNONBROWSABLE FUNCFLAG_FREPLACEABLE
+  FUNCFLAG_FIMMEDIATEBIND
+
+  CC_FASTCALL CC_CDECL CC_MSCPASCAL CC_PASCAL CC_MACPASCAL CC_STDCALL
+  CC_FPFASTCALL CC_SYSCALL CC_MPWCDECL CC_MPWPASCAL CC_MAX
+
+  INVOKE_FUNC INVOKE_PROPERTYGET INVOKE_PROPERTYPUT INVOKE_PROPERTYPUTREF
+
+  VARFLAG_FREADONLY VARFLAG_FSOURCE VARFLAG_FBINDABLE VARFLAG_FREQUESTEDIT
+  VARFLAG_FDISPLAYBIND VARFLAG_FDEFAULTBIND VARFLAG_FHIDDEN VARFLAG_FRESTRICTED
+  VARFLAG_FDEFAULTCOLLELEM VARFLAG_FUIDEFAULT VARFLAG_FNONBROWSABLE
+  VARFLAG_FREPLACEABLE VARFLAG_FIMMEDIATEBIND
+
+  LIBFLAG_FRESTRICTED LIBFLAG_FCONTROL LIBFLAG_FHIDDEN
+  SYS_WIN16 SYS_WIN32 SYS_MAC
+
+  FUNC_VIRTUAL FUNC_PUREVIRTUAL FUNC_NONVIRTUAL FUNC_STATIC FUNC_DISPATCH
+
+  @VT %TYPEFLAGS @TYPEKIND %IMPLTYPEFLAGS %PARAMFLAGS
+  %FUNCFLAGS @CALLCONV @FUNCKIND %INVOKEKIND %VARFLAGS %LIBFLAGS @SYSKIND
+);
+
+# Lib Flags
+# ---------
+
+sub LIBFLAG_FRESTRICTED () { 0x01; }
+sub LIBFLAG_FCONTROL    () { 0x02; }
+sub LIBFLAG_FHIDDEN     () { 0x04; }
+
+$LIBFLAGS{LIBFLAG_FRESTRICTED()} = LIBFLAG_FRESTRICTED;
+$LIBFLAGS{LIBFLAG_FCONTROL()}    = LIBFLAG_FCONTROL;
+$LIBFLAGS{LIBFLAG_FHIDDEN()}     = LIBFLAG_FHIDDEN;
+
+# Sys Kind
+# --------
+
+sub SYS_WIN16 () { 0; }
+sub SYS_WIN32 () { SYS_WIN16() + 1; }
+sub SYS_MAC   () { SYS_WIN32() + 1; }
+
+$SYSKIND[SYS_WIN16] = 'SYS_WIN16';
+$SYSKIND[SYS_WIN32] = 'SYS_WIN32';
+$SYSKIND[SYS_MAC]   = 'SYS_MAC';
+
+# Type Flags
+# ----------
+
+sub TYPEFLAG_FAPPOBJECT     () { 0x1; }
+sub TYPEFLAG_FCANCREATE     () { 0x2; }
+sub TYPEFLAG_FLICENSED      () { 0x4; }
+sub TYPEFLAG_FPREDECLID     () { 0x8; }
+sub TYPEFLAG_FHIDDEN        () { 0x10; }
+sub TYPEFLAG_FCONTROL       () { 0x20; }
+sub TYPEFLAG_FDUAL          () { 0x40; }
+sub TYPEFLAG_FNONEXTENSIBLE () { 0x80; }
+sub TYPEFLAG_FOLEAUTOMATION () { 0x100; }
+sub TYPEFLAG_FRESTRICTED    () { 0x200; }
+sub TYPEFLAG_FAGGREGATABLE  () { 0x400; }
+sub TYPEFLAG_FREPLACEABLE   () { 0x800; }
+sub TYPEFLAG_FDISPATCHABLE  () { 0x1000; }
+sub TYPEFLAG_FREVERSEBIND   () { 0x2000; }
+
+$TYPEFLAGS{TYPEFLAG_FAPPOBJECT()}     = TYPEFLAG_FAPPOBJECT;
+$TYPEFLAGS{TYPEFLAG_FCANCREATE()}     = TYPEFLAG_FCANCREATE;
+$TYPEFLAGS{TYPEFLAG_FLICENSED()}      = TYPEFLAG_FLICENSED;
+$TYPEFLAGS{TYPEFLAG_FPREDECLID()}     = TYPEFLAG_FPREDECLID;
+$TYPEFLAGS{TYPEFLAG_FHIDDEN()}        = TYPEFLAG_FHIDDEN;
+$TYPEFLAGS{TYPEFLAG_FCONTROL()}       = TYPEFLAG_FCONTROL;
+$TYPEFLAGS{TYPEFLAG_FDUAL()}          = TYPEFLAG_FDUAL;
+$TYPEFLAGS{TYPEFLAG_FNONEXTENSIBLE()} = TYPEFLAG_FNONEXTENSIBLE;
+$TYPEFLAGS{TYPEFLAG_FOLEAUTOMATION()} = TYPEFLAG_FOLEAUTOMATION;
+$TYPEFLAGS{TYPEFLAG_FRESTRICTED()}    = TYPEFLAG_FRESTRICTED;
+$TYPEFLAGS{TYPEFLAG_FAGGREGATABLE()}  = TYPEFLAG_FAGGREGATABLE;
+$TYPEFLAGS{TYPEFLAG_FREPLACEABLE()}   = TYPEFLAG_FREPLACEABLE;
+$TYPEFLAGS{TYPEFLAG_FDISPATCHABLE()}  = TYPEFLAG_FDISPATCHABLE;
+$TYPEFLAGS{TYPEFLAG_FREVERSEBIND()}   = TYPEFLAG_FREVERSEBIND;
+
+# Type Kind
+# ---------
+
+sub TKIND_ENUM      () { 0; }
+sub TKIND_RECORD    () { TKIND_ENUM()      + 1; }
+sub TKIND_MODULE    () { TKIND_RECORD()    + 1; }
+sub TKIND_INTERFACE () { TKIND_MODULE()    + 1; }
+sub TKIND_DISPATCH  () { TKIND_INTERFACE() + 1; }
+sub TKIND_COCLASS   () { TKIND_DISPATCH()  + 1; }
+sub TKIND_ALIAS     () { TKIND_COCLASS()   + 1; }
+sub TKIND_UNION     () { TKIND_ALIAS()     + 1; }
+sub TKIND_MAX       () { TKIND_UNION()     + 1; }
+
+$TYPEKIND[TKIND_ENUM]      = 'TKIND_ENUM';
+$TYPEKIND[TKIND_RECORD]    = 'TKIND_RECORD';
+$TYPEKIND[TKIND_MODULE]    = 'TKIND_MODULE';
+$TYPEKIND[TKIND_INTERFACE] = 'TKIND_INTERFACE';
+$TYPEKIND[TKIND_DISPATCH]  = 'TKIND_DISPATCH';
+$TYPEKIND[TKIND_COCLASS]   = 'TKIND_COCLASS';
+$TYPEKIND[TKIND_ALIAS]     = 'TKIND_ALIAS';
+$TYPEKIND[TKIND_UNION]     = 'TKIND_UNION';
+
+# Implemented Type Flags
+# ----------------------
+
+sub IMPLTYPEFLAG_FDEFAULT	() { 0x1; }
+sub IMPLTYPEFLAG_FSOURCE	() { 0x2; }
+sub IMPLTYPEFLAG_FRESTRICTED	() { 0x4; }
+sub IMPLTYPEFLAG_FDEFAULTVTABLE	() { 0x800; }
+ 
+$IMPLTYPEFLAGS{IMPLTYPEFLAG_FDEFAULT()}       = IMPLTYPEFLAG_FDEFAULT;
+$IMPLTYPEFLAGS{IMPLTYPEFLAG_FSOURCE()}        = IMPLTYPEFLAG_FSOURCE;
+$IMPLTYPEFLAGS{IMPLTYPEFLAG_FRESTRICTED()}    = IMPLTYPEFLAG_FRESTRICTED;
+$IMPLTYPEFLAGS{IMPLTYPEFLAG_FDEFAULTVTABLE()} = IMPLTYPEFLAG_FDEFAULTVTABLE;
+
+# Parameter Flags
+# ---------------
+
+sub PARAMFLAG_NONE        () { 0; }
+sub PARAMFLAG_FIN         () { 0x1; }
+sub PARAMFLAG_FOUT        () { 0x2; }
+sub PARAMFLAG_FLCID       () { 0x4; }
+sub PARAMFLAG_FRETVAL     () { 0x8; }
+sub PARAMFLAG_FOPT        () { 0x10; }
+sub PARAMFLAG_FHASDEFAULT () { 0x20; }
+
+$PARAMFLAGS{PARAMFLAG_NONE()}        = PARAMFLAG_NONE;
+$PARAMFLAGS{PARAMFLAG_FIN()}         = PARAMFLAG_FIN;
+$PARAMFLAGS{PARAMFLAG_FOUT()}        = PARAMFLAG_FOUT;
+$PARAMFLAGS{PARAMFLAG_FLCID()}       = PARAMFLAG_FLCID;
+$PARAMFLAGS{PARAMFLAG_FRETVAL()}     = PARAMFLAG_FRETVAL;
+$PARAMFLAGS{PARAMFLAG_FOPT()}        = PARAMFLAG_FOPT;
+$PARAMFLAGS{PARAMFLAG_FHASDEFAULT()} = PARAMFLAG_FHASDEFAULT;
+
+# Function Flags
+# --------------
+
+sub FUNCFLAG_FRESTRICTED       () { 0x1; }
+sub FUNCFLAG_FSOURCE           () { 0x2; }
+sub FUNCFLAG_FBINDABLE         () { 0x4; }
+sub FUNCFLAG_FREQUESTEDIT      () { 0x8; }
+sub FUNCFLAG_FDISPLAYBIND      () { 0x10; }
+sub FUNCFLAG_FDEFAULTBIND      () { 0x20; }
+sub FUNCFLAG_FHIDDEN           () { 0x40; }
+sub FUNCFLAG_FUSESGETLASTERROR () { 0x80; }
+sub FUNCFLAG_FDEFAULTCOLLELEM  () { 0x100; }
+sub FUNCFLAG_FUIDEFAULT        () { 0x200; }
+sub FUNCFLAG_FNONBROWSABLE     () { 0x400; }
+sub FUNCFLAG_FREPLACEABLE      () { 0x800; }
+sub FUNCFLAG_FIMMEDIATEBIND    () { 0x1000; }
+
+$FUNCFLAGS{FUNCFLAG_FRESTRICTED()}       = FUNCFLAG_FRESTRICTED;
+$FUNCFLAGS{FUNCFLAG_FSOURCE()}           = FUNCFLAG_FSOURCE;
+$FUNCFLAGS{FUNCFLAG_FBINDABLE()}         = FUNCFLAG_FBINDABLE;
+$FUNCFLAGS{FUNCFLAG_FREQUESTEDIT()}      = FUNCFLAG_FREQUESTEDIT;
+$FUNCFLAGS{FUNCFLAG_FDISPLAYBIND()}      = FUNCFLAG_FDISPLAYBIND;
+$FUNCFLAGS{FUNCFLAG_FDEFAULTBIND()}      = FUNCFLAG_FDEFAULTBIND;
+$FUNCFLAGS{FUNCFLAG_FHIDDEN()}           = FUNCFLAG_FHIDDEN;
+$FUNCFLAGS{FUNCFLAG_FUSESGETLASTERROR()} = FUNCFLAG_FUSESGETLASTERROR;
+$FUNCFLAGS{FUNCFLAG_FDEFAULTCOLLELEM()}  = FUNCFLAG_FDEFAULTCOLLELEM;
+$FUNCFLAGS{FUNCFLAG_FUIDEFAULT()}        = FUNCFLAG_FUIDEFAULT;
+$FUNCFLAGS{FUNCFLAG_FNONBROWSABLE()}     = FUNCFLAG_FNONBROWSABLE;
+$FUNCFLAGS{FUNCFLAG_FREPLACEABLE()}      = FUNCFLAG_FREPLACEABLE;
+$FUNCFLAGS{FUNCFLAG_FIMMEDIATEBIND()}    = FUNCFLAG_FIMMEDIATEBIND;
+
+# Calling conventions
+# -------------------
+
+sub CC_FASTCALL   () { 0; }
+sub CC_CDECL      () { 1; }
+sub CC_MSCPASCAL  () { CC_CDECL()      + 1; }
+sub CC_PASCAL     () { CC_MSCPASCAL; }
+sub CC_MACPASCAL  () { CC_PASCAL()     + 1; }
+sub CC_STDCALL    () { CC_MACPASCAL()  + 1; }
+sub CC_FPFASTCALL () { CC_STDCALL()    + 1; }
+sub CC_SYSCALL    () { CC_FPFASTCALL() + 1; }
+sub CC_MPWCDECL   () { CC_SYSCALL()    + 1; }
+sub CC_MPWPASCAL  () { CC_MPWCDECL()   + 1; }
+sub CC_MAX        () { CC_MPWPASCAL()  + 1; }
+
+$CALLCONV[CC_FASTCALL]   = 'CC_FASTCALL';
+$CALLCONV[CC_CDECL]      = 'CC_CDECL';
+$CALLCONV[CC_PASCAL]     = 'CC_PASCAL';
+$CALLCONV[CC_MACPASCAL]  = 'CC_MACPASCAL';
+$CALLCONV[CC_STDCALL]    = 'CC_STDCALL';
+$CALLCONV[CC_FPFASTCALL] = 'CC_FPFASTCALL';
+$CALLCONV[CC_SYSCALL]    = 'CC_SYSCALL';
+$CALLCONV[CC_MPWCDECL]   = 'CC_MPWCDECL';
+$CALLCONV[CC_MPWPASCAL]  = 'CC_MPWPASCAL';
+
+# Function Kind
+# -------------
+
+sub FUNC_VIRTUAL     () { 0; }
+sub FUNC_PUREVIRTUAL () { FUNC_VIRTUAL()     + 1; }
+sub FUNC_NONVIRTUAL  () { FUNC_PUREVIRTUAL() + 1; }
+sub FUNC_STATIC      () { FUNC_NONVIRTUAL()  + 1; }
+sub FUNC_DISPATCH    () { FUNC_STATIC()      + 1; }
+
+$FUNCKIND[FUNC_VIRTUAL]     = 'FUNC_VIRTUAL';
+$FUNCKIND[FUNC_PUREVIRTUAL] = 'FUNC_PUREVIRTUAL';
+$FUNCKIND[FUNC_NONVIRTUAL]  = 'FUNC_NONVIRTUAL';
+$FUNCKIND[FUNC_STATIC]      = 'FUNC_STATIC';
+$FUNCKIND[FUNC_DISPATCH]    = 'FUNC_DISPATCH';
+
+# Invoke Kind
+# -----------
+
+sub INVOKE_FUNC           () { 1; }
+sub INVOKE_PROPERTYGET    () { 2; }
+sub INVOKE_PROPERTYPUT    () { 4; }
+sub INVOKE_PROPERTYPUTREF () { 8; }
+
+$INVOKEKIND{INVOKE_FUNC()}           = INVOKE_FUNC;
+$INVOKEKIND{INVOKE_PROPERTYGET()}    = INVOKE_PROPERTYGET;
+$INVOKEKIND{INVOKE_PROPERTYPUT()}    = INVOKE_PROPERTYPUT;
+$INVOKEKIND{INVOKE_PROPERTYPUTREF()} = INVOKE_PROPERTYPUTREF;
+
+# Variable Flags
+# --------------
+
+sub VARFLAG_FREADONLY        () { 0x1;    }
+sub VARFLAG_FSOURCE          () { 0x2;    }
+sub VARFLAG_FBINDABLE        () { 0x4;    }
+sub VARFLAG_FREQUESTEDIT     () { 0x8;    }
+sub VARFLAG_FDISPLAYBIND     () { 0x10;   }
+sub VARFLAG_FDEFAULTBIND     () { 0x20;   }
+sub VARFLAG_FHIDDEN          () { 0x40;   }
+sub VARFLAG_FRESTRICTED      () { 0x80;   }
+sub VARFLAG_FDEFAULTCOLLELEM () { 0x100;  }
+sub VARFLAG_FUIDEFAULT       () { 0x200;  }
+sub VARFLAG_FNONBROWSABLE    () { 0x400;  }
+sub VARFLAG_FREPLACEABLE     () { 0x800;  }
+sub VARFLAG_FIMMEDIATEBIND   () { 0x1000; }
+
+$VARFLAGS{VARFLAG_FREADONLY()}        = VARFLAG_FREADONLY;
+$VARFLAGS{VARFLAG_FSOURCE()}          = VARFLAG_FSOURCE;
+$VARFLAGS{VARFLAG_FBINDABLE()}        = VARFLAG_FBINDABLE;
+$VARFLAGS{VARFLAG_FREQUESTEDIT()}     = VARFLAG_FREQUESTEDIT;
+$VARFLAGS{VARFLAG_FDISPLAYBIND()}     = VARFLAG_FDISPLAYBIND;
+$VARFLAGS{VARFLAG_FDEFAULTBIND()}     = VARFLAG_FDEFAULTBIND;
+$VARFLAGS{VARFLAG_FHIDDEN()}          = VARFLAG_FHIDDEN;
+$VARFLAGS{VARFLAG_FRESTRICTED()}      = VARFLAG_FRESTRICTED;
+$VARFLAGS{VARFLAG_FDEFAULTCOLLELEM()} = VARFLAG_FDEFAULTCOLLELEM;
+$VARFLAGS{VARFLAG_FUIDEFAULT()}       = VARFLAG_FUIDEFAULT;
+$VARFLAGS{VARFLAG_FNONBROWSABLE()}    = VARFLAG_FNONBROWSABLE;
+$VARFLAGS{VARFLAG_FREPLACEABLE()}     = VARFLAG_FREPLACEABLE;
+$VARFLAGS{VARFLAG_FIMMEDIATEBIND()}   = VARFLAG_FIMMEDIATEBIND;
+
+
+# Variant Types
+# -------------
+
+sub VT_EMPTY           () { 0; }
+sub VT_NULL            () { 1; }
+sub VT_I2              () { 2; }
+sub VT_I4              () { 3; }
+sub VT_R4              () { 4; }
+sub VT_R8              () { 5; }
+sub VT_CY              () { 6; }
+sub VT_DATE            () { 7; }
+sub VT_BSTR            () { 8; }
+sub VT_DISPATCH        () { 9; }
+sub VT_ERROR           () { 10; }
+sub VT_BOOL            () { 11; }
+sub VT_VARIANT         () { 12; }
+sub VT_UNKNOWN         () { 13; }
+sub VT_DECIMAL         () { 14; }
+sub VT_I1              () { 16; }
+sub VT_UI1             () { 17; }
+sub VT_UI2             () { 18; }
+sub VT_UI4             () { 19; }
+sub VT_I8              () { 20; }
+sub VT_UI8             () { 21; }
+sub VT_INT             () { 22; }
+sub VT_UINT            () { 23; }
+sub VT_VOID            () { 24; }
+sub VT_HRESULT         () { 25; }
+sub VT_PTR             () { 26; }
+sub VT_SAFEARRAY       () { 27; }
+sub VT_CARRAY          () { 28; }
+sub VT_USERDEFINED     () { 29; }
+sub VT_LPSTR           () { 30; }
+sub VT_LPWSTR          () { 31; }
+sub VT_FILETIME        () { 64; }
+sub VT_BLOB            () { 65; }
+sub VT_STREAM          () { 66; }
+sub VT_STORAGE         () { 67; }
+sub VT_STREAMED_OBJECT () { 68; }
+sub VT_STORED_OBJECT   () { 69; }
+sub VT_BLOB_OBJECT     () { 70; }
+sub VT_CF              () { 71; }
+sub VT_CLSID           () { 72; }
+sub VT_VECTOR          () { 0x1000; }
+sub VT_ARRAY           () { 0x2000; }
+sub VT_BYREF           () { 0x4000; }
+sub VT_RESERVED        () { 0x8000; }
+sub VT_ILLEGAL         () { 0xffff; }
+sub VT_ILLEGALMASKED   () { 0xfff; }
+sub VT_TYPEMASK        () { 0xfff; }
+
+$VT[VT_EMPTY]           = 'VT_EMPTY';
+$VT[VT_NULL]            = 'VT_NULL';
+$VT[VT_I2]              = 'VT_I2';
+$VT[VT_I4]              = 'VT_I4';
+$VT[VT_R4]              = 'VT_R4';
+$VT[VT_R8]              = 'VT_R8';
+$VT[VT_CY]              = 'VT_CY';
+$VT[VT_DATE]            = 'VT_DATE';
+$VT[VT_BSTR]            = 'VT_BSTR';
+$VT[VT_DISPATCH]        = 'VT_DISPATCH';
+$VT[VT_ERROR]           = 'VT_ERROR';
+$VT[VT_BOOL]            = 'VT_BOOL';
+$VT[VT_VARIANT]         = 'VT_VARIANT';
+$VT[VT_UNKNOWN]         = 'VT_UNKNOWN';
+$VT[VT_DECIMAL]         = 'VT_DECIMAL';
+$VT[VT_I1]              = 'VT_I1';
+$VT[VT_UI1]             = 'VT_UI1';
+$VT[VT_UI2]             = 'VT_UI2';
+$VT[VT_UI4]             = 'VT_UI4';
+$VT[VT_I8]              = 'VT_I8';
+$VT[VT_UI8]             = 'VT_UI8';
+$VT[VT_INT]             = 'VT_INT';
+$VT[VT_UINT]            = 'VT_UINT';
+$VT[VT_VOID]            = 'VT_VOID';
+$VT[VT_HRESULT]         = 'VT_HRESULT';
+$VT[VT_PTR]             = 'VT_PTR';
+$VT[VT_SAFEARRAY]       = 'VT_SAFEARRAY';
+$VT[VT_CARRAY]          = 'VT_CARRAY';
+$VT[VT_USERDEFINED]     = 'VT_USERDEFINED';
+$VT[VT_LPSTR]           = 'VT_LPSTR';
+$VT[VT_LPWSTR]          = 'VT_LPWSTR';
+$VT[VT_FILETIME]        = 'VT_FILETIME';
+$VT[VT_BLOB]            = 'VT_BLOB';
+$VT[VT_STREAM]          = 'VT_STREAM';
+$VT[VT_STORAGE]         = 'VT_STORAGE';
+$VT[VT_STREAMED_OBJECT] = 'VT_STREAMED_OBJECT';
+$VT[VT_STORED_OBJECT]   = 'VT_STORED_OBJECT';
+$VT[VT_BLOB_OBJECT]     = 'VT_BLOB_OBJECT';
+$VT[VT_CF]              = 'VT_CF';
+$VT[VT_CLSID]           = 'VT_CLSID';
+$VT[VT_VECTOR]          = 'VT_VECTOR';
+$VT[VT_ARRAY]           = 'VT_ARRAY';
+$VT[VT_BYREF]           = 'VT_BYREF';
+$VT[VT_RESERVED]        = 'VT_RESERVED';
+$VT[VT_ILLEGAL]         = 'VT_ILLEGAL';
+$VT[VT_ILLEGALMASKED]   = 'VT_ILLEGALMASKED';
+$VT[VT_TYPEMASK]        = 'VT_TYPEMASK';
+
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/OLE/Variant.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/OLE/Variant.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/OLE/Variant.pm	(revision 14139)
@@ -0,0 +1,577 @@
+# The documentation is at the __END__
+
+package Win32::OLE::Variant;
+require Win32::OLE;  # Make sure the XS bootstrap has been called
+
+use strict;
+use vars qw(@ISA @EXPORT @EXPORT_OK);
+
+use Exporter;
+@ISA = qw(Exporter);
+
+@EXPORT = qw(
+	     Variant
+	     VT_EMPTY VT_NULL VT_I2 VT_I4 VT_R4 VT_R8 VT_CY VT_DATE VT_BSTR
+	     VT_DISPATCH VT_ERROR VT_BOOL VT_VARIANT VT_UNKNOWN VT_DECIMAL VT_UI1
+	     VT_ARRAY VT_BYREF
+	    );
+
+@EXPORT_OK = qw(CP_ACP CP_OEMCP nothing nullstring);
+
+# Automation data types.
+sub VT_EMPTY {0;}
+sub VT_NULL {1;}
+sub VT_I2 {2;}
+sub VT_I4 {3;}
+sub VT_R4 {4;}
+sub VT_R8 {5;}
+sub VT_CY {6;}
+sub VT_DATE {7;}
+sub VT_BSTR {8;}
+sub VT_DISPATCH {9;}
+sub VT_ERROR {10;}
+sub VT_BOOL {11;}
+sub VT_VARIANT {12;}
+sub VT_UNKNOWN {13;}
+sub VT_DECIMAL {14;}	# Officially not allowed in VARIANTARGs
+sub VT_UI1 {17;}
+
+sub VT_ARRAY {0x2000;}
+sub VT_BYREF {0x4000;}
+
+
+# For backward compatibility
+sub CP_ACP   {0;}     # ANSI codepage
+sub CP_OEMCP {1;}     # OEM codepage
+
+use overload
+    # '+' => 'Add', '-' => 'Sub', '*' => 'Mul', '/' => 'Div',
+    '""'     => sub {$_[0]->As(VT_BSTR)},
+    '0+'     => sub {$_[0]->As(VT_R8)},
+    fallback => 1;
+
+sub Variant {
+    return Win32::OLE::Variant->new(@_);
+}
+
+sub nothing {
+    return Win32::OLE::Variant->new(VT_DISPATCH);
+}
+
+sub nullstring {
+    return Win32::OLE::Variant->new(VT_BSTR);
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Win32::OLE::Variant - Create and modify OLE VARIANT variables
+
+=head1 SYNOPSIS
+
+	use Win32::OLE::Variant;
+	my $var = Variant(VT_DATE, 'Jan 1,1970');
+	$OleObject->{value} = $var;
+	$OleObject->Method($var);
+
+
+=head1 DESCRIPTION
+
+The IDispatch interface used by the Perl OLE module uses a universal
+argument type called VARIANT.  This is basically an object containing
+a data type and the actual data value.  The data type is specified by
+the VT_xxx constants.
+
+=head2 Functions
+
+=over 8
+
+=item nothing()
+
+The nothing() function returns an empty VT_DISPATCH variant.  It can be
+used to clear an object reference stored in a property
+
+	use Win32::OLE::Variant qw(:DEFAULT nothing);
+	# ...
+	$object->{Property} = nothing;
+
+This has the same effect as the Visual Basic statement
+
+	Set object.Property = Nothing
+
+The nothing() function is B<not> exported by default.
+
+=item nullstring()
+
+The nullstring() function returns a VT_BSTR variant with a NULL string
+pointer.  This is B<not> the same as a VT_BSTR variant with an empty
+string "".  The nullstring() value is the same as the vbNullString
+constant in Visual Basic.
+
+The nullstring() function is B<not> exported by default.
+
+=item Variant(TYPE, DATA)
+
+This is just a function alias of the C<Win32::OLE::Variant->new()>
+method (see below).  This function is exported by default.
+
+=back
+
+=head2 Methods
+
+=over 8
+
+=item new(TYPE, DATA)
+
+This method returns a Win32::OLE::Variant object of the specified
+TYPE that contains the given DATA.  The Win32::OLE::Variant object
+can be used to specify data types other than IV, NV or PV (which are
+supported transparently).  See L<Variants> below for details.
+
+For VT_EMPTY and VT_NULL variants, the DATA argument may be omitted.
+For all non-VT_ARRAY variants DATA specifies the initial value.
+
+To create a SAFEARRAY variant, you have to specify the VT_ARRAY flag in
+addition to the variant base type of the array elemnts.  In this cases
+DATA must be a list specifying the dimensions of the array.  Each element
+can be either an element count (indices 0 to count-1) or an array
+reference pointing to the lower and upper array bounds of this dimension:
+
+	my $Array = Win32::OLE::Variant->new(VT_ARRAY|VT_R8, [1,2], 2);
+
+This creates a 2-dimensional SAFEARRAY of doubles with 4 elements:
+(1,0), (1,1), (2,0) and (2,1).
+
+A special case is the the creation of one-dimensional VT_UI1 arrays with
+a string DATA argument:
+
+	my $String = Variant(VT_ARRAY|VT_UI1, "String");
+
+This creates a 6 element character array initialized to "String".  For
+backward compatibility VT_UI1 with a string initializer automatically
+implies VT_ARRAY.  The next line is equivalent to the previous example:
+
+	my $String = Variant(VT_UI1, "String");
+
+If you really need a single character VT_UI1 variant, you have to create
+it using a numeric intializer:
+
+	my $Char = Variant(VT_UI1, ord('A'));
+
+=item As(TYPE)
+
+C<As> converts the VARIANT to the new type before converting to a
+Perl value.  This take the current LCID setting into account.  For
+example a string might contain a ',' as the decimal point character.
+Using C<$variant->As(VT_R8)> will correctly return the floating
+point value.
+
+The underlying variant object is NOT changed by this method.
+
+=item ChangeType(TYPE)
+
+This method changes the type of the contained VARIANT in place.  It
+returns the object itself, not the converted value.
+
+=item Copy([DIM])
+
+This method creates a copy of the object.  If the original variant had
+the VT_BYREF bit set then the new object will contain a copy of the
+referenced data and not a reference to the same old data.  The new
+object will not have the VT_BYREF bit set.
+
+	my $Var = Variant(VT_I4|VT_ARRAY|VT_BYREF, [1,5], 3);
+	my $Copy = $Var->Copy;
+
+The type of C<$Copy> is now VT_I4|VT_ARRAY and the value is a copy of
+the other SAFEARRAY.  Changes to elements of C<$Var> will not be reflected
+in C<$Copy> and vice versa.
+
+The C<Copy> method can also be used to extract a single element of a
+VT_ARRAY | VT_VARIANT object.  In this case the array indices must be
+specified as a list DIM:
+
+	my $Int = $Var->Copy(1, 2);
+
+C<$Int> is now a VT_I4 Variant object containing the value of element (1,2).
+
+=item Currency([FORMAT[, LCID]])
+
+This method converts the VARIANT value into a formatted curency string.  The
+FORMAT can be either an integer constant or a hash reference.  Valid constants
+are 0 and LOCALE_NOUSEROVERRIDE.  You get the value of LOCALE_NOUSEROVERRIDE
+from the Win32::OLE::NLS module:
+
+	use Win32::OLE::NLS qw(:LOCALE);
+
+LOCALE_NOUSEROVERRIDE tells the method to use the system default currency
+format for the specified locale, disregarding any changes that might have
+been made through the control panel application.
+
+The hash reference could contain the following keys:
+
+	NumDigits	number of fractional digits
+	LeadingZero	whether to use leading zeroes in decimal fields
+	Grouping	size of each group of digits to the left of the decimal
+	DecimalSep	decimal separator string
+	ThousandSep	thousand separator string
+	NegativeOrder	see L<Win32::OLE::NLS/LOCALE_ICURRENCY>
+	PositiveOrder	see L<Win32::OLE::NLS/LOCALE_INEGCURR>
+	CurrencySymbol	currency symbol string
+
+For example:
+
+	use Win32::OLE::Variant;
+	use Win32::OLE::NLS qw(:DEFAULT :LANG :SUBLANG :DATE :TIME);
+	my $lcidGerman = MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_NEUTRAL));
+	my $v = Variant(VT_CY, "-922337203685477.5808");
+	print $v->Currency({CurrencySymbol => "Tuits"}, $lcidGerman), "\n";
+
+will print:
+
+	-922.337.203.685.477,58 Tuits
+
+=item Date([FORMAT[, LCID]])
+
+Converts the VARIANT into a formatted date string.  FORMAT can be either
+one of the following integer constants or a format string:
+
+	LOCALE_NOUSEROVERRIDE	system default date format for this locale
+	DATE_SHORTDATE		use the short date format (default)
+	DATE_LONGDATE		use the long date format
+	DATE_YEARMONTH		use the year/month format
+	DATE_USE_ALT_CALENDAR	use the alternate calendar, if one exists
+	DATE_LTRREADING		left-to-right reading order layout
+	DATE_RTLREADING		right-to left reading order layout
+
+The constants are available from the Win32::OLE::NLS module:
+
+	use Win32::OLE::NLS qw(:LOCALE :DATE);
+
+The following elements can be used to construct a date format string.
+Characters must be specified exactly as given below (e.g. "dd" B<not> "DD").
+Spaces can be inserted anywhere between formating codes, other verbatim
+text should be included in single quotes.
+
+	d	day of month
+	dd	day of month with leading zero for single-digit days
+	ddd	day of week: three-letter abbreviation (LOCALE_SABBREVDAYNAME)
+	dddd	day of week: full name (LOCALE_SDAYNAME)
+	M	month
+	MM	month with leading zero for single-digit months
+	MMM	month: three-letter abbreviation (LOCALE_SABBREVMONTHNAME)
+	MMMM	month: full name (LOCALE_SMONTHNAME)
+	y	year as last two digits
+	yy	year as last two digits with leading zero for years less than 10
+	yyyy	year represented by full four digits
+	gg	period/era string
+
+For example:
+
+	my $v = Variant(VT_DATE, "April 1 99");
+	print $v->Date(DATE_LONGDATE), "\n";
+	print $v->Date("ddd',' MMM dd yy"), "\n";
+
+will print:
+
+	Thursday, April 01, 1999
+	Thu, Apr 01 99
+
+=item Dim()
+
+Returns a list of array bounds for a VT_ARRAY variant.  The list contains
+an array reference for each dimension of the variant's SAFEARRAY.  This
+reference points to an array containing the lower and upper bounds for
+this dimension.  For example:
+
+	my @Dim = $Var->Dim;
+
+Now C<@Dim> contains the following list: C<([1,5], [0,2])>.
+
+=item Get(DIM)
+
+For normal variants C<Get> returns the value of the variant, just like the
+C<Value> method.  For VT_ARRAY variants C<Get> retrieves the value of a single
+array element.  In this case C<DIM> must be a list of array indices.  E.g.
+
+	my $Val = $Var->Get(2,0);
+
+As a special case for one dimensional VT_UI1|VT_ARRAY variants the C<Get>
+method without arguments returns the character array as a Perl string.
+
+	print $String->Get, "\n";
+
+=item IsNothing()
+
+Tests if the object is an empty VT_DISPATCH variant.  See also nothing().
+
+=item IsNullString()
+
+Tests if the object is an empty VT_BSTR variant.  See also nullstring().
+
+=item LastError()
+
+The use of the C<Win32::OLE::Variant->LastError()> method is deprecated.
+Please use the C<Win32::OLE->LastError()> class method instead.
+
+=item Number([FORMAT[, LCID]])
+
+This method converts the VARIANT value into a formatted number string.  The
+FORMAT can be either an integer constant or a hash reference.  Valid constants
+are 0 and LOCALE_NOUSEROVERRIDE.  You get the value of LOCALE_NOUSEROVERRIDE
+from the Win32::OLE::NLS module:
+
+	use Win32::OLE::NLS qw(:LOCALE);
+
+LOCALE_NOUSEROVERRIDE tells the method to use the system default number
+format for the specified locale, disregarding any changes that might have
+been made through the control panel application.
+
+The hash reference could contain the following keys:
+
+	NumDigits	number of fractional digits
+	LeadingZero	whether to use leading zeroes in decimal fields
+	Grouping	size of each group of digits to the left of the decimal
+	DecimalSep	decimal separator string
+	ThousandSep	thousand separator string
+	NegativeOrder	see L<Win32::OLE::NLS/LOCALE_INEGNUMBER>
+
+=item Put(DIM, VALUE)
+
+The C<Put> method is used to assign a new value to a variant.  The value will
+be coerced into the current type of the variant.  E.g.:
+
+	my $Var = Variant(VT_I4, 42);
+	$Var->Put(3.1415);
+
+This changes the value of the variant to C<3> because the type is VT_I4.
+
+For VT_ARRAY type variants the indices for each dimension of the contained
+SAFEARRAY must be specified in front of the new value:
+
+	$Array->Put(1, 1, 2.7);
+
+It is also possible to assign values to *every* element of the SAFEARRAY at
+once using a single Put() method call:
+
+	$Array->Put([[1,2], [3,4]]);
+
+In this case the argument to Put() must be an array reference and the
+dimensions of the Perl list-of-lists must match the dimensions of the
+SAFEARRAY exactly.
+
+The are a few special cases for one-dimensional VT_UI1 arrays: The VALUE
+can be specified as a string instead of a number.  This will set the selected
+character to the first character of the string or to '\0' if the string was
+empty:
+
+	my $String = Variant(VT_UI1|VT_ARRAY, "ABCDE");
+	$String->Put(1, "123");
+	$String->Put(3, ord('Z'));
+	$String->Put(4, '');
+
+This will set the value of C<$String> to C<"A1CZ\0">.  If the index is omitted
+then the string is copied to the value completely.  The string is truncated
+if it is longer than the size of the VT_UI1 array.  The result will be padded
+with '\0's if the string is shorter:
+
+	$String->Put("String");
+
+Now C<$String> contains the value "Strin".
+
+C<Put> returns the Variant object itself so that multiple C<Put> calls can be
+chained together:
+
+	$Array->Put(0,0,$First_value)->Put(0,1,$Another_value);
+
+=item Time([FORMAT[, LCID]])
+
+Converts the VARIANT into a formatted time string.  FORMAT can be either
+one of the following integer constants or a format string:
+
+	LOCALE_NOUSEROVERRIDE	system default time format for this locale
+	TIME_NOMINUTESORSECONDS	don't use minutes or seconds
+	TIME_NOSECONDS		don't use seconds
+	TIME_NOTIMEMARKER	don't use a time marker
+	TIME_FORCE24HOURFORMAT	always use a 24-hour time format
+
+The constants are available from the Win32::OLE::NLS module:
+
+	use Win32::OLE::NLS qw(:LOCALE :TIME);
+
+The following elements can be used to construct a time format string.
+Characters must be specified exactly as given below (e.g. "dd" B<not> "DD").
+Spaces can be inserted anywhere between formating codes, other verbatim
+text should be included in single quotes.
+
+	h	hours; 12-hour clock
+	hh	hours with leading zero for single-digit hours; 12-hour clock
+	H	hours; 24-hour clock
+	HH	hours with leading zero for single-digit hours; 24-hour clock
+	m	minutes
+	mm	minutes with leading zero for single-digit minutes
+	s	seconds
+	ss	seconds with leading zero for single-digit seconds
+	t	one character time marker string, such as A or P
+	tt	multicharacter time marker string, such as AM or PM
+
+For example:
+
+	my $v = Variant(VT_DATE, "April 1 99 2:23 pm");
+	print $v->Time, "\n";
+	print $v->Time(TIME_FORCE24HOURFORMAT|TIME_NOTIMEMARKER), "\n";
+	print $v->Time("hh.mm.ss tt"), "\n";
+
+will print:
+
+	2:23:00 PM
+	14:23:00
+	02.23.00 PM
+
+=item Type()
+
+The C<Type> method returns the variant type of the contained VARIANT.
+
+=item Unicode()
+
+The C<Unicode> method returns a C<Unicode::String> object.  This contains
+the BSTR value of the variant in network byte order.  If the variant is
+not currently in VT_BSTR format then a VT_BSTR copy will be produced first.
+
+=item Value()
+
+The C<Value> method returns the value of the VARIANT as a Perl value.  The
+conversion is performed in the same manner as all return values of
+Win32::OLE method calls are converted.
+
+=back
+
+=head2 Overloading
+
+The Win32::OLE::Variant package has overloaded the conversion to
+string and number formats.  Therefore variant objects can be used in
+arithmetic and string operations without applying the C<Value>
+method first.
+
+=head2 Class Variables
+
+The Win32::OLE::Variant class used to have its own set of class variables
+like C<$CP>, C<$LCID> and C<$Warn>.  In version 0.1003 and later of the
+Win32::OLE module these variables have been eleminated.  Now the settings
+of Win32::OLE are used by the Win32::OLE::Variant module too.  Please read
+the documentation of the C<Win32::OLE-&gt;Option> class method.
+
+
+=head2 Constants
+
+These constants are exported by default:
+
+	VT_EMPTY
+	VT_NULL
+	VT_I2
+	VT_I4
+	VT_R4
+	VT_R8
+	VT_CY
+	VT_DATE
+	VT_BSTR
+	VT_DISPATCH
+	VT_ERROR
+	VT_BOOL
+	VT_VARIANT
+	VT_UNKNOWN
+	VT_DECIMAL
+	VT_UI1
+
+	VT_ARRAY
+	VT_BYREF
+
+VT_DECIMAL is not on the official list of allowable OLE Automation
+datatypes.  But even Microsoft ADO seems to sometimes return values
+of Recordset fields in VT_DECIMAL format.
+
+=head2 Variants
+
+A Variant is a data type that is used to pass data between OLE
+connections.
+
+The default behavior is to convert each perl scalar variable into
+an OLE Variant according to the internal perl representation.
+The following type correspondence holds:
+
+        C type          Perl type       OLE type
+        ------          ---------       --------
+          int              IV            VT_I4
+        double             NV            VT_R8
+        char *             PV            VT_BSTR
+        void *           ref to AV       VT_ARRAY
+           ?              undef          VT_ERROR
+           ?        Win32::OLE object    VT_DISPATCH
+
+Note that VT_BSTR is a wide character or Unicode string.  This presents a
+problem if you want to pass in binary data as a parameter as 0x00 is
+inserted between all the bytes in your data.  The C<Variant()> method
+provides a solution to this.  With Variants the script writer can specify
+the OLE variant type that the parameter should be converted to.  Currently
+supported types are:
+
+        VT_UI1     unsigned char
+        VT_I2      signed int (2 bytes)
+        VT_I4      signed int (4 bytes)
+        VT_R4      float      (4 bytes)
+        VT_R8      float      (8 bytes)
+        VT_DATE    OLE Date
+        VT_BSTR    OLE String
+        VT_CY      OLE Currency
+        VT_BOOL    OLE Boolean
+
+When VT_DATE and VT_CY objects are created, the input parameter is treated
+as a Perl string type, which is then converted to VT_BSTR, and finally to
+VT_DATE of VT_CY using the C<VariantChangeType()> OLE API function.
+See L<Win32::OLE/EXAMPLES> for how these types can be used.
+
+=head2 Variant arrays
+
+A variant can not only contain a single value but also a multi-dimensional
+array of values (called a SAFEARRAY).  In this case the VT_ARRAY flag must
+be added to the base variant type, e.g. C<VT_I4 | VT_ARRAY> for an array of
+integers.  The VT_EMPTY and VT_NULL types are invalid for SAFEARRAYs.  It
+is possible to create an array of variants: C<VT_VARIANT | VT_ARRAY>.  In this
+case each element of the array can have a different type (including VT_EMPTY
+and VT_NULL).  The elements of a VT_VARIANT SAFEARRAY cannot have either of the
+VT_ARRAY or VT_BYREF flags set.
+
+The lower and upper bounds for each dimension can be specified separately.
+They do not have to have all the same lower bound (unlike Perl's arrays).
+
+=head2 Variants by reference
+
+Some OLE servers expect parameters passed by reference so that they
+can be changed in the method call.  This allows methods to easily
+return multiple values.  There is preliminary support for this in
+the Win32::OLE::Variant module:
+
+	my $x = Variant(VT_I4|VT_BYREF, 0);
+	my $y = Variant(VT_I4|VT_BYREF, 0);
+	$Corel->GetSize($x, $y);
+	print "Size is $x by $y\n";
+
+After the C<GetSize> method call C<$x> and C<$y> will be set to
+the respective sizes.  They will still be variants.  In the print
+statement the overloading converts them to string representation
+automatically.
+
+VT_BYREF is now supported for all variant types (including SAFEARRAYs).
+It can also be used to pass an OLE object by reference:
+
+	my $Results = $App->CreateResultsObject;
+	$Object->Method(Variant(VT_DISPATCH|VT_BYREF, $Results));
+
+=head1 AUTHORS/COPYRIGHT
+
+This module is part of the Win32::OLE distribution.
+
+=cut
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/PerfLib.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/PerfLib.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/PerfLib.pm	(revision 14139)
@@ -0,0 +1,538 @@
+package Win32::PerfLib;
+
+use strict;
+use Carp;
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $AUTOLOAD);
+
+require Exporter;
+require DynaLoader;
+require AutoLoader;
+
+@ISA = qw(Exporter DynaLoader);
+
+@EXPORT = qw(
+	     PERF_100NSEC_MULTI_TIMER
+	     PERF_100NSEC_MULTI_TIMER_INV
+	     PERF_100NSEC_TIMER
+	     PERF_100NSEC_TIMER_INV
+	     PERF_AVERAGE_BASE
+	     PERF_AVERAGE_BULK
+	     PERF_AVERAGE_TIMER
+	     PERF_COUNTER_BASE
+	     PERF_COUNTER_BULK_COUNT
+	     PERF_COUNTER_COUNTER
+	     PERF_COUNTER_DELTA
+	     PERF_COUNTER_ELAPSED
+	     PERF_COUNTER_FRACTION
+	     PERF_COUNTER_HISTOGRAM
+	     PERF_COUNTER_HISTOGRAM_TYPE
+	     PERF_COUNTER_LARGE_DELTA
+	     PERF_COUNTER_LARGE_QUEUELEN_TYPE
+	     PERF_COUNTER_LARGE_RAWCOUNT
+	     PERF_COUNTER_LARGE_RAWCOUNT_HEX
+	     PERF_COUNTER_MULTI_BASE
+	     PERF_COUNTER_MULTI_TIMER
+	     PERF_COUNTER_MULTI_TIMER_INV
+	     PERF_COUNTER_NODATA
+	     PERF_COUNTER_QUEUELEN
+	     PERF_COUNTER_QUEUELEN_TYPE
+	     PERF_COUNTER_RATE
+	     PERF_COUNTER_RAWCOUNT
+	     PERF_COUNTER_RAWCOUNT_HEX
+	     PERF_COUNTER_TEXT
+	     PERF_COUNTER_TIMER
+	     PERF_COUNTER_TIMER_INV
+	     PERF_COUNTER_VALUE
+	     PERF_DATA_REVISION
+	     PERF_DATA_VERSION
+	     PERF_DELTA_BASE
+	     PERF_DELTA_COUNTER
+	     PERF_DETAIL_ADVANCED
+	     PERF_DETAIL_EXPERT
+	     PERF_DETAIL_NOVICE
+	     PERF_DETAIL_WIZARD
+	     PERF_DISPLAY_NOSHOW
+	     PERF_DISPLAY_NO_SUFFIX
+	     PERF_DISPLAY_PERCENT
+	     PERF_DISPLAY_PER_SEC
+	     PERF_DISPLAY_SECONDS
+	     PERF_ELAPSED_TIME
+	     PERF_INVERSE_COUNTER
+	     PERF_MULTI_COUNTER
+	     PERF_NO_INSTANCES
+	     PERF_NO_UNIQUE_ID
+	     PERF_NUMBER_DECIMAL
+	     PERF_NUMBER_DEC_1000
+	     PERF_NUMBER_HEX
+	     PERF_OBJECT_TIMER
+	     PERF_RAW_BASE
+	     PERF_RAW_FRACTION
+	     PERF_SAMPLE_BASE
+	     PERF_SAMPLE_COUNTER
+	     PERF_SAMPLE_FRACTION
+	     PERF_SIZE_DWORD
+	     PERF_SIZE_LARGE
+	     PERF_SIZE_VARIABLE_LEN
+	     PERF_SIZE_ZERO
+	     PERF_TEXT_ASCII
+	     PERF_TEXT_UNICODE
+	     PERF_TIMER_100NS
+	     PERF_TIMER_TICK
+	     PERF_TYPE_COUNTER
+	     PERF_TYPE_NUMBER
+	     PERF_TYPE_TEXT
+	     PERF_TYPE_ZERO
+	    );
+
+$VERSION = '0.05';
+
+sub AUTOLOAD {
+   
+    my $constname;
+    ($constname = $AUTOLOAD) =~ s/.*:://;
+    local $! = 0;
+    my $val = constant($constname);
+    if ($! != 0) {
+	if ($! =~ /Invalid/) {
+	    $AutoLoader::AUTOLOAD = $AUTOLOAD;
+	    goto &AutoLoader::AUTOLOAD;
+	}
+	else {
+	    croak "Your vendor has not defined Win32::PerfLib macro $constname";
+	}
+    }
+    eval "sub $AUTOLOAD { $val }";
+    goto &$AUTOLOAD;
+}
+
+bootstrap Win32::PerfLib $VERSION;
+
+# Preloaded methods go here.
+
+sub new
+{
+    my $proto = shift;
+    my $class = ref($proto) || $proto;
+    my $comp = shift;
+    my $handle;
+    my $self = {};
+    if(PerfLibOpen($comp,$handle))
+    {
+	$self->{handle} = $handle;
+	bless $self, $class;
+	return $self;
+    }
+    else
+    {
+	return undef;
+    }
+    
+}
+
+sub Close
+{
+    my $self = shift;
+    return PerfLibClose($self->{handle});
+}
+
+sub DESTROY
+{
+    my $self = shift;
+    if(!PerfLibClose($self->{handle}))
+    {
+	croak "Error closing handle!\n";
+    }
+}
+
+sub GetCounterNames
+{
+    my($machine,$href) = @_;
+    if(ref $href ne "HASH")
+    {
+	croak("usage: Win32::PerfLib::GetCounterNames(machine,hashRef)\n");
+    }
+    my($data,@data,$num,$name);
+    my $retval = PerfLibGetNames($machine,$data);
+    if($retval)
+    {
+	@data = split(/\0/, $data);
+	while(@data)
+	{
+	    $num = shift @data;
+	    $name = shift @data;
+	    $href->{$num} = $name;
+	}
+    }
+    $retval;
+}
+
+sub GetCounterHelp
+{
+    my($machine,$href) = @_;
+    if(ref $href ne "HASH")
+    {
+	croak("usage: Win32::PerfLib::GetCounterHelp(machine,hashRef)\n");
+    }
+    my($data,@data,$num,$name);
+    my $retval = PerfLibGetHelp($machine,$data);
+    if($retval)
+    {
+	@data = split(/\0/, $data);
+	while(@data)
+	{
+	    $num = shift @data;
+	    $name = shift @data;
+	    $href->{$num} = $name;
+	}
+    }
+    $retval;
+}
+
+sub GetObjectList
+{
+    my $self = shift;
+    my $object = shift;
+    my $data = shift;
+    if(ref $data ne "HASH")
+    {
+	croak("reference isn't a hash reference!\n");
+    }
+    return PerfLibGetObjects($self->{handle}, $object, $data);
+}
+
+sub GetCounterType
+{
+    my $type = shift;
+    my $retval;
+    if( &Win32::PerfLib::PERF_100NSEC_MULTI_TIMER == $type )
+    {
+	$retval = "PERF_100NSEC_MULTI_TIMER";
+    }
+    elsif( &Win32::PerfLib::PERF_100NSEC_MULTI_TIMER_INV == $type )
+    {
+	$retval = "PERF_100NSEC_MULTI_TIMER_INV";
+    }
+    elsif( &Win32::PerfLib::PERF_100NSEC_TIMER == $type )
+    {
+	$retval = "PERF_100NSEC_TIMER";
+    }
+    elsif( &Win32::PerfLib::PERF_100NSEC_TIMER_INV == $type )
+    {
+	$retval = "PERF_100NSEC_TIMER_INV";
+    }
+    elsif( &Win32::PerfLib::PERF_AVERAGE_BASE == $type )
+    {
+	$retval = "PERF_AVERAGE_BASE";
+    }
+    elsif( &Win32::PerfLib::PERF_AVERAGE_BULK == $type )
+    {
+	$retval = "PERF_AVERAGE_BULK";
+    }
+    elsif( &Win32::PerfLib::PERF_AVERAGE_TIMER == $type )
+    {
+	$retval = "PERF_AVERAGE_TIMER";
+    }
+    elsif( &Win32::PerfLib::PERF_COUNTER_BULK_COUNT == $type )
+    {
+	$retval = "PERF_COUNTER_BULK_COUNT";
+    }
+    elsif( &Win32::PerfLib::PERF_COUNTER_COUNTER == $type )
+    {
+	$retval = "PERF_COUNTER_COUNTER";
+    }
+    elsif( &Win32::PerfLib::PERF_COUNTER_DELTA == $type )
+    {
+	$retval = "PERF_COUNTER_DELTA";
+    }
+    elsif( &Win32::PerfLib::PERF_COUNTER_LARGE_DELTA == $type )
+    {
+	$retval = "PERF_COUNTER_LARGE_DELTA";
+    }
+    elsif( &Win32::PerfLib::PERF_COUNTER_LARGE_QUEUELEN_TYPE == $type )
+    {
+	$retval = "PERF_COUNTER_LARGE_QUEUELEN_TYPE";
+    }
+    elsif( &Win32::PerfLib::PERF_COUNTER_LARGE_RAWCOUNT == $type )
+    {
+	$retval = "PERF_COUNTER_LARGE_RAWCOUNT";
+    }
+    elsif( &Win32::PerfLib::PERF_COUNTER_LARGE_RAWCOUNT_HEX == $type )
+    {
+	$retval = "PERF_COUNTER_LARGE_RAWCOUNT_HEX";
+    }
+    elsif( &Win32::PerfLib::PERF_COUNTER_MULTI_BASE == $type )
+    {
+	$retval = "PERF_COUNTER_MULTI_BASE";
+    }
+    elsif( &Win32::PerfLib::PERF_COUNTER_MULTI_TIMER == $type )
+    {
+	$retval = "PERF_COUNTER_MULTI_TIMER";
+    }
+    elsif( &Win32::PerfLib::PERF_COUNTER_MULTI_TIMER_INV == $type )
+    {
+	$retval = "PERF_COUNTER_MULTI_TIMER_INV";
+    }
+    elsif( &Win32::PerfLib::PERF_COUNTER_NODATA == $type )
+    {
+	$retval = "PERF_COUNTER_NODATA";
+    }
+    elsif( &Win32::PerfLib::PERF_COUNTER_QUEUELEN_TYPE == $type )
+    {
+	$retval = "PERF_COUNTER_QUEUELEN_TYPE";
+    }
+    elsif( &Win32::PerfLib::PERF_COUNTER_RAWCOUNT == $type )
+    {
+	$retval = "PERF_COUNTER_RAWCOUNT";
+    }
+    elsif( &Win32::PerfLib::PERF_COUNTER_RAWCOUNT_HEX == $type )
+    {
+	$retval = "PERF_COUNTER_RAWCOUNT_HEX";
+    }
+    elsif( &Win32::PerfLib::PERF_COUNTER_TEXT == $type )
+    {
+	$retval = "PERF_COUNTER_TEXT";
+    }
+    elsif( &Win32::PerfLib::PERF_COUNTER_TIMER == $type )
+    {
+	$retval = "PERF_COUNTER_TIMER";
+    }
+    elsif( &Win32::PerfLib::PERF_COUNTER_TIMER_INV == $type )
+    {
+	$retval = "PERF_COUNTER_TIMER_INV";
+    }
+    elsif( &Win32::PerfLib::PERF_ELAPSED_TIME == $type )
+    {
+	$retval = "PERF_ELAPSED_TIME";
+    }
+    elsif( &Win32::PerfLib::PERF_RAW_BASE == $type )
+    {
+	$retval = "PERF_RAW_BASE";
+    }
+    elsif( &Win32::PerfLib::PERF_RAW_FRACTION == $type )
+    {
+	$retval = "PERF_RAW_FRACTION";
+    }
+    elsif( &Win32::PerfLib::PERF_SAMPLE_BASE == $type )
+    {
+	$retval = "PERF_SAMPLE_BASE";
+    }
+    elsif( &Win32::PerfLib::PERF_SAMPLE_COUNTER == $type )
+    {
+	$retval = "PERF_SAMPLE_COUNTER";
+    }
+    elsif( &Win32::PerfLib::PERF_SAMPLE_FRACTION == $type )
+    {
+	$retval = "PERF_SAMPLE_FRACTION";
+    }
+    $retval;
+}
+
+
+
+1;
+__END__
+
+=head1 NAME
+
+Win32::PerfLib - accessing the Windows NT Performance Counter
+
+=head1 SYNOPSIS
+
+  use Win32::PerfLib;
+  my $server = "";
+  Win32::PerfLib::GetCounterNames($server, \%counter);
+  %r_counter = map { $counter{$_} => $_ } keys %counter;
+  # retrieve the id for process object
+  $process_obj = $r_counter{Process};
+  # retrieve the id for the process ID counter
+  $process_id = $r_counter{'ID Process'};
+
+  # create connection to $server
+  $perflib = new Win32::PerfLib($server);
+  $proc_ref = {};
+  # get the performance data for the process object
+  $perflib->GetObjectList($process_obj, $proc_ref);
+  $perflib->Close();
+  $instance_ref = $proc_ref->{Objects}->{$process_obj}->{Instances};
+  foreach $p (sort keys %{$instance_ref})
+  {
+      $counter_ref = $instance_ref->{$p}->{Counters};
+      foreach $i (keys %{$counter_ref})
+      {
+	  if($counter_ref->{$i}->{CounterNameTitleIndex} == $process_id)
+	  {
+	      printf( "% 6d %s\n", $counter_ref->{$i}->{Counter},
+		      $instance_ref->{$p}->{Name}
+		    );
+	  }
+      }
+  }
+
+=head1 DESCRIPTION
+
+This module allows to retrieve the performance counter of any computer
+(running Windows NT) in the network.
+
+=head1 FUNCTIONS
+
+=head2 NOTE
+
+All of the functions return false if they fail, unless otherwise noted.
+If the $server argument is undef the local machine is assumed.
+
+=over 10
+
+=item Win32::PerfLib::GetCounterNames($server,$hashref)
+
+Retrieves the counter names and their indices from the registry and stores them
+in the hash reference
+
+=item Win32::PerfLib::GetCounterHelp($server,$hashref)
+
+Retrieves the counter help strings and their indices from the registry and
+stores them in the hash reference
+
+=item $perflib = Win32::PerfLib->new ($server)
+
+Creates a connection to the performance counters of the given server
+
+=item $perflib->GetObjectList($objectid,$hashref)
+
+retrieves the object and counter list of the given performance object.
+
+=item $perflib->Close($hashref)
+
+closes the connection to the performance counters
+
+=item Win32::PerfLib::GetCounterType(countertype)
+
+converts the counter type to readable string as referenced in L<calc.html> so
+that it is easier to find the appropriate formula to calculate the raw counter
+data.
+
+=back
+
+=head1 Datastructures
+
+The performance data is returned in the following data structure:
+
+=over 10
+
+=item Level 1
+
+  $hashref = {
+      'NumObjectTypes'   => VALUE
+      'Objects'          => HASHREF
+      'PerfFreq'         => VALUE
+      'PerfTime'         => VALUE
+      'PerfTime100nSec'  => VALUE
+      'SystemName'       => STRING
+      'SystemTime'       => VALUE
+  }
+
+=item Level 2
+
+The hash reference $hashref->{Objects} has the returned object ID(s) as keys and
+a hash reference to the object counter data as value. Even there is only one
+object requested in the call to GetObjectList there may be more than one object
+in the result.
+
+  $hashref->{Objects} = {
+      <object1>  => HASHREF
+      <object2>  => HASHREF
+      ...
+  }
+
+=item Level 3
+
+Each returned object ID has object-specific performance information. If an
+object has instances like the process object there is also a reference to
+the instance information.
+
+  $hashref->{Objects}->{<object1>} = {
+      'DetailLevel'           => VALUE
+      'Instances'             => HASHREF
+      'Counters'              => HASHREF
+      'NumCounters'           => VALUE
+      'NumInstances'          => VALUE
+      'ObjectHelpTitleIndex'  => VALUE
+      'ObjectNameTitleIndex'  => VALUE
+      'PerfFreq'              => VALUE
+      'PerfTime'              => VALUE
+  }
+
+=item Level 4
+
+If there are instance information for the object available they are stored in
+the 'Instances' hashref. If the object has no instances there is an 'Counters'
+key instead. The instances or counters are numbered.
+
+  $hashref->{Objects}->{<object1>}->{Instances} = {
+      <1>     => HASHREF
+      <2>     => HASHREF
+      ...
+      <n>     => HASHREF
+  }
+  or
+  $hashref->{Objects}->{<object1>}->{Counters} = {
+      <1>     => HASHREF
+      <2>     => HASHREF
+      ...
+      <n>     => HASHREF
+  }
+
+=item Level 5
+
+  $hashref->{Objects}->{<object1>}->{Instances}->{<1>} = {
+      Counters               => HASHREF
+      Name                   => STRING
+      ParentObjectInstance   => VALUE
+      ParentObjectTitleIndex => VALUE
+  }
+  or
+  $hashref->{Objects}->{<object1>}->{Counters}->{<1>} = {
+      Counter               => VALUE
+      CounterHelpTitleIndex => VALUE
+      CounterNameTitleIndex => VALUE
+      CounterSize           => VALUE
+      CounterType           => VALUE
+      DefaultScale          => VALUE
+      DetailLevel           => VALUE
+      Display               => STRING
+  }
+
+=item Level 6
+
+  $hashref->{Objects}->{<object1>}->{Instances}->{<1>}->{Counters} = {
+      <1>     => HASHREF
+      <2>     => HASHREF
+      ...
+      <n>     => HASHREF
+  }
+
+=item Level 7
+
+  $hashref->{Objects}->{<object1>}->{Instances}->{<1>}->{Counters}->{<1>} = {
+      Counter               => VALUE
+      CounterHelpTitleIndex => VALUE
+      CounterNameTitleIndex => VALUE
+      CounterSize           => VALUE
+      CounterType           => VALUE
+      DefaultScale          => VALUE
+      DetailLevel           => VALUE
+      Display               => STRING
+  }
+
+Depending on the B<CounterType> there are calculations to do (see calc.html).
+
+=back
+
+=head1 AUTHOR
+
+Jutta M. Klebe, jmk@bybyte.de
+
+=head1 SEE ALSO
+
+perl(1).
+
+=cut
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Pipe.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Pipe.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Pipe.pm	(revision 14139)
@@ -0,0 +1,413 @@
+package Win32::Pipe;
+
+$VERSION = '0.022';
+
+# Win32::Pipe.pm
+#       +==========================================================+
+#       |                                                          |
+#       |                     PIPE.PM package                      |
+#       |                     ---------------                      |
+#       |                    Release v96.05.11                     |
+#       |                                                          |
+#       |    Copyright (c) 1996 Dave Roth. All rights reserved.    |
+#       |   This program is free software; you can redistribute    |
+#       | it and/or modify it under the same terms as Perl itself. |
+#       |                                                          |
+#       +==========================================================+
+#
+#
+#	Use under GNU General Public License or Larry Wall's "Artistic License"
+#
+#	Check the README.TXT file that comes with this package for details about
+#	it's history.
+#
+
+require Exporter;
+require DynaLoader;
+
+@ISA= qw( Exporter DynaLoader );
+    # Items to export into callers namespace by default. Note: do not export
+    # names by default without a very good reason. Use EXPORT_OK instead.
+    # Do not simply export all your public functions/methods/constants.
+@EXPORT = qw();
+
+$ErrorNum = 0;
+$ErrorText = "";
+
+sub new
+{
+    my ($self, $Pipe);
+    my ($Type, $Name, $Time) = @_;
+
+    if (! $Time){
+        $Time = DEFAULT_WAIT_TIME;
+    }
+    $Pipe = PipeCreate($Name, $Time);
+    if ($Pipe){
+        $self = bless {};
+        $self->{'Pipe'} = $Pipe;
+    }else{
+        ($ErrorNum, $ErrorText) = PipeError();
+        return undef;
+    }
+    $self;
+}
+
+sub Write{
+    my($self, $Data) = @_;
+    $Data = PipeWrite($self->{'Pipe'}, $Data);
+    return $Data;
+}
+
+sub Read{
+    my($self) = @_;
+    my($Data);
+    $Data = PipeRead($self->{'Pipe'});
+    return $Data;
+}
+
+sub Error{
+    my($self) = @_;
+    my($MyError, $MyErrorText, $Temp);
+    if (! ref($self)){
+        undef $Temp;
+    }else{
+        $Temp = $self->{'Pipe'};
+    }
+    ($MyError, $MyErrorText) = PipeError($Temp);
+    return wantarray? ($MyError, $MyErrorText):"[$MyError] \"$MyErrorText\"";
+}
+
+
+sub Close{
+    my ($self) = shift;
+    PipeClose($self->{'Pipe'});
+}
+
+sub Connect{
+    my ($self) = @_;
+    my ($Result);
+    $Result = PipeConnect($self->{'Pipe'});
+    return $Result;
+}
+
+sub Disconnect{
+    my ($self, $iPurge) = @_;
+    my ($Result);
+    if (! $iPurge){
+        $iPurge = 1;
+    }
+    $Result = PipeDisconnect($self->{'Pipe'}, $iPurge);
+    return $Result;
+}
+
+sub BufferSize{
+    my($self) = @_;
+    my($Result) =  PipeBufferSize($self->{'Pipe'});
+    return $Result;
+}
+
+sub ResizeBuffer{
+    my($self, $Size) = @_;
+    my($Result) = PipeResizeBuffer($self->{'Pipe'}, $Size);
+    return $Result;
+}
+
+
+####
+#   Auto-Kill an instance of this module
+####
+sub DESTROY
+{
+    my ($self) = shift;
+    Close($self);
+}
+
+
+sub Credit{
+    my($Name, $Version, $Date, $Author, $CompileDate, $CompileTime, $Credits) = Win32::Pipe::Info();
+    my($Out, $iWidth);
+    $iWidth = 60;
+    $Out .=  "\n";
+    $Out .=  "  +". "=" x ($iWidth). "+\n";
+    $Out .=  "  |". Center("", $iWidth). "|\n";
+    $Out .=  "  |" . Center("", $iWidth). "|\n";
+    $Out .=  "  |". Center("$Name", $iWidth). "|\n";
+    $Out .=  "  |". Center("-" x length("$Name"), $iWidth). "|\n";
+    $Out .=  "  |". Center("", $iWidth). "|\n";
+
+    $Out .=  "  |". Center("Version $Version ($Date)", $iWidth). "|\n";
+    $Out .=  "  |". Center("by $Author", $iWidth). "|\n";
+    $Out .=  "  |". Center("Compiled on $CompileDate at $CompileTime.", $iWidth). "|\n";
+    $Out .=  "  |". Center("", $iWidth). "|\n";
+    $Out .=  "  |". Center("Credits:", $iWidth). "|\n";
+    $Out .=  "  |". Center(("-" x length("Credits:")), $iWidth). "|\n";
+    foreach $Temp (split("\n", $Credits)){
+        $Out .=  "  |". Center("$Temp", $iWidth). "|\n";
+    }
+    $Out .=  "  |". Center("", $iWidth). "|\n";
+    $Out .=  "  +". "=" x ($iWidth). "+\n";
+    return $Out;
+}
+
+sub Center{
+    local($Temp, $Width) = @_;
+    local($Len) = ($Width - length($Temp)) / 2;
+    return " " x int($Len) . $Temp . " " x (int($Len) + (($Len != int($Len))? 1:0));
+}
+
+# ------------------ A U T O L O A D   F U N C T I O N ---------------------
+
+sub AUTOLOAD {
+    # This AUTOLOAD is used to 'autoload' constants from the constant()
+    # XS function.  If a constant is not found then control is passed
+    # to the AUTOLOAD in AutoLoader.
+
+    my($constname);
+    ($constname = $AUTOLOAD) =~ s/.*:://;
+    #reset $! to zero to reset any current errors.
+    local $! = 0;
+    $val = constant($constname, @_ ? $_[0] : 0);
+
+    if ($! != 0) {
+    if ($! =~ /Invalid/) {
+        $AutoLoader::AUTOLOAD = $AUTOLOAD;
+        goto &AutoLoader::AUTOLOAD;
+    }
+    else {
+
+            # Added by JOC 06-APR-96
+            # $pack = 0;
+        $pack = 0;
+        ($pack,$file,$line) = caller;
+            print "Your vendor has not defined Win32::Pipe macro $constname, used in $file at line $line.";
+    }
+    }
+    eval "sub $AUTOLOAD { $val }";
+    goto &$AUTOLOAD;
+}
+
+bootstrap Win32::Pipe;
+
+1;
+__END__
+
+=head1 NAME
+
+Win32::Pipe - Win32 Named Pipe
+
+=head1 SYNOPSIS
+
+To use this extension, follow these basic steps. First, you need to
+'use' the pipe extension:
+
+    use Win32::Pipe;
+
+Then you need to create a server side of a named pipe:
+
+    $Pipe = new Win32::Pipe("My Pipe Name");
+
+or if you are going to connect to pipe that has already been created:
+
+    $Pipe = new Win32::Pipe("\\\\server\\pipe\\My Pipe Name");
+
+    NOTE: The "\\\\server\\pipe\\" is necessary when connecting
+          to an existing pipe! If you are accessing the same
+          machine you could use "\\\\.\\pipe\\" but either way
+          works fine.
+
+You should check to see if C<$Pipe> is indeed defined otherwise there
+has been an error.
+
+Whichever end is the server, it must now wait for a connection...
+
+    $Result = $Pipe->Connect();
+
+    NOTE: The client end does not do this! When the client creates
+          the pipe it has already connected!
+
+Now you can read and write data from either end of the pipe:
+
+    $Data = $Pipe->Read();
+
+    $Result = $Pipe->Write("Howdy! This is cool!");
+
+When the server is finished it must disconnect:
+
+    $Pipe->Disconnect();
+
+Now the server could C<Connect> again (and wait for another client) or
+it could destroy the named pipe...
+
+    $Data->Close();
+
+The client should C<Close> in order to properly end the session.
+
+=head1 DESCRIPTION
+
+=head2 General Use
+
+This extension gives Win32 Perl the ability to use Named Pipes. Why?
+Well considering that Win32 Perl does not (yet) have the ability to
+C<fork> I could not see what good the C<pipe(X,Y)> was. Besides, where
+I am as an admin I must have several perl daemons running on several
+NT Servers. It dawned on me one day that if I could pipe all these
+daemons' output to my workstation (across the net) then it would be
+much easier to monitor. This was the impetus for an extension using
+Named Pipes. I think that it is kinda cool. :)
+
+=head2 Benefits
+
+And what are the benefits of this module?
+
+=over
+
+=item *
+
+You may create as many named pipes as you want (uh, well, as many as
+your resources will allow).
+
+=item *
+
+Currently there is a limit of 256 instances of a named pipe (once a
+pipe is created you can have 256 client/server connections to that
+name).
+
+=item *
+
+The default buffer size is 512 bytes; this can be altered by the
+C<ResizeBuffer> method.
+
+=item *
+
+All named pipes are byte streams. There is currently no way to alter a
+pipe to be message based.
+
+=item *
+
+Other things that I cannot think of right now... :)
+
+=back
+
+=head1 CONSTRUCTOR
+
+=over
+
+=item new ( NAME )
+
+Creates a named pipe if used in server context or a connection to the
+specified named pipe if used in client context. Client context is
+determined by prepending $Name with "\\\\".
+
+Returns I<true> on success, I<false> on failure.
+
+=back
+
+=head1 METHODS
+
+=over
+
+=item BufferSize ()
+
+Returns the size of the instance of the buffer of the named pipe.
+
+=item Connect ()
+
+Tells the named pipe to create an instance of the named pipe and wait
+until a client connects. Returns I<true> on success, I<false> on
+failure.
+
+=item Close ()
+
+Closes the named pipe.
+
+=item Disconnect ()
+
+Disconnects (and destroys) the instance of the named pipe from the
+client. Returns I<true> on success, I<false> on failure.
+
+=item Error ()
+
+Returns the last error messages pertaining to the named pipe. If used
+in context to the package. Returns a list containing C<ERROR_NUMBER>
+and C<ERROR_TEXT>.
+
+=item Read ()
+
+Reads from the named pipe. Returns data read from the pipe on success,
+undef on failure.
+
+=item ResizeBuffer ( SIZE )
+
+Sets the size of the buffer of the instance of the named pipe to
+C<SIZE>. Returns the size of the buffer on success, I<false> on
+failure.
+
+=item Write ( DATA )
+
+Writes C<DATA> to the named pipe. Returns I<true> on success, I<false>
+on failure.
+
+=back
+
+=head1 LIMITATIONS
+
+What known problems does this thing have?
+
+=over
+
+=item *
+
+If someone is waiting on a C<Read> and the other end terminates then
+you will wait for one B<REALLY> long time! (If anyone has an idea on
+how I can detect the termination of the other end let me know!)
+
+=item *
+
+All pipes are blocking. I am considering using threads and callbacks
+into Perl to perform async IO but this may be too much for my time
+stress. ;)
+
+=item *
+
+There is no security placed on these pipes.
+
+=item *
+
+This module has neither been optimized for speed nor optimized for
+memory consumption. This may run into memory bloat.
+
+=back
+
+=head1 INSTALLATION NOTES
+
+If you wish to use this module with a build of Perl other than
+ActivePerl, you may wish to fetch the source distribution for this
+module. The source is included as part of the C<libwin32> bundle,
+which you can find in any CPAN mirror here:
+
+  modules/by-authors/Gurusamy_Sarathy/libwin32-0.151.tar.gz
+
+The source distribution also contains a pair of sample client/server
+test scripts. For the latest information on this module, consult the
+following web site:
+
+  http://www.roth.net/perl
+
+=head1 AUTHOR
+
+Dave Roth <rothd@roth.net>
+
+=head1 DISCLAIMER
+
+I do not guarantee B<ANYTHING> with this package. If you use it you
+are doing so B<AT YOUR OWN RISK>! I may or may not support this
+depending on my time schedule.
+
+=head1 COPYRIGHT
+
+Copyright (c) 1996 Dave Roth. All rights reserved.
+This program is free software; you can redistribute
+it and/or modify it under the same terms as Perl itself.
+
+=cut
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Process.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Process.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Process.pm	(revision 14139)
@@ -0,0 +1,197 @@
+package Win32::Process;
+
+require Exporter;
+require DynaLoader;
+@ISA = qw(Exporter DynaLoader);
+
+$VERSION = '0.09';
+
+# Items to export into callers namespace by default. Note: do not export
+# names by default without a very good reason. Use EXPORT_OK instead.
+# Do not simply export all your public functions/methods/constants.
+@EXPORT = qw(
+	CREATE_DEFAULT_ERROR_MODE
+	CREATE_NEW_CONSOLE
+	CREATE_NEW_PROCESS_GROUP
+	CREATE_NO_WINDOW
+	CREATE_SEPARATE_WOW_VDM
+	CREATE_SUSPENDED
+	CREATE_UNICODE_ENVIRONMENT
+	DEBUG_ONLY_THIS_PROCESS
+	DEBUG_PROCESS
+	DETACHED_PROCESS
+	HIGH_PRIORITY_CLASS
+	IDLE_PRIORITY_CLASS
+	INFINITE
+	NORMAL_PRIORITY_CLASS
+	REALTIME_PRIORITY_CLASS
+	THREAD_PRIORITY_ABOVE_NORMAL
+	THREAD_PRIORITY_BELOW_NORMAL
+	THREAD_PRIORITY_ERROR_RETURN
+	THREAD_PRIORITY_HIGHEST
+	THREAD_PRIORITY_IDLE
+	THREAD_PRIORITY_LOWEST
+	THREAD_PRIORITY_NORMAL
+	THREAD_PRIORITY_TIME_CRITICAL
+);
+
+sub AUTOLOAD {
+    # This AUTOLOAD is used to 'autoload' constants from the constant()
+    # XS function.
+    my($constname);
+    ($constname = $AUTOLOAD) =~ s/.*:://;
+    local $! = 0;
+    my $val = constant($constname);
+    if ($! != 0) {
+        my ($pack,$file,$line) = caller;
+        die "Your vendor has not defined Win32::Process macro $constname, used at $file line $line.";
+    }
+    eval "sub $AUTOLOAD { $val }";
+    goto &$AUTOLOAD;
+} # end AUTOLOAD
+
+bootstrap Win32::Process;
+
+1;
+__END__
+
+=head1 NAME
+
+Win32::Process - Create and manipulate processes.
+
+=head1 SYNOPSIS
+
+    use Win32::Process;
+    use Win32;
+
+    sub ErrorReport{
+	print Win32::FormatMessage( Win32::GetLastError() );
+    }
+
+    Win32::Process::Create($ProcessObj,
+				"C:\\winnt\\system32\\notepad.exe",
+				"notepad temp.txt",
+				0,
+				NORMAL_PRIORITY_CLASS,
+				".")|| die ErrorReport();
+
+    $ProcessObj->Suspend();
+    $ProcessObj->Resume();
+    $ProcessObj->Wait(INFINITE);
+
+=head1  DESCRIPTION
+
+This module provides access to the process control functions in the
+Win32 API.
+
+=head1 METHODS
+
+=over 8
+
+=item Win32::Process::Create($obj,$appname,$cmdline,$iflags,$cflags,$curdir)
+
+Creates a new process.
+
+    Args:
+
+	$obj		container for process object
+	$appname	full path name of executable module
+	$cmdline	command line args
+	$iflags		flag: inherit calling processes handles or not
+	$cflags		flags for creation (see exported vars below)
+	$curdir		working dir of new process
+
+Returns non-zero on success, 0 on failure.
+
+=item Win32::Process::Open($obj,$pid,$iflags)
+
+Creates a handle Perl can use to an existing process as identified by $pid.
+The $iflags is the inherit flag that is passed to OpenProcess.  Currently
+Win32::Process objects created using Win32::Process::Open cannot Suspend
+or Resume the process.  All other calls should work.
+
+Win32::Process::Open returns non-zero on success, 0 on failure.
+
+=item Win32::Process::KillProcess($pid, $exitcode)
+
+Terminates any process identified by $pid.  $exitcode will be set to
+the exit code of the process.
+
+=item $ProcessObj->Suspend()
+
+Suspend the process associated with the $ProcessObj.
+
+=item $ProcessObj->Resume()
+
+Resume a suspended process.
+
+=item $ProcessObj->Kill($exitcode)
+
+Kill the associated process, have it terminate with exit code $ExitCode.
+
+=item $ProcessObj->GetPriorityClass($class)
+
+Get the priority class of the process.
+
+=item $ProcessObj->SetPriorityClass($class)
+
+Set the priority class of the process (see exported values below for
+options).
+
+=item $ProcessObj->GetProcessAffinityMask($processAffinityMask, $systemAffinityMask)
+
+Get the process affinity mask.  This is a bitvector in which each bit
+represents the processors that a process is allowed to run on.
+
+=item $ProcessObj->SetProcessAffinityMask($processAffinityMask)
+
+Set the process affinity mask.  Only available on Windows NT.
+
+=item $ProcessObj->GetExitCode($exitcode)
+
+Retrieve the exitcode of the process.
+
+=item $ProcessObj->Wait($timeout)
+
+Wait for the process to die.  $timeout should be specified in milliseconds.
+To wait forever, specify the constant C<INFINITE>.
+
+=item $ProcessObj->GetProcessID()
+
+Returns the Process ID.
+
+=back
+
+=head1 EXPORTS
+
+The following constants are exported by default.
+
+	CREATE_DEFAULT_ERROR_MODE
+	CREATE_NEW_CONSOLE
+	CREATE_NEW_PROCESS_GROUP
+	CREATE_NO_WINDOW
+	CREATE_SEPARATE_WOW_VDM
+	CREATE_SUSPENDED
+	CREATE_UNICODE_ENVIRONMENT
+	DEBUG_ONLY_THIS_PROCESS
+	DEBUG_PROCESS
+	DETACHED_PROCESS
+	HIGH_PRIORITY_CLASS
+	IDLE_PRIORITY_CLASS
+	INFINITE
+	NORMAL_PRIORITY_CLASS
+	REALTIME_PRIORITY_CLASS
+	THREAD_PRIORITY_ABOVE_NORMAL
+	THREAD_PRIORITY_BELOW_NORMAL
+	THREAD_PRIORITY_ERROR_RETURN
+	THREAD_PRIORITY_HIGHEST
+	THREAD_PRIORITY_IDLE
+	THREAD_PRIORITY_LOWEST
+	THREAD_PRIORITY_NORMAL
+	THREAD_PRIORITY_TIME_CRITICAL
+
+=cut
+
+# Local Variables:
+# tmtrack-file-task: "Win32::Process"
+# End:
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Registry.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Registry.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Registry.pm	(revision 14139)
@@ -0,0 +1,545 @@
+package Win32::Registry;
+
+=head1 NAME
+
+Win32::Registry - accessing the Windows registry [obsolete, use Win32::TieRegistry]
+
+=head1 SYNOPSIS
+
+    use Win32::Registry;
+    my $tips;
+    $::HKEY_LOCAL_MACHINE->Open("SOFTWARE\\Microsoft\\Windows"
+                               ."\\CurrentVersion\\Explorer\\Tips", $tips)
+        or die "Can't open tips: $^E";
+    my ($type, $value);
+    $tips->QueryValueEx("18", $type, $value) or die "No tip #18: $^E";
+    print "Here's a tip: $value\n";
+
+=head1 DESCRIPTION
+
+    NOTE: This module provides a very klunky interface to access the
+    Windows registry, and is not currently being developed actively.  It
+    only exists for backward compatibility with old code that uses it.
+    For more powerful and flexible ways to access the registry, use
+    Win32::TieRegistry.
+
+Win32::Registry provides an object oriented interface to the Windows
+Registry.
+
+The following "root" registry objects are exported to the main:: name
+space.  Additional keys must be opened by calling the provided methods
+on one of these.
+
+    $HKEY_CLASSES_ROOT
+    $HKEY_CURRENT_USER
+    $HKEY_LOCAL_MACHINE
+    $HKEY_USERS
+    $HKEY_PERFORMANCE_DATA
+    $HKEY_CURRENT_CONFIG
+    $HKEY_DYN_DATA
+
+=cut
+
+use strict;
+require Exporter;
+require DynaLoader;
+use Win32::WinError;
+
+use vars qw($VERSION $AUTOLOAD @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
+
+$VERSION = '0.07';
+
+@ISA	= qw( Exporter DynaLoader );
+@EXPORT = qw(
+	HKEY_CLASSES_ROOT
+	HKEY_CURRENT_USER
+	HKEY_LOCAL_MACHINE
+	HKEY_PERFORMANCE_DATA
+	HKEY_CURRENT_CONFIG
+	HKEY_DYN_DATA
+	HKEY_USERS
+	KEY_ALL_ACCESS
+	KEY_CREATE_LINK
+	KEY_CREATE_SUB_KEY
+	KEY_ENUMERATE_SUB_KEYS
+	KEY_EXECUTE
+	KEY_NOTIFY
+	KEY_QUERY_VALUE
+	KEY_READ
+	KEY_SET_VALUE
+	KEY_WRITE
+	REG_BINARY
+	REG_CREATED_NEW_KEY
+	REG_DWORD
+	REG_DWORD_BIG_ENDIAN
+	REG_DWORD_LITTLE_ENDIAN
+	REG_EXPAND_SZ
+	REG_FULL_RESOURCE_DESCRIPTOR
+	REG_LEGAL_CHANGE_FILTER
+	REG_LEGAL_OPTION
+	REG_LINK
+	REG_MULTI_SZ
+	REG_NONE
+	REG_NOTIFY_CHANGE_ATTRIBUTES
+	REG_NOTIFY_CHANGE_LAST_SET
+	REG_NOTIFY_CHANGE_NAME
+	REG_NOTIFY_CHANGE_SECURITY
+	REG_OPENED_EXISTING_KEY
+	REG_OPTION_BACKUP_RESTORE
+	REG_OPTION_CREATE_LINK
+	REG_OPTION_NON_VOLATILE
+	REG_OPTION_RESERVED
+	REG_OPTION_VOLATILE
+	REG_REFRESH_HIVE
+	REG_RESOURCE_LIST
+	REG_RESOURCE_REQUIREMENTS_LIST
+	REG_SZ
+	REG_WHOLE_HIVE_VOLATILE
+);
+
+@EXPORT_OK = qw(
+    RegCloseKey
+    RegConnectRegistry
+    RegCreateKey
+    RegCreateKeyEx
+    RegDeleteKey
+    RegDeleteValue
+    RegEnumKey
+    RegEnumValue
+    RegFlushKey
+    RegGetKeySecurity
+    RegLoadKey
+    RegNotifyChangeKeyValue
+    RegOpenKey
+    RegOpenKeyEx
+    RegQueryInfoKey
+    RegQueryValue
+    RegQueryValueEx
+    RegReplaceKey
+    RegRestoreKey
+    RegSaveKey
+    RegSetKeySecurity
+    RegSetValue
+    RegSetValueEx
+    RegUnLoadKey
+);
+$EXPORT_TAGS{ALL}= \@EXPORT_OK;
+
+bootstrap Win32::Registry;
+
+sub import {
+    my $pkg = shift;
+    if ($_[0] && "Win32" eq $_[0]) {
+	Exporter::export($pkg, "Win32", @EXPORT_OK);
+	shift;
+    }
+    Win32::Registry->export_to_level(1+$Exporter::ExportLevel, $pkg, @_);
+}
+
+#######################################################################
+# This AUTOLOAD is used to 'autoload' constants from the constant()
+# XS function.  If a constant is not found then control is passed
+# to the AUTOLOAD in AutoLoader.
+
+sub AUTOLOAD {
+    my($constname);
+    ($constname = $AUTOLOAD) =~ s/.*:://;
+    #reset $! to zero to reset any current errors.
+    local $! = 0;
+    my $val = constant($constname, 0);
+    if ($! != 0) {
+	if ($! =~ /Invalid/) {
+	    $AutoLoader::AUTOLOAD = $AUTOLOAD;
+	    goto &AutoLoader::AUTOLOAD;
+	}
+	else {
+	    my ($pack,$file,$line) = caller;
+	    die "Unknown constant $constname in Win32::Registry "
+	       . "at $file line $line.\n";
+	}
+    }
+    eval "sub $AUTOLOAD { $val }";
+    goto &$AUTOLOAD;
+}
+
+#######################################################################
+# _new is a private constructor, not intended for public use.
+#
+
+sub _new {
+    my $self;
+    if ($_[0]) {
+	$self->{'handle'} = $_[0];
+	bless $self;
+    }
+    $self;
+}
+
+#define the basic registry objects to be exported.
+#these had to be hardwired unfortunately.
+# XXX Yuck!
+
+{
+    package main;
+    use vars qw(
+		$HKEY_CLASSES_ROOT
+		$HKEY_CURRENT_USER
+		$HKEY_LOCAL_MACHINE
+		$HKEY_USERS
+		$HKEY_PERFORMANCE_DATA
+		$HKEY_CURRENT_CONFIG
+		$HKEY_DYN_DATA
+	       );
+}
+
+$::HKEY_CLASSES_ROOT		= _new(&HKEY_CLASSES_ROOT);
+$::HKEY_CURRENT_USER		= _new(&HKEY_CURRENT_USER);
+$::HKEY_LOCAL_MACHINE		= _new(&HKEY_LOCAL_MACHINE);
+$::HKEY_USERS			= _new(&HKEY_USERS);
+$::HKEY_PERFORMANCE_DATA	= _new(&HKEY_PERFORMANCE_DATA);
+$::HKEY_CURRENT_CONFIG		= _new(&HKEY_CURRENT_CONFIG);
+$::HKEY_DYN_DATA		= _new(&HKEY_DYN_DATA);
+
+=head2 Methods
+
+The following methods are supported.  Note that subkeys can be
+specified as a path name, separated by backslashes (which may
+need to be doubled if you put them in double quotes).
+
+=over 8
+
+=item Open
+
+    $reg_obj->Open($sub_key_name, $sub_reg_obj);
+
+Opens a subkey of a registry object, returning the new registry object
+in $sub_reg_obj.
+
+=cut
+
+sub Open {
+    my $self = shift;
+    die 'usage: $obj->Open($sub_key_name, $sub_reg_obj)' if @_ != 2;
+    
+    my ($subkey) = @_;
+    my ($result,$subhandle);
+
+    $result = RegOpenKey($self->{'handle'},$subkey,$subhandle);
+    $_[1] = _new($subhandle);
+    
+    return 0 unless $_[1];
+    $! = Win32::GetLastError() unless $result;
+    return $result;
+}
+
+=item Close
+
+    $reg_obj->Close();
+
+Closes an open registry key.
+
+=cut
+
+sub Close {
+    my $self = shift;
+    die 'usage: $obj->Close()' if @_ != 0;
+
+    return unless exists $self->{'handle'};
+    my $result = RegCloseKey($self->{'handle'});
+    if ($result) {
+	delete $self->{'handle'};
+    }
+    else {
+	$! = Win32::GetLastError();
+    }
+    return $result;
+}
+
+sub DESTROY {
+    my $self = shift;
+    return unless exists $self->{'handle'};
+    RegCloseKey($self->{'handle'});
+    delete $self->{'handle'};
+}
+
+
+=item Connect
+
+    $reg_obj->Connect($node_name, $new_reg_obj);
+
+Connects to a remote Registry on the node specified by $node_name,
+returning it in $new_reg_obj.  Returns false if it fails.
+
+=cut
+
+sub Connect {
+    my $self = shift;
+    die 'usage: $obj->Connect($node_name, $new_reg_obj)' if @_ != 2;
+     
+    my ($node) = @_;
+    my ($result,$subhandle);
+
+    $result = RegConnectRegistry ($node, $self->{'handle'}, $subhandle);
+    $_[1] = _new($subhandle);
+
+    return 0 unless $_[1];
+    $! = Win32::GetLastError() unless $result;
+    return $result;
+}  
+
+=item Create
+
+    $reg_obj->Create($sub_key_name, $new_reg_obj);
+
+Opens the subkey specified by $sub_key_name, returning the new registry
+object in $new_reg_obj.  If the specified subkey doesn't exist, it is
+created.
+
+=cut
+
+sub Create {
+    my $self = shift;
+    die 'usage: $obj->Create($sub_key_name, $new_reg_obj)' if @_ != 2;
+
+    my ($subkey) = @_;
+    my ($result,$subhandle);
+
+    $result = RegCreateKey($self->{'handle'},$subkey,$subhandle);
+    $_[1] = _new ($subhandle);
+
+    return 0 unless $_[1];
+    $! = Win32::GetLastError() unless $result;
+    return $result;
+}
+
+=item SetValue
+
+    $reg_obj->SetValue($sub_key_name, $type, $value);
+
+Sets the default value for a subkey specified by $sub_key_name.
+
+=cut
+
+sub SetValue {
+    my $self = shift;
+    die 'usage: $obj->SetValue($subkey, $type, $value)' if @_ != 3;
+    my $result = RegSetValue($self->{'handle'}, @_);
+    $! = Win32::GetLastError() unless $result;
+    return $result;
+}
+
+=item SetValueEx
+
+    $reg_obj->SetValueEx($value_name, $reserved, $type, $value);
+
+Sets the value for the value name identified by $value_name
+in the key specified by $reg_obj.
+
+=cut
+
+sub SetValueEx {
+    my $self = shift;
+    die 'usage: $obj->SetValueEx($value_name, $reserved, $type, $value)' if @_ != 4;
+    my $result = RegSetValueEx($self->{'handle'}, @_);
+    $! = Win32::GetLastError() unless $result;
+    return $result;
+}
+
+=item QueryValue
+
+    $reg_obj->QueryValue($sub_key_name, $value);
+
+Gets the default value of the subkey specified by $sub_key_name.
+
+=cut
+
+sub QueryValue {
+    my $self = shift;
+    die 'usage: $obj->QueryValue($sub_key_name, $value)' if @_ != 2;
+    my $result = RegQueryValue($self->{'handle'}, $_[0], $_[1]);
+    $! = Win32::GetLastError() unless $result;
+    return $result;
+}
+
+=item QueryKey
+
+    $reg_obj->QueryKey($classref, $number_of_subkeys, $number_of_values);
+
+Gets information on a key specified by $reg_obj.
+
+=cut
+
+sub QueryKey {
+    my $garbage;
+    my $self = shift;
+    die 'usage: $obj->QueryKey($classref, $number_of_subkeys, $number_of_values)'
+    	if @_ != 3;
+
+    my $result = RegQueryInfoKey($self->{'handle'}, $_[0],
+    				 $garbage, $garbage, $_[1],
+			         $garbage, $garbage, $_[2],
+			         $garbage, $garbage, $garbage, $garbage);
+
+    $! = Win32::GetLastError() unless $result;
+    return $result;
+}
+
+=item QueryValueEx
+
+    $reg_obj->QueryValueEx($value_name, $type, $value);
+
+Gets the value for the value name identified by $value_name
+in the key specified by $reg_obj.
+
+=cut
+
+sub QueryValueEx {
+    my $self = shift;
+    die 'usage: $obj->QueryValueEx($value_name, $type, $value)' if @_ != 3;
+    my $result = RegQueryValueEx($self->{'handle'}, $_[0], undef, $_[1], $_[2]);
+    $! = Win32::GetLastError() unless $result;
+    return $result;
+}
+
+=item GetKeys
+
+    my @keys;
+    $reg_obj->GetKeys(\@keys);
+
+Populates the supplied array reference with the names of all the keys
+within the registry object $reg_obj.
+
+=cut
+
+sub GetKeys {
+    my $self = shift;
+    die 'usage: $obj->GetKeys($arrayref)' if @_ != 1 or ref($_[0]) ne 'ARRAY';
+
+    my ($result, $i, $keyname);
+    $keyname = "DummyVal";
+    $i = 0;
+    $result = 1;
+    
+    while ( $result ) {
+	$result = RegEnumKey( $self->{'handle'},$i++, $keyname );
+	if ($result) {
+	    push( @{$_[0]}, $keyname );
+	}
+    }
+    return(1);
+}
+
+=item GetValues
+
+    my %values;
+    $reg_obj->GetValues(\%values);
+
+Populates the supplied hash reference with entries of the form
+
+    $value_name => [ $value_name, $type, $data ]
+
+for each value in the registry object $reg_obj.
+
+=cut
+
+sub GetValues {
+    my $self = shift;
+    die 'usage: $obj->GetValues($hashref)' if @_ != 1;
+
+    my ($result,$name,$type,$data,$i);
+    $name = "DummyVal";
+    $i = 0;
+    while ( $result=RegEnumValue( $self->{'handle'},
+				  $i++,
+				  $name,
+				  undef,
+				  $type,
+				  $data ))
+    {
+	$_[0]->{$name} = [ $name, $type, $data ];
+    }
+    return(1);
+}
+
+=item DeleteKey
+
+    $reg_obj->DeleteKey($sub_key_name);
+
+Deletes a subkey specified by $sub_key_name from the registry.
+
+=cut
+
+sub DeleteKey {
+    my $self = shift;
+    die 'usage: $obj->DeleteKey($sub_key_name)' if @_ != 1;
+    my $result = RegDeleteKey($self->{'handle'}, @_);
+    $! = Win32::GetLastError() unless $result;
+    return $result;
+}
+
+=item DeleteValue
+
+    $reg_obj->DeleteValue($value_name);
+
+Deletes a value identified by $value_name from the registry.
+
+=cut
+
+sub DeleteValue {
+    my $self = shift;
+    die 'usage: $obj->DeleteValue($value_name)' if @_ != 1;
+    my $result = RegDeleteValue($self->{'handle'}, @_);
+    $! = Win32::GetLastError() unless $result;
+    return $result;
+}
+
+=item Save
+
+    $reg_obj->Save($filename);
+
+Saves the hive specified by $reg_obj to a file.
+
+=cut
+
+sub Save {
+    my $self = shift;
+    die 'usage: $obj->Save($filename)' if @_ != 1;
+    my $result = RegSaveKey($self->{'handle'}, @_);
+    $! = Win32::GetLastError() unless $result;
+    return $result;
+}
+
+=item Load
+
+    $reg_obj->Load($sub_key_name, $file_name);
+
+Loads a key specified by $sub_key_name from a file.
+
+=cut
+
+sub Load {
+    my $self = shift;
+    die 'usage: $obj->Load($sub_key_name, $file_name)' if @_ != 2;
+    my $result = RegLoadKey($self->{'handle'}, @_);
+    $! = Win32::GetLastError() unless $result;
+    return $result;
+}
+
+=item UnLoad
+
+    $reg_obj->Unload($sub_key_name);
+
+Unloads a registry hive.
+
+=cut
+
+sub UnLoad {
+    my $self = shift;
+    die 'usage: $obj->UnLoad($sub_key_name)' if @_ != 1;
+    my $result = RegUnLoadKey($self->{'handle'}, @_);
+    $! = Win32::GetLastError() unless $result;
+    return $result;
+}
+
+1;
+__END__
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Semaphore.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Semaphore.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Semaphore.pm	(revision 14139)
@@ -0,0 +1,127 @@
+#---------------------------------------------------------------------
+package Win32::Semaphore;
+#
+# Copyright 1998 Christopher J. Madsen
+#
+# Created: 3 Feb 1998 from the ActiveWare version
+#   (c) 1995 Microsoft Corporation. All rights reserved.
+#       Developed by ActiveWare Internet Corp., http://www.ActiveWare.com
+#
+#   Other modifications (c) 1997 by Gurusamy Sarathy <gsar@activestate.com>
+#
+# Author: Christopher J. Madsen <chris_madsen@geocities.com>
+# Version: 1.00 (6-Feb-1998)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the same terms as Perl itself.
+#
+# 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 either the
+# GNU General Public License or the Artistic License for more details.
+#
+# Use Win32 semaphore objects for synchronization
+#---------------------------------------------------------------------
+
+$VERSION = '1.02';
+
+use Win32::IPC 1.00 '/./';      # Import everything
+require Exporter;
+require DynaLoader;
+
+@ISA = qw(Exporter DynaLoader Win32::IPC);
+@EXPORT_OK = qw(
+  wait_all wait_any
+);
+
+bootstrap Win32::Semaphore;
+
+sub Create  { $_[0] = new('Win32::Semaphore',@_[1..3]) }
+sub Open  { $_[0] = Win32::Semaphore->open($_[1]) }
+sub Release { &release }
+
+1;
+__END__
+
+=head1 NAME
+
+Win32::Semaphore - Use Win32 semaphore objects from Perl
+
+=head1 SYNOPSIS
+	require Win32::Semaphore;
+
+	$sem = Win32::Semaphore->new($initial,$maximum,$name);
+	$sem->wait;
+
+=head1 DESCRIPTION
+
+This module allows access to Win32 semaphore objects.  The C<wait>
+method and C<wait_all> & C<wait_any> functions are inherited from the
+L<"Win32::IPC"> module.
+
+=head2 Methods
+
+=over 4
+
+=item $semaphore = Win32::Semaphore->new($initial, $maximum, [$name])
+
+Constructor for a new semaphore object.  C<$initial> is the initial
+count, and C<$maximum> is the maximum count for the semaphore.  If
+C<$name> is omitted, creates an unnamed semaphore object.
+
+If C<$name> signifies an existing semaphore object, then C<$initial>
+and C<$maximum> are ignored and the object is opened.
+
+=item $semaphore = Win32::Semaphore->open($name)
+
+Constructor for opening an existing semaphore object.
+
+=item $semaphore->release([$increment, [$previous]])
+
+Increment the count of C<$semaphore> by C<$increment> (default 1).
+If C<$increment> plus the semaphore's current count is more than its
+maximum count, the count is not changed.  Returns true if the
+increment is successful.
+
+The semaphore's count (before incrementing) is stored in the second
+argument (if any).
+
+It is not necessary to wait on a semaphore before calling C<release>,
+but you'd better know what you're doing.
+
+=item $semaphore->wait([$timeout])
+
+Wait for C<$semaphore>'s count to be nonzero, then decrement it by 1.
+See L<"Win32::IPC">.
+
+=back
+
+=head2 Deprecated Functions and Methods
+
+B<Win32::Semaphore> still supports the ActiveWare syntax, but its use
+is deprecated.
+
+=over 4
+
+=item Win32::Semaphore::Create($SemObject,$Initial,$Max,$Name)
+
+Use C<$SemObject = Win32::Semaphore-E<gt>new($Initial,$Max,$Name)> instead.
+
+=item Win32::Semaphore::Open($SemObject, $Name)
+
+Use C<$SemObject = Win32::Semaphore-E<gt>open($Name)> instead.
+
+=item $SemObj->Release($Count,$LastVal)
+
+Use C<$SemObj-E<gt>release($Count,$LastVal)> instead.
+
+=back
+
+=head1 AUTHOR
+
+Christopher J. Madsen E<lt>F<chris_madsen@geocities.com>E<gt>
+
+Loosely based on the original module by ActiveWare Internet Corp.,
+F<http://www.ActiveWare.com>
+
+=cut
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Server.pl
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Server.pl	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Server.pl	(revision 14139)
@@ -0,0 +1,51 @@
+
+    use Win32::Pipe;
+
+
+    $PipeName = "TEST this long named pipe!";
+    $NewSize = 2048;
+
+    $iFlag = 1;
+    while($iFlag){
+        print "Creating pipe \"$PipeName\".\n";
+        if($Pipe = new Win32::Pipe($PipeName)){
+            $PipeSize = $Pipe->BufferSize();
+            print "This pipe's current size is $PipeSize byte" . (($PipeSize == 1)? "":"s") . ".\nWe shall change it to $NewSize ...";
+            print (($Pipe->ResizeBuffer($NewSize) == $NewSize)? "Successful":"Unsucessful") . "!\n\n";
+
+            print "\n\nR e a d y   f o r   r e a d i n g :\n";
+            print "-----------------------------------\n";
+            $iFlag2 = 1;
+
+            print "Openning the pipe...\n";
+            undef $In;
+            while($Pipe->Connect()){
+
+                 while($iFlag2){
+                    ++$iMessage;
+                    print "Reading Message #$iMessage: ";
+                    $In = $Pipe->Read();
+                    if(! $In){
+                        $iFlag2 = 0;
+                        print "Recieved no data, closing connection....\n";
+                        next;
+                    }
+#                    $In =~ s/\n*$//gi;
+                    if ($In =~ /^quit/i){
+                        print "\n\nQuitting this connection....\n";
+                        $iFlag2 = 0;
+                    }elsif ($In =~ /^exit/i){
+                        print "\n\nExitting.....\n";
+                        $iFlag2 = $iFlag = 0;
+                    }else{
+                        print "\"$In\"\n";
+                    }
+                }
+                print "Disconnecting...\n";
+                $Pipe->Disconnect();
+            }
+            $Pipe->Close();
+        }
+    }
+
+
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Service.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Service.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Service.pm	(revision 14139)
@@ -0,0 +1,102 @@
+package Win32::Service;
+
+#
+# Service.pm
+# Written by Douglas_Lankshear@ActiveWare.com
+#
+# subsequently hacked by Gurusamy Sarathy <gsar@activestate.com>
+#
+
+$VERSION = '0.05';
+
+require Exporter;
+require DynaLoader;
+
+die "The Win32::Service module works only on Windows NT" if(!Win32::IsWinNT());
+
+@ISA= qw( Exporter DynaLoader );
+@EXPORT_OK =
+    qw(
+	StartService
+	StopService
+	GetStatus
+	PauseService
+	ResumeService
+	GetServices
+    );
+
+=head1 NAME
+
+Win32::Service - manage system services in perl
+
+=head1 SYNOPSIS
+
+	use Win32::Service;
+
+=head1 DESCRIPTION
+
+This module offers control over the administration of system services.
+
+=head1 FUNCTIONS
+
+=head2 NOTE:
+
+All of the functions return false if they fail, unless otherwise noted.
+If hostName is an empty string, the local machine is assumed.
+
+=over 10
+
+=item StartService(hostName, serviceName)
+
+Start the service serviceName on machine hostName.
+
+=item StopService(hostName, serviceName)
+
+Stop the service serviceName on the machine hostName.
+
+=item GetStatus(hostName, serviceName, status) 
+
+Get the status of a service.  The third argument must be a hash
+reference that will be populated with entries corresponding
+to the SERVICE_STATUS structure of the Win32 API.  See the
+Win32 Platform SDK documentation for details of this structure.
+
+=item PauseService(hostName, serviceName)
+
+=item ResumeService(hostName, serviceName)
+
+=item GetServices(hostName, hashref) 
+
+Enumerates both active and inactive Win32 services at the specified host.
+The hashref is populated with the descriptive service names as keys
+and the short names as the values.
+
+=back
+
+=cut
+
+sub AUTOLOAD
+{
+    my($constname);
+    ($constname = $AUTOLOAD) =~ s/.*:://;
+    #reset $! to zero to reset any current errors.
+    local $! = 0;
+    my $val = constant($constname);
+    if ($! != 0) {
+	if($! =~ /Invalid/) {
+	    $AutoLoader::AUTOLOAD = $AUTOLOAD;
+	    goto &AutoLoader::AUTOLOAD;
+	}
+	else {
+	    ($pack,$file,$line) = caller;
+	    die "Your vendor has not defined Win32::Service macro $constname, used in $file at line $line.";
+	}
+    }
+    eval "sub $AUTOLOAD { $val }";
+    goto &$AUTOLOAD;
+}
+
+bootstrap Win32::Service;
+
+1;
+__END__
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Shortcut.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Shortcut.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Shortcut.pm	(revision 14139)
@@ -0,0 +1,352 @@
+package Win32::Shortcut;
+#######################################################################
+#
+# Win32::Shortcut - Perl Module for Shell Link Interface
+# ^^^^^^^^^^^^^^^
+# This module creates an object oriented interface to the Win32
+# Shell Links (IShellLink interface).
+#
+# Version: 0.03 (07 Apr 1997)
+#
+#######################################################################
+
+require Exporter;       # to export the constants to the main:: space
+require DynaLoader;     # to dynuhlode the module.
+
+@ISA= qw( Exporter DynaLoader );
+@EXPORT = qw(
+    SW_SHOWMAXIMIZED
+    SW_SHOWMINNOACTIVE
+    SW_SHOWNORMAL
+);
+
+
+#######################################################################
+# This AUTOLOAD is used to 'autoload' constants from the constant()
+# XS function.  If a constant is not found then control is passed
+# to the AUTOLOAD in AutoLoader.
+#
+
+sub AUTOLOAD {
+    my($constname);
+    ($constname = $AUTOLOAD) =~ s/.*:://;
+    #reset $! to zero to reset any current errors.
+    local $! = 0;
+    my $val = constant($constname, @_ ? $_[0] : 0);
+    if ($! != 0) {
+
+    # [dada] This results in an ugly Autoloader error
+
+    #if ($! =~ /Invalid/) {
+    #    $AutoLoader::AUTOLOAD = $AUTOLOAD;
+    #    goto &AutoLoader::AUTOLOAD;
+    #} else {
+    
+    # [dada] ... I prefer this one :)
+
+        ($pack, $file, $line) = caller;
+        undef $pack; # [dada] and get rid of "used only once" warning...
+        die "Win32::Shortcut::$constname is not defined, used at $file line $line.";
+
+    #}
+    }
+    eval "sub $AUTOLOAD { $val }";
+    goto &$AUTOLOAD;
+}
+
+
+#######################################################################
+# STATIC OBJECT PROPERTIES
+#
+$VERSION = "0.03";
+
+#######################################################################
+# PUBLIC METHODS
+#
+
+#======== ### CLASS CONSTRUCTOR
+sub new {
+#========
+    my($class, $file) = @_;
+    my $self = {}; 
+    my $ilink = 0; 
+    my $ifile = 0;
+
+    ($ilink, $ifile) = _Instance();
+
+    if($ilink and $ifile) {
+        $self->{'ilink'} = $ilink;
+        $self->{'ifile'} = $ifile;
+        bless $self;
+        # Initialize properties
+        $self->{'File'}             = "";
+        $self->{'Path'}             = "";
+        $self->{'Arguments'}        = "";
+        $self->{'WorkingDirectory'} = "";
+        $self->{'Description'}      = "";
+        $self->{'ShowCmd'}          = 0;
+        $self->{'Hotkey'}           = 0;
+        $self->{'IconLocation'}     = "";
+        $self->{'IconNumber'}       = 0;
+
+        $self->Load($file) if $file;
+        
+    } else {
+        return undef;
+    }
+    $self;
+}  
+
+#=========
+sub Load {
+#=========
+    my($self, $file) = @_;
+    return undef unless ref($self);
+  
+    my $result = _Load($self->{'ilink'}, $self->{'ifile'}, $file);
+
+    if(defined($result)) {
+  
+        # fill the properties of $self
+        $self->{'File'} = $file;
+        $self->{'Path'} = _GetPath($self->{'ilink'}, $self->{'ifile'},0);
+        $self->{'ShortPath'} = _GetPath($self->{'ilink'}, $self->{'ifile'},1);
+        $self->{'Arguments'} = _GetArguments($self->{'ilink'}, $self->{'ifile'});
+        $self->{'WorkingDirectory'} = _GetWorkingDirectory($self->{'ilink'}, $self->{'ifile'});
+        $self->{'Description'} = _GetDescription($self->{'ilink'}, $self->{'ifile'});
+        $self->{'ShowCmd'} = _GetShowCmd($self->{'ilink'}, $self->{'ifile'});
+        $self->{'Hotkey'} = _GetHotkey($self->{'ilink'}, $self->{'ifile'});
+        ($self->{'IconLocation'},
+         $self->{'IconNumber'}) = _GetIconLocation($self->{'ilink'}, $self->{'ifile'});
+    }
+    return $result;
+}
+
+
+#========
+sub Set {
+#========
+    my($self, $path, $arguments, $dir, $description, $show, $hotkey, 
+       $iconlocation, $iconnumber) = @_;
+    return undef unless ref($self);
+
+    $self->{'Path'}             = $path;
+    $self->{'Arguments'}        = $arguments;
+    $self->{'WorkingDirectory'} = $dir;
+    $self->{'Description'}      = $description;
+    $self->{'ShowCmd'}          = $show;
+    $self->{'Hotkey'}           = $hotkey;
+    $self->{'IconLocation'}     = $iconlocation;
+    $self->{'IconNumber'}       = $iconnumber;
+    return 1;
+}
+
+
+#=========
+sub Save {
+#=========
+    my($self, $file) = @_;
+    return undef unless ref($self);
+
+    return undef if not $file and not $self->{'File'};
+    $file = $self->{'File'} if not $file;
+
+    _SetPath($self->{'ilink'}, $self->{'ifile'}, $self->{'Path'});
+    _SetArguments($self->{'ilink'}, $self->{'ifile'}, $self->{'Arguments'});
+    _SetWorkingDirectory($self->{'ilink'}, $self->{'ifile'}, $self->{'WorkingDirectory'});
+    _SetDescription($self->{'ilink'}, $self->{'ifile'}, $self->{'Description'});
+    _SetShowCmd($self->{'ilink'}, $self->{'ifile'}, $self->{'ShowCmd'});
+    _SetHotkey($self->{'ilink'}, $self->{'ifile'}, $self->{'Hotkey'});
+    _SetIconLocation($self->{'ilink'}, $self->{'ifile'},
+                     $self->{'IconLocation'}, $self->{'IconNumber'});
+
+    my $result = _Save($self->{'ilink'}, $self->{'ifile'}, $file);
+    return $result;
+}
+
+#============
+sub Resolve {
+#============
+    my($self, $flags) = @_;
+    return undef unless ref($self);
+    $flags = 1 unless defined($flags);
+    my $result = _Resolve($self->{'ilink'}, $self->{'ifile'}, $flags);
+    return $result;
+}
+
+
+#==========
+sub Close {
+#==========
+    my($self) = @_;
+    return undef unless ref($self);
+
+    my $result = _Release($self->{'ilink'}, $self->{'ifile'});
+    $self->{'released'} = 1;
+    return $result;
+}
+
+#=========
+sub Path {
+#=========
+    my($self, $value) = @_;
+    return undef unless ref($self);
+
+    if(not defined($value)) {
+        return $self->{'Path'};
+    } else {
+        $self->{'Path'} = $value;
+    }
+    return $self->{'Path'};
+}
+
+#==============
+sub ShortPath {
+#==============
+    my($self) = @_;
+    return undef unless ref($self);
+    return $self->{'ShortPath'};
+}
+
+#==============
+sub Arguments {
+#==============
+    my($self, $value) = @_;
+    return undef unless ref($self);
+
+    if(not defined($value)) {
+        return $self->{'Arguments'};
+    } else {
+        $self->{'Arguments'} = $value;
+    }
+    return $self->{'Arguments'};
+}
+
+#=====================
+sub WorkingDirectory {
+#=====================
+    my($self, $value) = @_;
+    return undef unless ref($self);
+
+    if(not defined($value)) {
+        return $self->{'WorkingDirectory'};
+    } else {
+        $self->{'WorkingDirectory'} = $value;
+    }
+    return $self->{'WorkingDirectory'};
+}
+
+
+#================
+sub Description {
+#================
+    my($self, $value) = @_;
+    return undef unless ref($self);
+
+    if(not defined($value)) {
+        return $self->{'Description'};
+    } else {
+        $self->{'Description'} = $value;
+    }
+    return $self->{'Description'};
+}
+
+#============
+sub ShowCmd {
+#============
+    my($self, $value) = @_;
+    return undef unless ref($self);
+
+    if(not defined($value)) {
+        return $self->{'ShowCmd'};
+    } else {
+        $self->{'ShowCmd'} = $value;
+    }
+    return $self->{'ShowCmd'};
+}
+
+#===========
+sub Hotkey {
+#===========
+    my($self, $value) = @_;
+    return undef unless ref($self);
+
+    if(not defined($value)) {
+        return $self->{'Hotkey'};
+    } else {
+        $self->{'Hotkey'} = $value;
+    }
+    return $self->{'Hotkey'};
+}
+
+#=================
+sub IconLocation {
+#=================
+    my($self, $value) = @_;
+    return undef unless ref($self);
+
+    if(not defined($value)) {
+        return $self->{'IconLocation'};
+    } else {
+        $self->{'IconLocation'} = $value;
+    }
+    return $self->{'IconLocation'};
+}
+
+#===============
+sub IconNumber {
+#===============
+    my($self, $value) = @_;
+    return undef unless ref($self);
+
+    if(not defined($value)) {
+        return $self->{'IconNumber'};
+    } else {
+        $self->{'IconNumber'} = $value;
+    }
+    return $self->{'IconNumber'};
+}
+
+#============
+sub Version {
+#============
+    # [dada] to get rid of the "used only once" warning...
+    return $VERSION;
+}
+
+
+#######################################################################
+# PRIVATE METHODS
+#
+
+#============ ### CLASS DESTRUCTOR
+sub DESTROY {
+#============
+    my($self) = @_;
+
+    if(not $self->{'released'}) {
+        _Release($self->{'ilink'}, $self->{'ifile'});
+    }
+}
+
+#======== ### PACKAGE DESTRUCTOR
+sub END { 
+#========
+    # print "Exiting...\n";
+    _Exit(); 
+}
+
+#######################################################################
+# dynamically load in the Shortcut.pll module.
+#
+
+bootstrap Win32::Shortcut;
+
+# Preloaded methods go here.
+
+#Currently Autoloading is not implemented in Perl for win32
+# Autoload methods go after __END__, and are processed by the autosplit program.
+
+1;
+__END__
+
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Sound.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Sound.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Sound.pm	(revision 14139)
@@ -0,0 +1,582 @@
+#######################################################################
+#
+# Win32::Sound - An extension to play with Windows sounds
+# 
+# Author: Aldo Calpini <dada@divinf.it>
+# Version: 0.47
+# Info:
+#       http://www.divinf.it/dada/perl
+#       http://www.perl.com/CPAN/authors/Aldo_Calpini
+#
+#######################################################################
+# Version history: 
+# 0.01 (19 Nov 1996) file created
+# 0.03 (08 Apr 1997) first release
+# 0.30 (20 Oct 1998) added Volume/Format/Devices/DeviceInfo
+#                    (thanks Dave Roth!)
+# 0.40 (16 Mar 1999) added the WaveOut object
+# 0.45 (09 Apr 1999) added $! support, documentation et goodies
+# 0.46 (25 Sep 1999) fixed small bug in DESTROY, wo was used without being
+#		     initialized (Gurusamy Sarathy <gsar@activestate.com>)
+# 0.47 (22 May 2000) support for passing Unicode string to Play()
+#                    (Doug Lankshear <dougl@activestate.com>)
+
+package Win32::Sound;
+
+# See the bottom of this file for the POD documentation.  
+# Search for the string '=head'.
+
+require Exporter;       # to export the constants to the main:: space
+require DynaLoader;     # to dynuhlode the module.
+
+@ISA= qw( Exporter DynaLoader );
+@EXPORT = qw(
+    SND_ASYNC
+    SND_NODEFAULT
+    SND_LOOP
+    SND_NOSTOP
+);
+
+#######################################################################
+# This AUTOLOAD is used to 'autoload' constants from the constant()
+# XS function.  If a constant is not found then control is passed
+# to the AUTOLOAD in AutoLoader.
+#
+
+sub AUTOLOAD {
+    my($constname);
+    ($constname = $AUTOLOAD) =~ s/.*:://;
+    #reset $! to zero to reset any current errors.
+    local $! = 0;
+    my $val = constant($constname, @_ ? $_[0] : 0);
+    if ($! != 0) {
+
+    # [dada] This results in an ugly Autoloader error
+
+    #if ($! =~ /Invalid/) {
+    #    $AutoLoader::AUTOLOAD = $AUTOLOAD;
+    #    goto &AutoLoader::AUTOLOAD;
+    #} else {
+    
+    # [dada] ... I prefer this one :)
+
+        ($pack, $file, $line) = caller;
+        undef $pack; # [dada] and get rid of "used only once" warning...
+        die "Win32::Sound::$constname is not defined, used at $file line $line.";
+
+    #}
+    }
+    eval "sub $AUTOLOAD { $val }";
+    goto &$AUTOLOAD;
+}
+
+
+#######################################################################
+# STATIC OBJECT PROPERTIES
+#
+$VERSION="0.47"; 
+undef unless $VERSION; # [dada] to avoid "possible typo" warning
+
+#######################################################################
+# METHODS
+#
+
+sub Version { $VERSION }
+
+sub Volume {
+    my(@in) = @_;
+    # Allows '0%'..'100%'   
+    $in[0] =~ s{ ([\d\.]+)%$ }{ int($1*100/255) }ex if defined $in[0];
+    $in[1] =~ s{ ([\d\.]+)%$ }{ int($1*100/255) }ex if defined $in[1];
+    _Volume(@in);
+}
+
+#######################################################################
+# dynamically load in the Sound.dll module.
+#
+
+bootstrap Win32::Sound;
+
+#######################################################################
+# Win32::Sound::WaveOut
+#
+
+package Win32::Sound::WaveOut;
+
+sub new {
+    my($class, $one, $two, $three) = @_;
+    my $self = {};
+    bless($self, $class);
+    
+    if($one !~ /^\d+$/ 
+    and not defined($two)
+    and not defined($three)) {
+        # Looks like a file
+        $self->Open($one);
+    } else {
+        # Default format if not given
+        $self->{samplerate} = ($one   or 44100);
+        $self->{bits}       = ($two   or 16);
+        $self->{channels}   = ($three or 2);
+        $self->OpenDevice();
+    }
+    return $self;
+}
+
+sub Volume {
+    my(@in) = @_;
+    # Allows '0%'..'100%'   
+    $in[0] =~ s{ ([\d\.]+)%$ }{ int($1*255/100) }ex if defined $in[0];
+    $in[1] =~ s{ ([\d\.]+)%$ }{ int($1*255/100) }ex if defined $in[1];
+    _Volume(@in);
+}
+
+sub Pitch {
+    my($self, $pitch) = @_;
+    my($int, $frac);
+    if(defined($pitch)) {
+        $pitch =~ /(\d+).?(\d+)?/;
+        $int = $1;
+        $frac = $2 or 0;
+        $int = $int << 16;
+        $frac = eval("0.$frac * 65536");
+        $pitch = $int + $frac;
+        return _Pitch($self, $pitch);
+    } else {
+        $pitch = _Pitch($self);
+        $int = ($pitch & 0xFFFF0000) >> 16;
+        $frac = $pitch & 0x0000FFFF;
+        return eval("$int.$frac");
+    }
+}
+
+sub PlaybackRate {
+    my($self, $rate) = @_;
+    my($int, $frac);
+    if(defined($rate)) {
+        $rate =~ /(\d+).?(\d+)?/;
+        $int = $1;
+        $frac = $2 or 0;
+        $int = $int << 16;
+        $frac = eval("0.$frac * 65536");
+        $rate = $int + $frac;
+        return _PlaybackRate($self, $rate);
+    } else {
+        $rate = _PlaybackRate($self);
+        $int = ($rate & 0xFFFF0000) >> 16;
+        $frac = $rate & 0x0000FFFF;
+        return eval("$int.$frac");
+    }
+}
+
+# Preloaded methods go here.
+
+#Currently Autoloading is not implemented in Perl for win32
+# Autoload methods go after __END__, and are processed by the autosplit program.
+
+1;
+__END__
+
+
+=head1 NAME
+
+Win32::Sound - An extension to play with Windows sounds
+
+=head1 SYNOPSIS
+
+    use Win32::Sound;
+    Win32::Sound::Volume('100%');
+    Win32::Sound::Play("file.wav");
+    Win32::Sound::Stop();
+    
+    # ...and read on for more fun ;-)
+
+=head1 FUNCTIONS
+
+=over 4
+
+=item B<Win32::Sound::Play(SOUND, [FLAGS])>
+
+Plays the specified sound: SOUND can the be name of a WAV file
+or one of the following predefined sound names:
+
+    SystemDefault
+    SystemAsterisk
+    SystemExclamation
+    SystemExit
+    SystemHand
+    SystemQuestion
+    SystemStart
+
+Additionally, if the named sound could not be found, the 
+function plays the system default sound (unless you specify the 
+C<SND_NODEFAULT> flag). If no parameters are given, this function 
+stops the sound actually playing (see also Win32::Sound::Stop).
+
+FLAGS can be a combination of the following constants:
+
+=over 4
+
+=item C<SND_ASYNC>
+
+The sound is played asynchronously and the function 
+returns immediately after beginning the sound
+(if this flag is not specified, the sound is
+played synchronously and the function returns
+when the sound ends).
+
+=item C<SND_LOOP>
+
+The sound plays repeatedly until it is stopped.
+You must also specify C<SND_ASYNC> flag.
+
+=item C<SND_NODEFAULT>
+
+No default sound is used. If the specified I<sound>
+cannot be found, the function returns without
+playing anything.
+
+=item C<SND_NOSTOP>
+
+If a sound is already playing, the function fails.
+By default, any new call to the function will stop
+previously playing sounds.
+
+=back
+
+=item B<Win32::Sound::Stop()>
+
+Stops the sound currently playing.
+
+=item B<Win32::Sound::Volume()>
+
+Returns the wave device volume; if 
+called in an array context, returns left
+and right values. Otherwise, returns a single
+32 bit value (left in the low word, right 
+in the high word).
+In case of error, returns C<undef> and sets
+$!.
+
+Examples:
+
+    ($L, $R) = Win32::Sound::Volume();
+    if( not defined Win32::Sound::Volume() ) {
+        die "Can't get volume: $!";
+    }
+
+=item B<Win32::Sound::Volume(LEFT, [RIGHT])>
+
+Sets the wave device volume; if two arguments
+are given, sets left and right channels 
+independently, otherwise sets them both to
+LEFT (eg. RIGHT=LEFT). Values range from
+0 to 65535 (0xFFFF), but they can also be
+given as percentage (use a string containing 
+a number followed by a percent sign).
+
+Returns C<undef> and sets $! in case of error,
+a true value if successful.
+
+Examples:
+
+    Win32::Sound::Volume('50%');
+    Win32::Sound::Volume(0xFFFF, 0x7FFF);
+    Win32::Sound::Volume('100%', '50%');
+    Win32::Sound::Volume(0);
+
+=item B<Win32::Sound::Format(filename)>
+
+Returns information about the specified WAV file format;
+the array contains:
+
+=over
+
+=item * sample rate (in Hz)
+
+=item * bits per sample (8 or 16)
+
+=item * channels (1 for mono, 2 for stereo)
+
+=back
+
+Example:
+
+    ($hz, $bits, $channels) 
+        = Win32::Sound::Format("file.wav");
+
+
+=item B<Win32::Sound::Devices()>
+
+Returns all the available sound devices;
+their names contain the type of the
+device (WAVEOUT, WAVEIN, MIDIOUT,
+MIDIIN, AUX or MIXER) and 
+a zero-based ID number: valid devices
+names are for example:
+
+    WAVEOUT0
+    WAVEOUT1
+    WAVEIN0
+    MIDIOUT0
+    MIDIIN0
+    AUX0
+    AUX1
+    AUX2
+
+There are also two special device
+names, C<WAVE_MAPPER> and C<MIDI_MAPPER>
+(the default devices for wave output
+and midi output).
+
+Example:
+
+    @devices = Win32::Sound::Devices();
+
+=item Win32::Sound::DeviceInfo(DEVICE)
+
+Returns an associative array of information 
+about the sound device named DEVICE (the
+same format of Win32::Sound::Devices).
+
+The content of the array depends on the device
+type queried. Each device type returns B<at least> 
+the following information:
+
+    manufacturer_id
+    product_id
+    name
+    driver_version
+
+For additional data refer to the following
+table:
+
+    WAVEIN..... formats
+                channels
+    
+    WAVEOUT.... formats
+                channels
+                support
+                
+    MIDIOUT.... technology
+                voices
+                notes
+                channels
+                support
+                
+    AUX........ technology
+                support
+                
+    MIXER...... destinations
+                support
+
+The meaning of the fields, where not
+obvious, can be evinced from the 
+Microsoft SDK documentation (too long
+to report here, maybe one day... :-).
+
+Example:
+
+    %info = Win32::Sound::DeviceInfo('WAVE_MAPPER');
+    print "$info{name} version $info{driver_version}\n";
+
+=back
+
+=head1 THE WaveOut PACKAGE
+
+Win32::Sound also provides a different, more
+powerful approach to wave audio data with its 
+C<WaveOut> package. It has methods to load and
+then play WAV files, with the additional feature
+of specifying the start and end range, so you
+can play only a portion of an audio file.
+
+Furthermore, it is possible to load arbitrary
+binary data to the soundcard to let it play and
+save them back into WAV files; in a few words,
+you can do some sound synthesis work.
+
+=head2 FUNCTIONS
+
+=over
+
+=item new Win32::Sound::WaveOut(FILENAME)
+
+=item new Win32::Sound::WaveOut(SAMPLERATE, BITS, CHANNELS)
+
+=item new Win32::Sound::WaveOut()
+
+This function creates a C<WaveOut> object; the
+first form opens the specified wave file (see
+also C<Open()> ), so you can directly C<Play()> it.
+
+The second (and third) form opens the
+wave output device with the format given
+(or if none given, defaults to 44.1kHz,
+16 bits, stereo); to produce something
+audible you can either C<Open()> a wave file
+or C<Load()> binary data to the soundcard
+and then C<Write()> it.
+
+=item Close()
+
+Closes the wave file currently opened.
+
+=item CloseDevice()
+
+Closes the wave output device; you can change
+format and reopen it with C<OpenDevice()>.
+
+=item GetErrorText(ERROR)
+
+Returns the error text associated with
+the specified ERROR number; note it only
+works for wave-output-specific errors.
+
+=item Load(DATA)
+
+Loads the DATA buffer in the soundcard.
+The format of the data buffer depends
+on the format used; for example, with
+8 bit mono each sample is one character,
+while with 16 bit stereo each sample is
+four characters long (two 16 bit values
+for left and right channels). The sample
+rate defines how much samples are in one
+second of sound. For example, to fit one
+second at 44.1kHz 16 bit stereo your buffer
+must contain 176400 bytes (44100 * 4).
+
+=item Open(FILE)
+
+Opens the specified wave FILE.
+
+=item OpenDevice()
+
+Opens the wave output device with the
+current sound format (not needed unless
+you used C<CloseDevice()>).
+
+=item Pause()
+
+Pauses the sound currently playing; 
+use C<Restart()> to continue playing.
+
+=item Play( [FROM, TO] )
+
+Plays the opened wave file. You can optionally
+specify a FROM - TO range, where FROM and TO
+are expressed in samples (or use FROM=0 for the
+first sample and TO=-1 for the last sample).
+Playback happens always asynchronously, eg. in 
+the background.
+
+=item Position()
+
+Returns the sample number currently playing;
+note that the play position is not zeroed
+when the sound ends, so you have to call a
+C<Reset()> between plays to receive the
+correct position in the current sound.
+
+=item Reset()
+
+Stops playing and resets the play position
+(see C<Position()>).
+
+=item Restart()
+
+Continues playing the sound paused by C<Pause()>.
+
+=item Save(FILE, [DATA])
+
+Writes the DATA buffer (if not given, uses the 
+buffer currently loaded in the soundcard) 
+to the specified wave FILE.
+
+=item Status()
+
+Returns 0 if the soundcard is currently playing,
+1 if it's free, or C<undef> on errors.
+
+=item Unload()
+
+Frees the soundcard from the loaded data.
+
+=item Volume( [LEFT, RIGHT] )
+
+Gets or sets the volume for the wave output device.
+It works the same way as Win32::Sound::Volume.
+
+=item Write()
+
+Plays the data currently loaded in the soundcard;
+playback happens always asynchronously, eg. in 
+the background.
+
+=back
+
+=head2 THE SOUND FORMAT
+
+The sound format is stored in three properties of
+the C<WaveOut> object: C<samplerate>, C<bits> and
+C<channels>.
+If you need to change them without creating a 
+new object, you should close before and reopen 
+afterwards the device.
+
+    $WAV->CloseDevice();
+    $WAV->{samplerate} = 44100; # 44.1kHz
+    $WAV->{bits}       = 8;     # 8 bit
+    $WAV->{channels}   = 1;     # mono
+    $WAV->OpenDevice();
+
+You can also use the properties to query the
+sound format currently used.
+
+=head2 EXAMPLE
+
+This small example produces a 1 second sinusoidal
+wave at 440Hz and saves it in F<sinus.wav>:
+
+    use Win32::Sound;
+    
+    # Create the object
+    $WAV = new Win32::Sound::WaveOut(44100, 8, 2);
+    
+    $data = ""; 
+    $counter = 0;
+    $increment = 440/44100;
+    
+    # Generate 44100 samples ( = 1 second)
+    for $i (1..44100) {
+
+        # Calculate the pitch 
+        # (range 0..255 for 8 bits)
+        $v = sin($counter/2*3.14) * 128 + 128;    
+
+        # "pack" it twice for left and right
+        $data .= pack("cc", $v, $v);
+
+        $counter += $increment;
+    }
+    
+    $WAV->Load($data);       # get it
+    $WAV->Write();           # hear it
+    1 until $WAV->Status();  # wait for completion
+    $WAV->Save("sinus.wav"); # write to disk
+    $WAV->Unload();          # drop it
+
+=head1 VERSION
+
+Win32::Sound version 0.46, 25 Sep 1999.
+
+=head1 AUTHOR
+
+Aldo Calpini, C<dada@divinf.it>
+
+Parts of the code provided and/or suggested by Dave Roth.
+
+=cut
+
+
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Test.pl
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Test.pl	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/Test.pl	(revision 14139)
@@ -0,0 +1,478 @@
+#####
+#       T E S T . P L
+#       -------------
+#       A test script for exercising the Win32::ODBC extension. Install
+#       the ODBC.PLL extension and the ODBC.PM wrapper, set up an ODBC
+#       DSN (Data Source Name) by the ODBC administrator, then give this a try!
+#
+#       READ THE DOCUMENTATION -- I AM NOT RESPOSIBLE FOR ANY PROBLEMS THAT
+#       THIS MAY CAUSE WHATSOEVER.  BY USING THIS OR ANY  ---
+#       OF THE WIN32::ODBC PARTS FOUND IN THE DISTRIBUTION YOU ARE AGREEING
+#       WITH THE TERMS OF THIS DISTRIBUTION!!!!!
+#
+#
+#       You have been warned.
+#       --- ---- ---- ------
+#
+#       Updated to test newest version v961007.  Dave Roth <rothd@roth.net>
+#           This version contains a small sample database (in MS Access 7.0
+#           format) called ODBCTest.mdb. Place this database in the same
+#           directory as this test.pl file.
+#
+#       --------------------------------------------------------------------
+#
+#       SYNTAX:
+#           perl test.pl ["DSN Name" [Max Rows]]
+#
+#               DSN Name....Name of DSN that will be used. If this is
+#                           omitted then we will use the obnoxious default DSN.
+#               Max Rows....Maximum number of rows wanted to be retrieved from
+#                           the DSN.
+#                           - If this is 0 then the request is to retrieve as
+#                             many as possible.
+#                           - If this is a value greater than that which the DSN
+#                             driver can handle the value will be the greatest
+#                             the DSN driver allows.
+#                           - If omitted then we use the default value.
+#####
+
+    use Win32::ODBC;
+
+
+    $TempDSN = "Win32 ODBC Test --123xxYYzz987--";
+    $iTempDSN = 1;
+
+    if (!($DSN = $ARGV[0])){
+        $DSN = $TempDSN;
+    }
+    $MaxRows = 8 unless defined ($MaxRows = $ARGV[1]);
+
+    $DriverType = "Microsoft Access Driver (*.mdb)";
+    $Desc = "Description=The Win32::ODBC Test DSN for Perl";
+    $Dir = `cd`;
+    chop $Dir;
+    $DBase = "ODBCTest.mdb";
+
+    $iWidth=60;
+    %SQLStmtTypes = (SQL_CLOSE, "SQL_CLOSE", SQL_DROP, "SQL_DROP", SQL_UNBIND, "SQL_UNBIND", SQL_RESET_PARAMS, "SQL_RESET_PARAMS");
+
+#    Initialize();
+
+    ($Name, $Version, $Date, $Author, $CompileDate, $CompileTime, $Credits) = Win32::ODBC::Info();
+    print "\n";
+    print "\t+", "=" x ($iWidth), "+\n";
+    print "\t|", Center("", $iWidth), "|\n";
+    print "\t|", Center("", $iWidth), "|\n";
+    print "\t|", Center("$Name", $iWidth), "|\n";
+    print "\t|", Center("-" x length("$Name"), $iWidth), "|\n";
+    print "\t|", Center("", $iWidth), "|\n";
+
+    print "\t|", Center("Version $Version ($Date)", $iWidth), "|\n";
+    print "\t|", Center("by $Author", $iWidth), "|\n";
+    print "\t|", Center("Compiled on $CompileDate at $CompileTime.", $iWidth), "|\n";
+    print "\t|", Center("", $iWidth), "|\n";
+    print "\t|", Center("Credits:", $iWidth), "|\n";
+    print "\t|", Center(("-" x length("Credits:")), $iWidth), "|\n";
+    foreach $Temp (split("\n", $Credits)){
+        print "\t|", Center("$Temp", $iWidth), "|\n";
+    }
+    print "\t|", Center("", $iWidth), "|\n";
+    print "\t+", "=" x ($iWidth), "+\n";
+
+####
+#   T E S T  1
+####
+    PrintTest(1, "Dump available ODBC Drivers");
+    print "\nAvailable ODBC Drivers:\n";
+    if (!(%Drivers = Win32::ODBC::Drivers())){
+        $Failed{'Test 1'} = "Drivers(): " . Win32::ODBC::Error();
+    }
+    foreach $Driver (keys(%Drivers)){
+        print "  Driver=\"$Driver\"\n  Attributes: ", join("\n" . " "x14, sort(split(';', $Drivers{$Driver}))), "\n\n";
+    }
+
+
+####
+#   T E S T  2
+####
+    PrintTest(2,"Dump available datasources");
+
+    ####
+    #   Notice you don't need an instantiated object to use this...
+    ####
+    print "\nHere are the available datasources...\n";
+    if (!(%DSNs = Win32::ODBC::DataSources())){
+        $Failed{'Test 2'} = "DataSources(): " . Win32::ODBC::Error();
+    }
+    foreach $Temp (keys(%DSNs)){
+        if (($Temp eq $TempDSN) && ($DSNs{$Temp} eq $DriverType)){
+            $iTempDSNExists++;
+        }
+        if ($DSN =~ /$Temp/i){
+            $iTempDSN = 0;
+            $DriverType = $DSNs{$Temp};
+        }
+        print "\tDSN=\"$Temp\" (\"$DSNs{$Temp}\")\n";
+    }
+
+####
+#   T E S T 2.5
+####
+        #   IF WE DO NOT find the DSN the user specified...
+    if ($iTempDSN){
+        PrintTest("2.5", "Create a Temporary DSN");
+
+        print "\n\tCould not find the DSN (\"$DSN\") so we will\n\tuse a temporary one (\"$TempDSN\")...\n\n";
+
+        $DSN = $TempDSN;
+
+        if (! $iTempDSNExists){
+            print "\tAdding DSN \"$DSN\"...";
+            if (Win32::ODBC::ConfigDSN(ODBC_ADD_DSN, $DriverType, ("DSN=$DSN", "Description=The Win32 ODBC Test DSN for Perl", "DBQ=$Dir\\$DBase", "DEFAULTDIR=$Dir", "UID=", "PWD="))){
+                print "Successful!\n";
+            }else{
+                print "Failure\n";
+                $Failed{'Test 2.5'} = "ConfigDSN(): Could not add \"$DSN\": " . Win32::ODBC::Error();
+                    # If we failed here then use the last DSN we listed in Test 2
+                $DriverType = $DSNs{$Temp};
+                $DSN = $Temp;
+                print "\n\tCould not add a temporary DSN so using the last one listed:\n";
+                print "\t\t$DSN ($DriverType)\n";
+
+            }
+        }
+    }
+
+####
+#   Report What Driver/DSN we are using
+####
+
+    print "\n\nWe are using the DSN:\n\tDSN = \"$DSN\"\n";
+    print "\tDriver = \"$DriverType\"\n\n";
+
+
+####
+#   T E S T  3
+####
+    PrintTest(3, "Open several ODBC connections");
+    print "\n\tOpening ODBC connection for \"$DSN\"...\n\t\t";
+    if (!($O = new Win32::ODBC($DSN))){
+        print "Failure. \n\n";
+        $Failed{'Test 3a'} = "new(): " . Win32::ODBC::Error();
+        PresentErrors();
+        exit();
+    }else{
+        print "Success (connection #", $O->Connection(), ")\n\n";
+    }
+
+    print "\tOpening ODBC connection for \"$DSN\"...\n\t\t";
+    if (!($O2 = new Win32::ODBC($DSN))){
+        $Failed{'Test 3b'} = "new(): " . Win32::ODBC::Error();
+        print "Failure. \n\n";
+    }else{
+        print "Success (connection #", $O2->Connection(), ")\n\n";
+    }
+
+    print "\tOpening ODBC connection for \"$DSN\"\n\t\t";
+    if (!($O3 = new Win32::ODBC($DSN))){
+        $Failed{'Test 3c'} = "new(): " . Win32::ODBC::Error();
+        print "Failure. \n\n";
+    }else{
+        print "Success (connection #", $O3->Connection(), ")\n\n";
+    }
+
+
+####
+#   T E S T  4
+####
+    PrintTest(4, "Close all but one connection");
+
+    print "\n\tCurrently open ODBC connections are: \"", join(", ", sort($O2->GetConnections())), "\"\n";
+    print "\tClosing ODBC connection #", $O2->Connection(), "...\n";
+    print "\t\t...", (($O2->Close())? "Successful.":"Failure."), "\n";
+
+    print "\n\tCurrently open ODBC connections are: \"", join(", ", sort($O3->GetConnections())), "\"\n";
+    print "\tClosing ODBC connection #", $O3->Connection(), "...\n";
+    print "\t\t...", (($O3->Close())? "Successful.":"Failure."), "\n";
+
+    print "\n\tCurrently open ODBC connections are: \"", join(", ", sort($O2->GetConnections())), "\"\n";
+
+####
+#   T E S T  5
+####
+    PrintTest(5, "Set/query Max Buffer size for a connection");
+
+    srand(time);
+    $Temp = int(rand(10240)) + 10240;
+    print "\nMaximum Buffer Size for connection #", $O->Connection(), ":\n";
+    print "\tValue set at ", $O->GetMaxBufSize(), "\n";
+
+    print "\tSetting Maximum Buffer Size to $Temp...  it has been set to ", $O->SetMaxBufSize($Temp), "\n";
+    print "\tValue set at ", $O->GetMaxBufSize(), "\n";
+
+    $Temp += int(rand(10240)) + 102400;
+    print "\tSetting Maximum Buffer Size to $Temp... (can not be more than 102400)\n\t\t...it has been set to ", $O->SetMaxBufSize($Temp), "\n";
+    print "\tValue set at ", $O->GetMaxBufSize(), "\n";
+
+    $Temp = int(rand(1024)) + 2048;
+    print "\tSetting Maximum Buffer Size to $Temp...  it has been set to ", $O->SetMaxBufSize($Temp), "\n";
+
+    print "\tValue set at ", $O->GetMaxBufSize(), "\n";
+
+
+####
+#   T E S T  6
+####
+    PrintTest(6, "Set/query Stmt Close Type");
+
+    print "\n\tStatement Close Type is currently set as ", $O->GetStmtCloseType(), " " . $O->Error . "\n";
+    print "\tSetting Statement Close Type to SQL_CLOSE: (returned code of ",  $O->SetStmtCloseType(SQL_CLOSE), ")" . $O->Error . "\n";
+    print "\tStatement Close Type is currently set as ", $O->GetStmtCloseType(), " " . $O->Error ."\n";
+
+
+####
+#   T E S T  7
+####
+    PrintTest(7, "Dump DSN for current connection");
+
+    if (! (%DSNAttributes = $O->GetDSN())){
+        $Failed{'Test 7'} = "GetDSN(): " . $O->Error();
+    }else{
+        print"\nThe DSN for connection #", $O->Connection(), ":\n";
+        print "\tDSN...\n";
+        foreach (sort(keys(%DSNAttributes))){
+            print "\t$_ = \"$DSNAttributes{$_}\"\n";
+        }
+    }
+
+
+
+####
+#   T E S T  8
+####
+    PrintTest(8, "Dump list of ALL tables in datasource");
+
+    print "\nList of tables for \"$DSN\"\n\n";
+    $Num = 0;
+    if ($O->Catalog("", "", "%", "'TABLE','VIEW','SYSTEM TABLE', 'GLOBAL TEMPORARY','LOCAL TEMPORARY','ALIAS','SYNONYM'")){
+
+        print "\tCursor is currently named \"", $O->GetCursorName(), "\".\n";
+        print "\tRenaming cursor to \"TestCursor\"...", (($O->SetCursorName("TestCursor"))? "Success":"Failure"), ".\n";
+        print "\tCursor is currently named \"", $O->GetCursorName(), "\".\n\n";
+
+        @FieldNames = $O->FieldNames();
+
+        $~ = "Test_8_Header";
+        write;
+
+        $~ = "Test_8_Body";
+        while($O->FetchRow()){
+            undef %Data;
+            %Data = $O->DataHash();
+            write;
+        }
+    }
+    print "\n\tTotal number of tables displayed: $Num\n";
+
+
+
+####
+#   T E S T  9
+####
+    PrintTest(9, "Dump list of non-system tables and views in datasource");
+
+    print "\n";
+    $Num = 0;
+
+    foreach  $Temp ($O->TableList("", "", "%", "TABLE, VIEW, SYSTEM_TABLE")){
+        $Table = $Temp;
+        print "\t", ++$Num, ".) \"$Temp\"\n";
+    }
+    print "\n\tTotal number of tables displayed: $Num\n";
+
+
+####
+#   T E S T  10
+####
+    PrintTest(10, "Dump contents of the table: \"$Table\"");
+
+    print "\n";
+
+    print "\tResetting (dropping) cursor...", (($O->DropCursor())? "Successful":"Failure"), ".\n\n";
+
+    print "\tCurrently the cursor type is: ", $O->GetStmtOption($O->SQL_CURSOR_TYPE), "\n";
+    print "\tSetting Cursor to Dynamic (", ($O->SQL_CURSOR_DYNAMIC), ")...", (($O->SetStmtOption($O->SQL_CURSOR_TYPE, $O->SQL_CURSOR_DYNAMIC))? "Success":"Failure"), ".\n";
+    print "\t\tThis may have failed depending on your ODBC Driver.\n";
+    print "\t\tThis is not really a problem, it will default to another value.\n";
+    print "\tUsing the cursor type of: ", $O->GetStmtOption($O->SQL_CURSOR_TYPE), "\n\n";
+
+    print "\tSetting the connection to only grab $MaxRows row", ($MaxRows == 1)? "":"s", " maximum...";
+    if ($O->SetStmtOption($O->SQL_MAX_ROWS, $MaxRows)){
+        print "Success!\n";
+    }else{
+        $Failed{'Test 10a'} = "SetStmtOption(): " . Win32::ODBC::Error();
+        print "Failure.\n";
+    }
+
+    $iTemp = $O->GetStmtOption($O->SQL_MAX_ROWS);
+    print "\tUsing the maximum rows: ", (($iTemp)? $iTemp:"No maximum limit"), "\n\n";
+
+    print "\tCursor is currently named \"", $O->GetCursorName(), "\".\n";
+    print "\tRenaming cursor to \"TestCursor\"...", (($O->SetCursorName("TestCursor"))? "Success":"Failure"), ".\n";
+    print "\tCursor is currently named \"", $O->GetCursorName(), "\".\n\n";
+
+    if (! $O->Sql("SELECT * FROM [$Table]")){
+        @FieldNames = $O->FieldNames();
+        $Cols = $#FieldNames + 1;
+        $Cols = 8 if ($Cols > 8);
+
+        $FmH = "format Test_10_Header =\n";
+        $FmH2 = "";
+        $FmH3 = "";
+        $FmB = "format Test_10_Body = \n";
+        $FmB2 = "";
+
+        for ($iTemp = 0; $iTemp < $Cols; $iTemp++){
+            $FmH .= "@" . "<" x (80/$Cols - 2) . " ";
+            $FmH2 .= "\$FieldNames[$iTemp],";
+            $FmH3 .= "-" x (80/$Cols - 1) . " ";
+
+            $FmB .= "@" . "<" x (80/$Cols - 2) . " ";
+            $FmB2 .= "\$Data{\$FieldNames[$iTemp]},";
+        }
+        chop $FmH2;
+        chop $FmB2;
+
+        eval"$FmH\n$FmH2\n$FmH3\n.\n";
+        eval "$FmB\n$FmB2\n.\n";
+
+        $~ = "Test_10_Header";
+        write();
+        $~ = "Test_10_Body";
+
+            # Fetch the next rowset
+        while($O->FetchRow()){
+            undef %Data;
+            %Data = $O->DataHash();
+            write();
+        }
+            ####
+            #   THE preceeding block could have been written like this:
+            #   ------------------------------------------------------
+            #
+            #       print "\tCurrently the cursor type is: ", $O->GetStmtOption($O->SQL_CURSOR_TYPE), "\n";
+            #       print "\tSetting Cursor to Dynamic (", ($O->SQL_CURSOR_DYNAMIC), ")...", (($O->SetStmtOption($O->SQL_CURSOR_TYPE, $O->SQL_CURSOR_DYNAMIC))? "Success":"Failure"), ".\n";
+            #       print "\t\tThis may have failed depending on your ODBC Driver. No real problem.\n";
+            #       print "\tUsing the cursor type of: ", $O->GetStmtOption($O->SQL_CURSOR_TYPE), "\n\n";
+            #
+            #       print "\tSetting rowset size = 15 ...", (($O->SetStmtOption($O->SQL_ROWSET_SIZE, 15))? "Success":"Failure"), ".\n";
+            #       print "\tGetting rowset size: ", $O->GetStmtOption($O->SQL_ROWSET_SIZE), "\n\n";
+            #
+            #       while($O->FetchRow()){
+            #           $iNum = 1;
+            #               #  Position yourself in the rowset
+            #           while($O->SetPos($iNum++ ,$O->SQL_POSITION, $O->SQL_LOCK_NO_CHANGE)){
+            #               undef %Data;
+            #               %Data = $O->DataHash();
+            #               write();
+            #           }
+            #           print "\t\tNext rowset...\n";
+            #       }
+            #
+            #   The reason I didn't write it that way (which is easier) is to
+            #   show that we can now SetPos(). Also Fetch() now uses
+            #   SQLExtendedFetch() so it can position itself and retrieve
+            #   rowsets. Notice earlier in this Test 10 we set the
+            #   SQL_ROWSET_SIZE. If this was not set it would default to
+            #   no limit (depending upon your ODBC Driver).
+            ####
+
+        print "\n\tNo more records available.\n";
+    }else{
+        $Failed{'Test 10'} = "Sql(): " . $O->Error();
+    }
+
+    $O->Close();
+
+####
+#   T E S T 11
+####
+    if ($iTempDSN){
+        PrintTest(11, "Remove the temporary DSN");
+        print "\n\tRemoving the temporary DSN:\n";
+        print "\t\tDSN = \"$DSN\"\n\t\tDriver = \"$DriverType\"\n";
+
+        if (Win32::ODBC::ConfigDSN(ODBC_REMOVE_DSN, $DriverType, "DSN=$DSN")){
+            print "\tSuccessful!\n";
+        }else{
+            print "\tFailed.\n";
+            $Failed{'Test 11'} = "ConfigDSN(): Could not remove \"$DSN\":" . Win32::ODBC::Error();
+        }
+    }
+
+
+    PrintTest("E N D   O F   T E S T");
+    PresentErrors();
+
+
+
+#----------------------- F U N C T I O N S ---------------------------
+
+sub Error{
+    my($Data) = @_;
+    $Data->DumpError() if ref($Data);
+    Win32::ODBC::DumpError() if ! ref($Data);
+}
+
+
+sub Center{
+    local($Temp, $Width) = @_;
+    local($Len) = ($Width - length($Temp)) / 2;
+    return " " x int($Len), $Temp, " " x (int($Len) + (($Len != int($Len))? 1:0));
+}
+
+sub PrintTest{
+    my($Num, $String) = @_;
+    my($Temp);
+    if (length($String)){
+        $Temp = "  T E S T  $Num $String ";
+    }else{
+        $Temp = "  $Num  ";
+    }
+    $Len = length($Temp);
+    print "\n", "-" x ((79 - $Len)/2), $Temp, "-" x ((79 - $Len)/2 - 1), "\n";
+    print "\t$String\n";
+}
+
+sub PresentErrors{
+    PrintTest("", "Error Report:");
+    if (keys(%Failed)){
+        print "The following were errors:\n";
+        foreach (sort(keys(%Failed))){
+            print "$_ = $Failed{$_}\n";
+        }
+    }else{
+        print "\n\nThere were no errors reported during this test.\n\n";
+    }
+}
+
+
+sub Initialize{
+format Test_8_Header =
+       @<<<<<<<<<<<<<<<<<<<<<<<<<<< @|||||||||||| @|||||||||||| @|||||||||||
+       $FieldNames[0],     $FieldNames[1], $FieldNames[2], $FieldNames[3]
+       ---------------------------- ------------- ------------- ------------
+.
+format Test_8_Body =
+   @>. @<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<< @<<<<<<<<<<<< @<<<<<<<<<<<
+ ++$Num, $Data{$FieldNames[0]},  $Data{$FieldNames[1]},   $Data{$FieldNames[2]}, $Data{$FieldNames[3]}
+.
+format Test_9_Header =
+          @<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<< @<<<<<<<<<<<<<< @<<<<<<<<<<<<<<
+           $FieldNames[0],  $FieldNames[1],   $FieldNames[2], $FieldNames[3]
+.
+format Test_9_Body =
+          @<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<< @<<<<<<<<<<<<<< @<<<<<<<<<<<<<<
+           $Data{$FieldNames[0]},  $Data{$FieldNames[1]},   $Data{$FieldNames[2]}, $Data{$FieldNames[3]}
+.
+}
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/TieRegistry.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/TieRegistry.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/TieRegistry.pm	(revision 14139)
@@ -0,0 +1,3800 @@
+# Win32/TieRegistry.pm -- Perl module to easily use a Registry
+# (on Win32 systems so far).
+# by Tye McQueen, tye@metronet.com, see http://www.metronet.com/~tye/.
+
+#
+# Skip to "=head" line for user documentation.
+#
+
+
+package Win32::TieRegistry;
+
+
+use strict;
+use vars qw( $PACK $VERSION @ISA @EXPORT @EXPORT_OK );
+
+$PACK= "Win32::TieRegistry";	# Used in error messages.
+$VERSION= '0.25';		# Released 2003-10-07
+
+
+use Carp;
+
+require Tie::Hash;
+@ISA= qw(Tie::Hash);
+
+# Required other modules:
+use Win32API::Registry 0.12 qw( :KEY_ :HKEY_ :REG_ );
+
+#Optional other modules:
+use vars qw( $_NoMoreItems $_FileNotFound $_TooSmall $_MoreData $_SetDualVar );
+
+if(  eval { require Win32::WinError }  ) {
+    $_NoMoreItems= Win32::WinError::constant("ERROR_NO_MORE_ITEMS",0);
+    $_FileNotFound= Win32::WinError::constant("ERROR_FILE_NOT_FOUND",0);
+    $_TooSmall= Win32::WinError::constant("ERROR_INSUFFICIENT_BUFFER",0);
+    $_MoreData= Win32::WinError::constant("ERROR_MORE_DATA",0);
+} else {
+    $_NoMoreItems= "^No more data";
+    $_FileNotFound= "cannot find the file";
+    $_TooSmall= " data area passed to ";
+    $_MoreData= "^more data is avail";
+}
+if(  $_SetDualVar= eval { require SetDualVar }  ) {
+    import SetDualVar;
+}
+
+
+#Implementation details:
+#    When opened:
+#	HANDLE		long; actual handle value
+#	MACHINE		string; name of remote machine ("" if local)
+#	PATH		list ref; machine-relative full path for this key:
+#			["LMachine","System","Disk"]
+#			["HKEY_LOCAL_MACHINE","System","Disk"]
+#	DELIM		char; delimiter used to separate subkeys (def="\\")
+#	OS_DELIM	char; always "\\" for Win32
+#	ACCESS		long; usually KEY_ALL_ACCESS, perhaps KEY_READ, etc.
+#	ROOTS		string; var name for "Lmachine"->HKEY_LOCAL_MACHINE map
+#	FLAGS		int; bits to control certain options
+#    Often:
+#	VALUES		ref to list of value names (data/type never cached)
+#	SUBKEYS		ref to list of subkey names
+#	SUBCLASSES	ref to list of subkey classes
+#	SUBTIMES	ref to list of subkey write times
+#	MEMBERS		ref to list of subkey_name.DELIM's, DELIM.value_name's
+#	MEMBHASH	hash ref to with MEMBERS as keys and 1's as values
+#    Once Key "Info" requested:
+#	Class CntSubKeys CntValues MaxSubKeyLen MaxSubClassLen
+#	MaxValNameLen MaxValDataLen SecurityLen LastWrite
+#    If is tied to a hash and iterating over key values:
+#	PREVIDX		int; index of last MEMBERS element return
+#    If is the key object returned by Load():
+#	UNLOADME	list ref; information about Load()ed key
+#    If is a subkey of a "loaded" key other than the one returned by Load():
+#	DEPENDON	obj ref; object that can't be destroyed before us
+
+
+#Package-local variables:
+
+# Option flag bits:
+use vars qw( $Flag_ArrVal $Flag_TieVal $Flag_DualTyp $Flag_DualBin
+	     $Flag_FastDel $Flag_HexDWord $Flag_Split $Flag_FixNulls );
+$Flag_ArrVal=	0x0001;
+$Flag_TieVal=	0x0002;
+$Flag_FastDel=	0x0004;
+$Flag_HexDWord=	0x0008;
+$Flag_Split=	0x0010;
+$Flag_DualTyp=	0x0020;
+$Flag_DualBin=	0x0040;
+$Flag_FixNulls=	0x0080;
+
+
+use vars qw( $RegObj %_Roots %RegHash $Registry );
+
+# Short-hand for HKEY_* constants:
+%_Roots= (
+    "Classes" =>	HKEY_CLASSES_ROOT,
+    "CUser" =>		HKEY_CURRENT_USER,
+    "LMachine" =>	HKEY_LOCAL_MACHINE,
+    "Users" =>		HKEY_USERS,
+    "PerfData" =>	HKEY_PERFORMANCE_DATA,	# Too picky to be useful
+    "CConfig" =>	HKEY_CURRENT_CONFIG,
+    "DynData" =>	HKEY_DYN_DATA,		# Too picky to be useful
+);
+
+# Basic master Registry object:
+$RegObj= {};
+@$RegObj{qw( HANDLE MACHINE PATH DELIM OS_DELIM ACCESS FLAGS ROOTS )}= (
+    "NONE", "", [], "\\", "\\",
+    KEY_READ|KEY_WRITE, $Flag_HexDWord|$Flag_FixNulls, "${PACK}::_Roots" );
+$RegObj->{FLAGS} |= $Flag_DualTyp|$Flag_DualBin   if  $_SetDualVar;
+bless $RegObj;
+
+# Fill cache for master Registry object:
+@$RegObj{qw( VALUES SUBKEYS SUBCLASSES SUBTIMES )}= (
+    [],  [ keys(%_Roots) ],  [],  []  );
+grep( s#$#$RegObj->{DELIM}#,
+  @{ $RegObj->{MEMBERS}= [ @{$RegObj->{SUBKEYS}} ] } );
+@$RegObj{qw( Class MaxSubKeyLen MaxSubClassLen MaxValNameLen
+  MaxValDataLen SecurityLen LastWrite CntSubKeys CntValues )}=
+    ( "", 0, 0, 0, 0, 0, 0, 0, 0 );
+
+# Create master Registry tied hash:
+$RegObj->Tie( \%RegHash );
+
+# Create master Registry combination object and tied hash reference:
+$Registry= \%RegHash;
+bless $Registry;
+
+
+# Preloaded methods go here.
+
+
+# Map option names to name of subroutine that controls that option:
+use vars qw( @_opt_subs %_opt_subs );
+@_opt_subs= qw( Delimiter ArrayValues TieValues SplitMultis DWordsToHex
+	FastDelete FixSzNulls DualTypes DualBinVals AllowLoad AllowSave );
+@_opt_subs{@_opt_subs}= @_opt_subs;
+
+sub import
+{
+    my $pkg= shift(@_);
+    my $level= $Exporter::ExportLevel;
+    my $expto= caller($level);
+    my @export= ();
+    my @consts= ();
+    my $registry= $Registry->Clone;
+    local( $_ );
+    while(  @_  ) {
+	$_= shift(@_);
+	if(  /^\$(\w+::)*\w+$/  ) {
+	    push( @export, "ObjVar" )   if  /^\$RegObj$/;
+	    push( @export, $_ );
+	} elsif(  /^\%(\w+::)*\w+$/  ) {
+	    push( @export, $_ );
+	} elsif(  /^[$%]/  ) {
+	    croak "${PACK}->import:  Invalid variable name ($_)";
+	} elsif(  /^:/  ||  /^(H?KEY|REG)_/  ) {
+	    push( @consts, $_ );
+	} elsif(  ! @_  ) {
+	    croak "${PACK}->import:  Missing argument after option ($_)";
+	} elsif(  exists $_opt_subs{$_}  ) {
+	    $_= $_opt_subs{$_};
+	    $registry->$_( shift(@_) );
+	} elsif(  /^TiedRef$/  ) {
+	    $_= shift(@_);
+	    if(  ! ref($_)  &&  /^(\$?)(\w+::)*\w+$/  ) {
+		$_= '$'.$_   unless  '$' eq $1;
+	    } elsif(  "SCALAR" ne ref($_)  ) {
+		croak "${PACK}->import:  Invalid var after TiedRef ($_)";
+	    }
+	    push( @export, $_ );
+	} elsif(  /^TiedHash$/  ) {
+	    $_= shift(@_);
+	    if(  ! ref($_)  &&  /^(\%?)(\w+::)*\w+$/  ) {
+		$_= '%'.$_   unless  '%' eq $1;
+	    } elsif(  "HASH" ne ref($_)  ) {
+		croak "${PACK}->import:  Invalid var after TiedHash ($_)";
+	    }
+	    push( @export, $_ );
+	} elsif(  /^ObjectRef$/  ) {
+	    $_= shift(@_);
+	    if(  ! ref($_)  &&  /^(\$?)(\w+::)*\w+$/  ) {
+		push( @export, "ObjVar" );
+		$_= '$'.$_   unless  '$' eq $1;
+	    } elsif(  "SCALAR" eq ref($_)  ) {
+		push( @export, "ObjRef" );
+	    } else {
+		croak "${PACK}->import:  Invalid var after ObjectRef ($_)";
+	    }
+	    push( @export, $_ );
+	} elsif(  /^ExportLevel$/  ) {
+	    $level= shift(@_);
+	    $expto= caller($level);
+	} elsif(  /^ExportTo$/  ) {
+	    undef $level;
+	    $expto= caller($level);
+	} else {
+	    croak "${PACK}->import:  Invalid option ($_)";
+	}
+    }
+    Win32API::Registry->export( $expto, @consts )   if  @consts;
+    @export= ('$Registry')   unless  @export;
+    while(  @export  ) {
+	$_= shift( @export );
+	if(  /^\$((?:\w+::)*)(\w+)$/  ) {
+	    my( $pack, $sym )= ( $1, $2 );
+	    $pack= $expto   unless  defined($pack)  &&  "" ne $pack;
+	    no strict 'refs';
+	    *{"${pack}::$sym"}= \${"${pack}::$sym"};
+	    ${"${pack}::$sym"}= $registry;
+	} elsif(  /^\%((?:\w+::)*)(\w+)$/  ) {
+	    my( $pack, $sym )= ( $1, $2 );
+	    $pack= $expto   unless  defined($pack)  &&  "" ne $pack;
+	    no strict 'refs';
+	    *{"${pack}::$sym"}= \%{"${pack}::$sym"};
+	    $registry->Tie( \%{"${pack}::$sym"} );
+	} elsif(  "SCALAR" eq ref($_)  ) {
+	    $$_= $registry;
+	} elsif(  "HASH" eq ref($_)  ) {
+	    $registry->Tie( $_ );
+	} elsif(  /^ObjVar$/  ) {
+	    $_= shift( @_ );
+	    /^\$((?:\w+::)*)(\w+)$/;
+	    my( $pack, $sym )= ( $1, $2 );
+	    $pack= $expto   unless  defined($pack)  &&  "" ne $pack;
+	    no strict 'refs';
+	    *{"${pack}::$sym"}= \${"${pack}::$sym"};
+	    ${"${pack}::$sym"}= $registry->ObjectRef;
+	} elsif(  /^ObjRef$/  ) {
+	    ${shift(@_)}= $registry->ObjectRef;
+	} else {
+	    die "Impossible var to export ($_)";
+	}
+    }
+}
+
+
+use vars qw( @_new_Opts %_new_Opts );
+@_new_Opts= qw( ACCESS DELIM MACHINE DEPENDON );
+@_new_Opts{@_new_Opts}= (1) x @_new_Opts;
+
+sub _new
+{
+    my $this= shift( @_ );
+    $this= tied(%$this)   if  ref($this)  &&  tied(%$this);
+    my $class= ref($this) || $this;
+    my $self= {};
+    my( $handle, $rpath, $opts )= @_;
+    if(  @_ < 2  ||  "ARRAY" ne ref($rpath)  ||  3 < @_
+     ||  3 == @_ && "HASH" ne ref($opts)  ) {
+	croak "Usage:  ${PACK}->_new( \$handle, \\\@path, {OPT=>VAL,...} );\n",
+	      "  options: @_new_Opts\nCalled";
+    }
+    @$self{qw( HANDLE PATH )}= ( $handle, $rpath );
+    @$self{qw( MACHINE ACCESS DELIM OS_DELIM ROOTS FLAGS )}=
+      ( $this->Machine, $this->Access, $this->Delimiter,
+        $this->OS_Delimiter, $this->_Roots, $this->_Flags );
+    if(  ref($opts)  ) {
+	my @err= grep( ! $_new_Opts{$_}, keys(%$opts) );
+	@err  and  croak "${PACK}->_new:  Invalid options (@err)";
+	@$self{ keys(%$opts) }= values(%$opts);
+    }
+    bless $self, $class;
+    return $self;
+}
+
+
+sub _split
+{
+    my $self= shift( @_ );
+    $self= tied(%$self)   if  tied(%$self);
+    my $path= shift( @_ );
+    my $delim= @_ ? shift(@_) : $self->Delimiter;
+    my $list= [ split( /\Q$delim/, $path ) ];
+    return $list;
+}
+
+
+sub _rootKey
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    my $keyPath= shift(@_);
+    my $delim= @_ ? shift(@_) : $self->Delimiter;
+    my( $root, $subPath );
+    if(  "ARRAY" eq ref($keyPath)  ) {
+	$subPath= $keyPath;
+    } else {
+	$subPath= $self->_split( $keyPath, $delim );
+    }
+    $root= shift( @$subPath );
+    if(  $root =~ /^HKEY_/  ) {
+	my $handle= Win32API::Registry::constant($root,0);
+	$handle  or  croak "Invalid HKEY_ constant ($root): $!";
+	return( $self->_new( $handle, [$root], {DELIM=>$delim} ),
+	        $subPath );
+    } elsif(  $root =~ /^([-+]|0x)?\d/  ) {
+	return( $self->_new( $root, [sprintf("0x%lX",$root)],
+			     {DELIM=>$delim} ),
+		$subPath );
+    } else {
+	my $roots= $self->Roots;
+	if(  $roots->{$root}  ) {
+	    return( $self->_new( $roots->{$root}, [$root], {DELIM=>$delim} ),
+	            $subPath );
+	}
+	croak "No such root key ($root)";
+    }
+}
+
+
+sub _open
+{
+    my $this= shift(@_);
+    $this= tied(%$this)   if  ref($this)  &&  tied(%$this);
+    my $subPath= shift(@_);
+    my $sam= @_ ? shift(@_) : $this->Access;
+    my $subKey= join( $this->OS_Delimiter, @$subPath );
+    my $handle= 0;
+    $this->RegOpenKeyEx( $subKey, 0, $sam, $handle )
+      or  return ();
+    return $this->_new( $handle, [ @{$this->_Path}, @$subPath ],
+      { ACCESS=>$sam, ( defined($this->{UNLOADME}) ? ("DEPENDON",$this)
+	: defined($this->{DEPENDON}) ? ("DEPENDON",$this->{DEPENDON}) : () )
+      } );
+}
+
+
+sub ObjectRef
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    return $self;
+}
+
+
+sub _constant
+{
+    my( $name, $desc )= @_;
+    my $value= Win32API::Registry::constant( $name, 0 );
+    my $func= (caller(1))[3];
+    if(  0 == $value  ) {
+	if(  $! =~ /invalid/i  ) {
+	    croak "$func: Invalid $desc ($name)";
+	} elsif(  0 != $!  ) {
+	    croak "$func: \u$desc ($name) not support on this platform";
+	}
+    }
+    return $value;
+}
+
+
+sub _connect
+{
+    my $this= shift(@_);
+    $this= tied(%$this)   if  ref($this)  &&  tied(%$this);
+    my $subPath= pop(@_);
+    $subPath= $this->_split( $subPath )   unless  ref($subPath);
+    my $machine= @_ ? shift(@_) : shift(@$subPath);
+    my $handle= 0;
+    my( $temp )= $this->_rootKey( [@$subPath] );
+    $temp->RegConnectRegistry( $machine, $temp->Handle, $handle )
+      or  return ();
+    my $self= $this->_new( $handle, [shift(@$subPath)], {MACHINE=>$machine} );
+    return( $self, $subPath );
+}
+
+
+use vars qw( @Connect_Opts %Connect_Opts );
+@Connect_Opts= qw(Access Delimiter);
+@Connect_Opts{@Connect_Opts}= (1) x @Connect_Opts;
+
+sub Connect
+{
+    my $this= shift(@_);
+    my $tied=  ref($this)  &&  tied(%$this);
+    $this= tied(%$this)   if  $tied;
+    my( $machine, $key, $opts )= @_;
+    my $delim= "";
+    my $sam;
+    my $subPath;
+    if(  @_ < 2  ||  3 < @_
+     ||  3 == @_ && "HASH" ne ref($opts)  ) {
+	croak "Usage:  \$obj= ${PACK}->Connect(",
+	      " \$Machine, \$subKey, { OPT=>VAL,... } );\n",
+	      "  options: @Connect_Opts\nCalled";
+    }
+    if(  ref($opts)  ) {
+	my @err= grep( ! $Connect_Opts{$_}, keys(%$opts) );
+	@err  and  croak "${PACK}->Connect:  Invalid options (@err)";
+    }
+    $delim= "$opts->{Delimiter}"   if  defined($opts->{Delimiter});
+    $delim= $this->Delimiter   if  "" eq $delim;
+    $sam= defined($opts->{Access}) ? $opts->{Access} : $this->Access;
+    $sam= _constant($sam,"key access type")   if  $sam =~ /^KEY_/;
+    ( $this, $subPath )= $this->_connect( $machine, $key );
+    return ()   unless  defined($this);
+    my $self= $this->_open( $subPath, $sam );
+    return ()   unless  defined($self);
+    $self->Delimiter( $delim );
+    $self= $self->TiedRef   if  $tied;
+    return $self;
+}
+
+
+my @_newVirtual_keys= qw( MEMBERS VALUES SUBKEYS SUBTIMES SUBCLASSES
+    Class SecurityLen LastWrite CntValues CntSubKeys
+    MaxValNameLen MaxValDataLen MaxSubKeyLen MaxSubClassLen );
+
+sub _newVirtual
+{
+    my $self= shift(@_);
+    my( $rPath, $root, $opts )= @_;
+    my $new= $self->_new( "NONE", $rPath, $opts )
+      or  return ();
+    @{$new}{@_newVirtual_keys}= @{$root->ObjectRef}{@_newVirtual_keys};
+    return $new;
+}
+
+
+#$key= new Win32::TieRegistry "LMachine/System/Disk";
+#$key= new Win32::TieRegistry "//Server1/LMachine/System/Disk";
+#Win32::TieRegistry->new( HKEY_LOCAL_MACHINE, {DELIM=>"/",ACCESS=>KEY_READ} );
+#Win32::TieRegistry->new( [ HKEY_LOCAL_MACHINE, ".../..." ], {DELIM=>$DELIM} );
+#$key->new( ... );
+
+use vars qw( @new_Opts %new_Opts );
+@new_Opts= qw(Access Delimiter);
+@new_Opts{@new_Opts}= (1) x @new_Opts;
+
+sub new
+{
+    my $this= shift( @_ );
+    $this= tied(%$this)   if  ref($this)  &&  tied(%$this);
+    if(  ! ref($this)  ) {
+	no strict "refs";
+	my $self= ${"${this}::Registry"};
+	croak "${this}->new failed since ${PACK}::new sees that ",
+	  "\$${this}::Registry is not an object."
+	  if  ! ref($self);
+	$this= $self->Clone;
+    }
+    my( $subKey, $opts )= @_;
+    my $delim= "";
+    my $dlen;
+    my $sam;
+    my $subPath;
+    if(  @_ < 1  ||  2 < @_
+     ||  2 == @_ && "HASH" ne ref($opts)  ) {
+	croak "Usage:  \$obj= ${PACK}->new( \$subKey, { OPT=>VAL,... } );\n",
+	      "  options: @new_Opts\nCalled";
+    }
+    if(  defined($opts)  ) {
+	my @err= grep( ! $new_Opts{$_}, keys(%$opts) );
+	@err  and  die "${PACK}->new:  Invalid options (@err)";
+    }
+    $delim= "$opts->{Delimiter}"   if  defined($opts->{Delimiter});
+    $delim= $this->Delimiter   if  "" eq $delim;
+    $dlen= length($delim);
+    $sam= defined($opts->{Access}) ? $opts->{Access} : $this->Access;
+    $sam= _constant($sam,"key access type")   if  $sam =~ /^KEY_/;
+    if(  "ARRAY" eq ref($subKey)  ) {
+	$subPath= $subKey;
+	if(  "NONE" eq $this->Handle  &&  @$subPath  ) {
+	    ( $this, $subPath )= $this->_rootKey( $subPath );
+	}
+    } elsif(  $delim x 2 eq substr($subKey,0,2*$dlen)  ) {
+	my $path= $this->_split( substr($subKey,2*$dlen), $delim );
+	my $mach= shift(@$path);
+	if(  ! @$path  ) {
+	    return $this->_newVirtual( $path, $Registry,
+			    {MACHINE=>$mach,DELIM=>$delim,ACCESS=>$sam} );
+	}
+	( $this, $subPath )= $this->_connect( $mach, $path );
+	return ()   if  ! defined($this);
+	if(  0 == @$subPath  ) {
+	    $this->Delimiter( $delim );
+	    return $this;
+	}
+    } elsif(  $delim eq substr($subKey,0,$dlen)  ) {
+	( $this, $subPath )= $this->_rootKey( substr($subKey,$dlen), $delim );
+    } elsif(  "NONE" eq $this->Handle  &&  "" ne $subKey  ) {
+	my( $mach )= $this->Machine;
+	if(  $mach  ) {
+	    ( $this, $subPath )= $this->_connect( $mach, $subKey );
+	} else {
+	    ( $this, $subPath )= $this->_rootKey( $subKey, $delim );
+	}
+    } else {
+	$subPath= $this->_split( $subKey, $delim );
+    }
+    return ()   unless  defined($this);
+    if(  0 == @$subPath  &&  "NONE" eq $this->Handle  ) {
+	return $this->_newVirtual( $this->_Path, $this,
+				   { DELIM=>$delim, ACCESS=>$sam } );
+    }
+    my $self= $this->_open( $subPath, $sam );
+    return ()   unless  defined($self);
+    $self->Delimiter( $delim );
+    return $self;
+}
+
+
+sub Open
+{
+    my $self= shift(@_);
+    my $tied=  ref($self)  &&  tied(%$self);
+    $self= tied(%$self)   if  $tied;
+    $self= $self->new( @_ );
+    $self= $self->TiedRef   if  defined($self)  &&  $tied;
+    return $self;
+}
+
+
+sub Clone
+{
+    my $self= shift( @_ );
+    my $new= $self->Open("");
+    return $new;
+}
+
+
+{ my @flush;
+    sub Flush
+    {
+	my $self= shift(@_);
+	$self= tied(%$self)   if  tied(%$self);
+	my( $flush )= shift(@_);
+	@_  and  croak "Usage:  \$key->Flush( \$bFlush );";
+	return 0   if  "NONE" eq $self->Handle;
+	@flush= qw( VALUES SUBKEYS SUBCLASSES SUBTIMES MEMBERS Class
+		    CntSubKeys CntValues MaxSubKeyLen MaxSubClassLen
+		    MaxValNameLen MaxValDataLen SecurityLen LastWrite PREVIDX )
+	  unless  @flush;
+	delete( @$self{@flush} );
+	if(  defined($flush)  &&  $flush  ) {
+	    return $self->RegFlushKey();
+	} else {
+	    return 1;
+	}
+    }
+}
+
+
+sub _DualVal
+{
+    my( $hRef, $num )= @_;
+    if(  $_SetDualVar  &&  $$hRef{$num}  ) {
+	&SetDualVar( $num, "$$hRef{$num}", 0+$num );
+    }
+    return $num;
+}
+
+
+use vars qw( @_RegDataTypes %_RegDataTypes );
+@_RegDataTypes= qw( REG_SZ REG_EXPAND_SZ REG_BINARY REG_LINK REG_MULTI_SZ
+		    REG_DWORD_LITTLE_ENDIAN REG_DWORD_BIG_ENDIAN REG_DWORD
+		    REG_RESOURCE_LIST REG_FULL_RESOURCE_DESCRIPTOR
+		    REG_RESOURCE_REQUIREMENTS_LIST REG_NONE );
+# Make sure that REG_DWORD appears _after_ other REG_DWORD_*
+# items above and that REG_NONE appears _last_.
+foreach(  @_RegDataTypes  ) {
+    $_RegDataTypes{Win32API::Registry::constant($_,0)}= $_;
+}
+
+sub GetValue
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    1 == @_  or  croak "Usage:  (\$data,\$type)= \$key->GetValue('ValName');";
+    my( $valName )= @_;
+    my( $valType, $valData, $dLen )= (0,"",0);
+    return ()   if  "NONE" eq $self->Handle;
+    $self->RegQueryValueEx( $valName, [], $valType, $valData,
+      $dLen= ( defined($self->{MaxValDataLen}) ? $self->{MaxValDataLen} : 0 )
+    )  or  return ();
+    if(  REG_DWORD == $valType  ) {
+	my $val= unpack("L",$valData);
+	$valData= sprintf "0x%08.8lX", $val   if  $self->DWordsToHex;
+	&SetDualVar( $valData, $valData, $val )   if  $self->DualBinVals
+    } elsif(  REG_BINARY == $valType  &&  length($valData) <= 4  ) {
+	&SetDualVar( $valData, $valData, hex reverse unpack("h*",$valData) )
+	  if  $self->DualBinVals;
+    } elsif(  ( REG_SZ == $valType || REG_EXPAND_SZ == $valType )
+          &&  $self->FixSzNulls  ) {
+	substr($valData,-1)= ""   if  "\0" eq substr($valData,-1);
+    } elsif(  REG_MULTI_SZ == $valType  &&  $self->SplitMultis  ) {
+	## $valData =~ s/\0\0$//;	# Why does this often fail??
+	substr($valData,-2)= ""   if  "\0\0" eq substr($valData,-2);
+	$valData= [ split( /\0/, $valData, -1 ) ]
+    }
+    if(  ! wantarray  ) {
+	return $valData;
+    } elsif(  ! $self->DualTypes  ) {
+	return( $valData, $valType );
+    } else {
+	return(  $valData,  _DualVal( \%_RegDataTypes, $valType )  );
+    }
+}
+
+
+sub _ErrNum
+{
+    # return $^E;
+    return Win32::GetLastError();
+}
+
+
+sub _ErrMsg
+{
+    # return $^E;
+    return Win32::FormatMessage( Win32::GetLastError() );
+}
+
+sub _Err
+{
+    my $err;
+    # return $^E;
+    return _ErrMsg   if  ! $_SetDualVar;
+    return &SetDualVar( $err, _ErrMsg, _ErrNum );
+}
+
+sub _NoMoreItems
+{
+    return
+      $_NoMoreItems =~ /^\d/
+        ?  _ErrNum == $_NoMoreItems
+        :  _ErrMsg =~ /$_NoMoreItems/io;
+}
+
+
+sub _FileNotFound
+{
+    return
+      $_FileNotFound =~ /^\d/
+        ?  _ErrNum == $_FileNotFound
+        :  _ErrMsg =~ /$_FileNotFound/io;
+}
+
+
+sub _TooSmall
+{
+    return
+      $_TooSmall =~ /^\d/
+        ?  _ErrNum == $_TooSmall
+        :  _ErrMsg =~ /$_TooSmall/io;
+}
+
+
+sub _MoreData
+{
+    return
+      $_MoreData =~ /^\d/
+        ?  _ErrNum == $_MoreData
+        :  _ErrMsg =~ /$_MoreData/io;
+}
+
+
+sub _enumValues
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    my( @names )= ();
+    my $pos= 0;
+    my $name= "";
+    my $nlen= 1+$self->Information("MaxValNameLen");
+    while(  $self->RegEnumValue($pos++,$name,$nlen,[],[],[],[])  ) {
+	push( @names, $name );
+    }
+    if(  ! _NoMoreItems()  ) {
+	return ();
+    }
+    $self->{VALUES}= \@names;
+    return 1;
+}
+
+
+sub ValueNames
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    @_  and  croak "Usage:  \@names= \$key->ValueNames;";
+    $self->_enumValues   unless  $self->{VALUES};
+    return @{$self->{VALUES}};
+}
+
+
+sub _enumSubKeys
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    my( @subkeys, @classes, @times )= ();
+    my $pos= 0;
+    my( $subkey, $class, $time )= ("","","");
+    my( $namSiz, $clsSiz )= $self->Information(
+			      qw( MaxSubKeyLen MaxSubClassLen ));
+    $namSiz++;  $clsSiz++;
+    while(  $self->RegEnumKeyEx(
+	      $pos++, $subkey, $namSiz, [], $class, $clsSiz, $time )  ) {
+	push( @subkeys, $subkey );
+	push( @classes, $class );
+	push( @times, $time );
+    }
+    if(  ! _NoMoreItems()  ) {
+	return ();
+    }
+    $self->{SUBKEYS}= \@subkeys;
+    $self->{SUBCLASSES}= \@classes;
+    $self->{SUBTIMES}= \@times;
+    return 1;
+}
+
+
+sub SubKeyNames
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    @_  and  croak "Usage:  \@names= \$key->SubKeyNames;";
+    $self->_enumSubKeys   unless  $self->{SUBKEYS};
+    return @{$self->{SUBKEYS}};
+}
+
+
+sub SubKeyClasses
+{
+    my $self= shift(@_);
+    @_  and  croak "Usage:  \@classes= \$key->SubKeyClasses;";
+    $self->_enumSubKeys   unless  $self->{SUBCLASSES};
+    return @{$self->{SUBCLASSES}};
+}
+
+
+sub SubKeyTimes
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    @_  and  croak "Usage:  \@times= \$key->SubKeyTimes;";
+    $self->_enumSubKeys   unless  $self->{SUBTIMES};
+    return @{$self->{SUBTIMES}};
+}
+
+
+sub _MemberNames
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    @_  and  croak "Usage:  \$arrayRef= \$key->_MemberNames;";
+    if(  ! $self->{MEMBERS}  ) {
+	$self->_enumValues   unless  $self->{VALUES};
+	$self->_enumSubKeys   unless  $self->{SUBKEYS};
+	my( @members )= (  map( $_.$self->{DELIM}, @{$self->{SUBKEYS}} ),
+			   map( $self->{DELIM}.$_, @{$self->{VALUES}} )  );
+	$self->{MEMBERS}= \@members;
+    }
+    return $self->{MEMBERS};
+}
+
+
+sub _MembersHash
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    @_  and  croak "Usage:  \$hashRef= \$key->_MembersHash;";
+    if(  ! $self->{MEMBHASH}  ) {
+	my $aRef= $self->_MemberNames;
+	$self->{MEMBHASH}= {};
+	@{$self->{MEMBHASH}}{@$aRef}= (1) x @$aRef;
+    }
+    return $self->{MEMBHASH};
+}
+
+
+sub MemberNames
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    @_  and  croak "Usage:  \@members= \$key->MemberNames;";
+    return @{$self->_MemberNames};
+}
+
+
+sub Information
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    my( $time, $nkeys, $nvals, $xsec, $xkey, $xcls, $xname, $xdata )=
+	("",0,0,0,0,0,0,0);
+    my $clen= 8;
+    if(  ! $self->RegQueryInfoKey( [], [], $nkeys, $xkey, $xcls,
+				   $nvals, $xname, $xdata, $xsec, $time )  ) {
+	return ();
+    }
+    if(  defined($self->{Class})  ) {
+	$clen= length($self->{Class});
+    } else {
+	$self->{Class}= "";
+    }
+    while(  ! $self->RegQueryInfoKey( $self->{Class}, $clen,
+				      [],[],[],[],[],[],[],[],[])
+        &&  _MoreData  ) {
+	$clen *= 2;
+    }
+    my( %info );
+    @info{ qw( LastWrite CntSubKeys CntValues SecurityLen
+	       MaxValDataLen MaxSubKeyLen MaxSubClassLen MaxValNameLen )
+    }=       ( $time,    $nkeys,    $nvals,   $xsec,
+               $xdata,       $xkey,       $xcls,         $xname );
+    if(  @_  ) {
+	my( %check );
+	@check{keys(%info)}= keys(%info);
+	my( @err )= grep( ! $check{$_}, @_ );
+	if(  @err  ) {
+	    croak "${PACK}::Information- Invalid info requested (@err)";
+	}
+	return @info{@_};
+    } else {
+	return %info;
+    }
+}
+
+
+sub Delimiter
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    $self= $RegObj   unless  ref($self);
+    my( $oldDelim )= $self->{DELIM};
+    if(  1 == @_  &&  "" ne "$_[0]"  ) {
+	delete $self->{MEMBERS};
+	delete $self->{MEMBHASH};
+	$self->{DELIM}= "$_[0]";
+    } elsif(  0 != @_  ) {
+	croak "Usage:  \$oldDelim= \$key->Delimiter(\$newDelim);";
+    }
+    return $oldDelim;
+}
+
+
+sub Handle
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    @_  and  croak "Usage:  \$handle= \$key->Handle;";
+    $self= $RegObj   unless  ref($self);
+    return $self->{HANDLE};
+}
+
+
+sub Path
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    @_  and  croak "Usage:  \$path= \$key->Path;";
+    my $delim= $self->{DELIM};
+    $self= $RegObj   unless  ref($self);
+    if(  "" eq $self->{MACHINE}  ) {
+	return(  $delim . join( $delim, @{$self->{PATH}} ) . $delim  );
+    } else {
+	return(  $delim x 2
+	  . join( $delim, $self->{MACHINE}, @{$self->{PATH}} )
+	  . $delim  );
+    }
+}
+
+
+sub _Path
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    @_  and  croak "Usage:  \$arrRef= \$key->_Path;";
+    $self= $RegObj   unless  ref($self);
+    return $self->{PATH};
+}
+
+
+sub Machine
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    @_  and  croak "Usage:  \$machine= \$key->Machine;";
+    $self= $RegObj   unless  ref($self);
+    return $self->{MACHINE};
+}
+
+
+sub Access
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    @_  and  croak "Usage:  \$access= \$key->Access;";
+    $self= $RegObj   unless  ref($self);
+    return $self->{ACCESS};
+}
+
+
+sub OS_Delimiter
+{
+    my $self= shift(@_);
+    @_  and  croak "Usage:  \$backslash= \$key->OS_Delimiter;";
+    return $self->{OS_DELIM};
+}
+
+
+sub _Roots
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  ref($self)  &&  tied(%$self);
+    @_  and  croak "Usage:  \$varName= \$key->_Roots;";
+    $self= $RegObj   unless  ref($self);
+    return $self->{ROOTS};
+}
+
+
+sub Roots
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  ref($self)  &&  tied(%$self);
+    @_  and  croak "Usage:  \$hashRef= \$key->Roots;";
+    $self= $RegObj   unless  ref($self);
+    return eval "\\%$self->{ROOTS}";
+}
+
+
+sub TIEHASH
+{
+    my( $this )= shift(@_);
+    $this= tied(%$this)   if  ref($this)  &&  tied(%$this);
+    my( $key )= @_;
+    if(  1 == @_  &&  ref($key)  &&  "$key" =~ /=/  ) {
+	return $key;	# $key is already an object (blessed reference).
+    }
+    return $this->new( @_ );
+}
+
+
+sub Tie
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    my( $hRef )= @_;
+    if(  1 != @_  ||  ! ref($hRef)  ||  "$hRef" !~ /(^|=)HASH\(/  ) {
+	croak "Usage: \$key->Tie(\\\%hash);";
+    }
+    return  tie %$hRef, ref($self), $self;
+}
+
+
+sub TiedRef
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    my $hRef= @_ ? shift(@_) : {};
+    return ()   if  ! defined($self);
+    $self->Tie($hRef);
+    bless $hRef, ref($self);
+    return $hRef;
+}
+
+
+sub _Flags
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    my $oldFlags= $self->{FLAGS};
+    if(  1 == @_  ) {
+	$self->{FLAGS}= shift(@_);
+    } elsif(  0 != @_  ) {
+	croak "Usage:  \$oldBits= \$key->_Flags(\$newBits);";
+    }
+    return $oldFlags;
+}
+
+
+sub ArrayValues
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    my $oldFlag= $Flag_ArrVal == ( $Flag_ArrVal & $self->{FLAGS} );
+    if(  1 == @_  ) {
+	my $bool= shift(@_);
+	if(  $bool  ) {
+	    $self->{FLAGS} |= $Flag_ArrVal;
+	} else {
+	    $self->{FLAGS} &= ~( $Flag_ArrVal | $Flag_TieVal );
+	}
+    } elsif(  0 != @_  ) {
+	croak "Usage:  \$oldBool= \$key->ArrayValues(\$newBool);";
+    }
+    return $oldFlag;
+}
+
+
+sub TieValues
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    my $oldFlag= $Flag_TieVal == ( $Flag_TieVal & $self->{FLAGS} );
+    if(  1 == @_  ) {
+	my $bool= shift(@_);
+	if(  $bool  ) {
+	    croak "${PACK}->TieValues cannot be enabled with this version";
+	    $self->{FLAGS} |= $Flag_TieVal;
+	} else {
+	    $self->{FLAGS} &= ~$Flag_TieVal;
+	}
+    } elsif(  0 != @_  ) {
+	croak "Usage:  \$oldBool= \$key->TieValues(\$newBool);";
+    }
+    return $oldFlag;
+}
+
+
+sub FastDelete
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    my $oldFlag= $Flag_FastDel == ( $Flag_FastDel & $self->{FLAGS} );
+    if(  1 == @_  ) {
+	my $bool= shift(@_);
+	if(  $bool  ) {
+	    $self->{FLAGS} |= $Flag_FastDel;
+	} else {
+	    $self->{FLAGS} &= ~$Flag_FastDel;
+	}
+    } elsif(  0 != @_  ) {
+	croak "Usage:  \$oldBool= \$key->FastDelete(\$newBool);";
+    }
+    return $oldFlag;
+}
+
+
+sub SplitMultis
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    my $oldFlag= $Flag_Split == ( $Flag_Split & $self->{FLAGS} );
+    if(  1 == @_  ) {
+	my $bool= shift(@_);
+	if(  $bool  ) {
+	    $self->{FLAGS} |= $Flag_Split;
+	} else {
+	    $self->{FLAGS} &= ~$Flag_Split;
+	}
+    } elsif(  0 != @_  ) {
+	croak "Usage:  \$oldBool= \$key->SplitMultis(\$newBool);";
+    }
+    return $oldFlag;
+}
+
+
+sub DWordsToHex
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    my $oldFlag= $Flag_HexDWord == ( $Flag_HexDWord & $self->{FLAGS} );
+    if(  1 == @_  ) {
+	my $bool= shift(@_);
+	if(  $bool  ) {
+	    $self->{FLAGS} |= $Flag_HexDWord;
+	} else {
+	    $self->{FLAGS} &= ~$Flag_HexDWord;
+	}
+    } elsif(  0 != @_  ) {
+	croak "Usage:  \$oldBool= \$key->DWordsToHex(\$newBool);";
+    }
+    return $oldFlag;
+}
+
+
+sub FixSzNulls
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    my $oldFlag= $Flag_FixNulls == ( $Flag_FixNulls & $self->{FLAGS} );
+    if(  1 == @_  ) {
+	my $bool= shift(@_);
+	if(  $bool  ) {
+	    $self->{FLAGS} |= $Flag_FixNulls;
+	} else {
+	    $self->{FLAGS} &= ~$Flag_FixNulls;
+	}
+    } elsif(  0 != @_  ) {
+	croak "Usage:  \$oldBool= \$key->FixSzNulls(\$newBool);";
+    }
+    return $oldFlag;
+}
+
+
+sub DualTypes
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    my $oldFlag= $Flag_DualTyp == ( $Flag_DualTyp & $self->{FLAGS} );
+    if(  1 == @_  ) {
+	my $bool= shift(@_);
+	if(  $bool  ) {
+	    croak "${PACK}->DualTypes cannot be enabled since ",
+		  "SetDualVar module not installed"
+	      unless  $_SetDualVar;
+	    $self->{FLAGS} |= $Flag_DualTyp;
+	} else {
+	    $self->{FLAGS} &= ~$Flag_DualTyp;
+	}
+    } elsif(  0 != @_  ) {
+	croak "Usage:  \$oldBool= \$key->DualTypes(\$newBool);";
+    }
+    return $oldFlag;
+}
+
+
+sub DualBinVals
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    my $oldFlag= $Flag_DualBin == ( $Flag_DualBin & $self->{FLAGS} );
+    if(  1 == @_  ) {
+	my $bool= shift(@_);
+	if(  $bool  ) {
+	    croak "${PACK}->DualBinVals cannot be enabled since ",
+		  "SetDualVar module not installed"
+	      unless  $_SetDualVar;
+	    $self->{FLAGS} |= $Flag_DualBin;
+	} else {
+	    $self->{FLAGS} &= ~$Flag_DualBin;
+	}
+    } elsif(  0 != @_  ) {
+	croak "Usage:  \$oldBool= \$key->DualBinVals(\$newBool);";
+    }
+    return $oldFlag;
+}
+
+
+sub GetOptions
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    my( $opt, $meth );
+    if(  ! @_  ||  1 == @_  &&  "HASH" eq ref($_[0])  ) {
+	my $href= @_ ? $_[0] : {};
+	foreach $opt (  grep !/^Allow/, @_opt_subs  ) {
+	    $meth= $_opt_subs{$opt};
+	    $href->{$opt}=  $self->$meth();
+	}
+	return @_ ? $self : $href;
+    }
+    my @old;
+    foreach $opt (  @_  ) {
+	$meth= $_opt_subs{$opt};
+	if(  defined $meth  ) {
+	    if(  $opt eq "AllowLoad"  ||  $opt eq "AllowSave"  ) {
+		croak "${PACK}->GetOptions:  Getting current setting of $opt ",
+		      "not supported in this release";
+	    }
+	    push(  @old,  $self->$meth()  );
+	} else {
+	    croak "${PACK}->GetOptions:  Invalid option ($opt) ",
+		  "not one of ( ", join(" ",grep !/^Allow/, @_opt_subs), " )";
+	}
+    }
+    return wantarray ? @old : $old[-1];
+}
+
+
+sub SetOptions
+{
+    my $self= shift(@_);
+    # Don't get object if hash ref so "ref" returns original ref.
+    my( $opt, $meth, @old );
+    while(  @_  ) {
+	$opt= shift(@_);
+	$meth= $_opt_subs{$opt};
+	if(  ! @_  ) {
+	    croak "${PACK}->SetOptions:  Option value missing ",
+		  "after option name ($opt)";
+	} elsif(  defined $meth  ) {
+	    push(  @old,  $self->$meth( shift(@_) )  );
+	} elsif(  $opt eq substr("reference",0,length($opt))  ) {
+	    shift(@_)   if  @_;
+	    push(  @old,  $self  );
+	} else {
+	    croak "${PACK}->SetOptions:  Invalid option ($opt) ",
+		  "not one of ( @_opt_subs )";
+	}
+    }
+    return wantarray ? @old : $old[-1];
+}
+
+
+sub _parseTiedEnt
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    my $ent= shift(@_);
+    my $delim= shift(@_);
+    my $dlen= length( $delim );
+    my $parent= @_ ? shift(@_) : 0;
+    my $off;
+    if(  $delim x 2 eq substr($ent,0,2*$dlen)  &&  "NONE" eq $self->Handle  ) {
+	if(  0 <= ( $off= index( $ent, $delim x 2, 2*$dlen ) )  ) {
+	    return(  substr( $ent, 0, $off ),  substr( $ent, 2*$dlen+$off )  );
+	} elsif(  $delim eq substr($ent,-$dlen)  ) {
+	    return( substr($ent,0,-$dlen) );
+	} elsif(  2*$dlen <= ( $off= rindex( $ent, $delim ) )  ) {
+	    return(  substr( $ent, 0, $off ),
+	      undef,  substr( $ent, $dlen+$off )  );
+	} elsif(  $parent  ) {
+	    return();
+	} else {
+	    return( $ent );
+	}
+    } elsif(  $delim eq substr($ent,0,$dlen)  &&  "NONE" ne $self->Handle  ) {
+	return( undef, substr($ent,$dlen) );
+    } elsif(  $self->{MEMBERS}  &&  $self->_MembersHash->{$ent}  ) {
+	return( substr($ent,0,-$dlen) );
+    } elsif(  0 <= ( $off= index( $ent, $delim x 2 ) )  ) {
+	return(  substr( $ent, 0, $off ),  substr( $ent, 2*$dlen+$off ) );
+    } elsif(  $delim eq substr($ent,-$dlen)  ) {
+	if(  $parent
+	 &&  0 <= ( $off= rindex( $ent, $delim, length($ent)-2*$dlen ) )  ) {
+	    return(  substr($ent,0,$off),
+	      undef,  undef,  substr($ent,$dlen+$off,-$dlen)  );
+	} else {
+	    return( substr($ent,0,-$dlen) );
+	}
+    } elsif(  0 <= ( $off= rindex( $ent, $delim ) )  ) {
+	return(
+	  substr( $ent, 0, $off ),  undef,  substr( $ent, $dlen+$off )  );
+    } else {
+	return( undef, undef, $ent );
+    }
+}
+
+
+sub _FetchValue
+{
+    my $self= shift( @_ );
+    my( $val, $createKey )= @_;
+    my( $data, $type );
+    if(  ( $data, $type )= $self->GetValue( $val )  ) {
+	return $self->ArrayValues ? [ $data, $type ]
+	       : wantarray        ? ( $data, $type )
+				  : $data;
+    } elsif(  $createKey  and  $data= $self->new($val)  ) {
+	return $data->TiedRef;
+    } else {
+	return ();
+    }
+}
+
+
+sub FETCH
+{
+    my $self= shift(@_);
+    my $ent= shift(@_);
+    my $delim= $self->Delimiter;
+    my( $key, $val, $ambig )= $self->_parseTiedEnt( $ent, $delim, 0 );
+    my $sub;
+    if(  defined($key)  ) {
+	if(  defined($self->{MEMBHASH})
+	 &&  $self->{MEMBHASH}->{$key.$delim}
+	 &&  0 <= index($key,$delim)  ) {
+	    return ()
+	      unless  $sub= $self->new( $key,
+			      {"Delimiter"=>$self->OS_Delimiter} );
+	    $sub->Delimiter($delim);
+	} else {
+	    return ()
+	      unless  $sub= $self->new( $key );
+	}
+    } else {
+	$sub= $self;
+    }
+    if(  defined($val)  ) {
+	return $sub->_FetchValue( $val );
+    } elsif(  ! defined($ambig)  ) {
+	return $sub->TiedRef;
+    } elsif(  defined($key)  ) {
+	return $sub->FETCH(  $ambig  );
+    } else {
+	return $sub->_FetchValue( $ambig, "" ne $ambig );
+    }
+}
+
+
+sub _FetchOld
+{
+    my( $self, $key )= @_;
+    my $old= $self->FETCH($key);
+    if(  $old  ) {
+	my $copy= {};
+	%$copy= %$old;
+	return $copy;
+    }
+    # return $^E;
+    return _Err;
+}
+
+
+sub DELETE
+{
+    my $self= shift(@_);
+    my $ent= shift(@_);
+    my $delim= $self->Delimiter;
+    my( $key, $val, $ambig, $subkey )= $self->_parseTiedEnt( $ent, $delim, 1 );
+    my $sub;
+    my $fast= defined(wantarray) ? $self->FastDelete : 2;
+    my $old= 1;	# Value returned if FastDelete is set.
+    if(  defined($key)
+     &&  ( defined($val) || defined($ambig) || defined($subkey) )  ) {
+	return ()
+	  unless  $sub= $self->new( $key );
+    } else {
+	$sub= $self;
+    }
+    if(  defined($val)  ) {
+	$old= $sub->GetValue($val) || _Err   unless  2 <= $fast;
+	$sub->RegDeleteValue( $val );
+    } elsif(  defined($subkey)  ) {
+	$old= $sub->_FetchOld( $subkey.$delim )   unless  $fast;
+	$sub->RegDeleteKey( $subkey );
+    } elsif(  defined($ambig)  ) {
+	if(  defined($key)  ) {
+	    $old= $sub->DELETE($ambig);
+	} else {
+	    $old= $sub->GetValue($ambig) || _Err   unless  2 <= $fast;
+	    if(  defined( $old )  ) {
+		$sub->RegDeleteValue( $ambig );
+	    } else {
+		$old= $sub->_FetchOld( $ambig.$delim )   unless  $fast;
+		$sub->RegDeleteKey( $ambig );
+	    }
+	}
+    } elsif(  defined($key)  ) {
+	$old= $sub->_FetchOld( $key.$delim )   unless  $fast;
+	$sub->RegDeleteKey( $key );
+    } else {
+	croak "${PACK}->DELETE:  Key ($ent) can never be deleted";
+    }
+    return $old;
+}
+
+
+sub SetValue
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    my $name= shift(@_);
+    my $data= shift(@_);
+    my( $type )= @_;
+    my $size;
+    if(  ! defined($type)  ) {
+	if(  "ARRAY" eq ref($data)  ) {
+	    croak "${PACK}->SetValue:  Value is array reference but ",
+		  "no data type given"
+	      unless  2 == @$data;
+	    ( $data, $type )= @$data;
+	} else {
+	    $type= REG_SZ;
+	}
+    }
+    $type= _constant($type,"registry value data type")   if  $type =~ /^REG_/;
+    if(  REG_MULTI_SZ == $type  &&  "ARRAY" eq ref($data)  ) {
+	$data= join( "\0", @$data ) . "\0\0";
+	## $data= pack(  "a*" x (1+@$data),  map( $_."\0", @$data, "" )  );
+    } elsif(  ( REG_SZ == $type || REG_EXPAND_SZ == $type )
+          &&  $self->FixSzNulls  ) {
+	$data .= "\0"    unless  "\0" eq substr($data,0,-1);
+    } elsif(  REG_DWORD == $type  &&  $data =~ /^0x[0-9a-fA-F]{3,}$/  ) {
+	$data= pack( "L", hex($data) );
+	# We could to $data=pack("L",$data) for REG_DWORD but I see
+	# no nice way to always destinguish when to do this or not.
+    }
+    return $self->RegSetValueEx( $name, 0, $type, $data, length($data) );
+}
+
+
+sub StoreKey
+{
+    my $this= shift(@_);
+    $this= tied(%$this)   if  ref($this)  &&  tied(%$this);
+    my $subKey= shift(@_);
+    my $data= shift(@_);
+    my $ent;
+    my $self;
+    if(  ! ref($data)  ||  "$data" !~ /(^|=)HASH/  ) {
+	croak "${PACK}->StoreKey:  For ", $this->Path.$subKey, ",\n",
+	      "  subkey data must be a HASH reference";
+    }
+    if(  defined( $$data{""} )  &&  "HASH" eq ref($$data{""})  ) {
+	$self= $this->CreateKey( $subKey, delete $$data{""} );
+    } else {
+	$self= $this->CreateKey( $subKey );
+    }
+    return ()   if  ! defined($self);
+    foreach $ent (  keys(%$data)  ) {
+	return ()
+	  unless  $self->STORE( $ent, $$data{$ent} );
+    }
+    return $self;
+}
+
+
+# = { "" => {OPT=>VAL}, "val"=>[], "key"=>{} } creates a new key
+# = "string" creates a new REG_SZ value
+# = [ data, type ] creates a new value
+sub STORE
+{
+    my $self= shift(@_);
+    my $ent= shift(@_);
+    my $data= shift(@_);
+    my $delim= $self->Delimiter;
+    my( $key, $val, $ambig, $subkey )= $self->_parseTiedEnt( $ent, $delim, 1 );
+    my $sub;
+    if(  defined($key)
+     &&  ( defined($val) || defined($ambig) || defined($subkey) )  ) {
+	return ()
+	  unless  $sub= $self->new( $key );
+    } else {
+	$sub= $self;
+    }
+    if(  defined($val)  ) {
+	croak "${PACK}->STORE:  For ", $sub->Path.$delim.$val, ",\n",
+	      "  value data cannot be a HASH reference"
+	  if  ref($data)  &&  "$data" =~ /(^|=)HASH/;
+	$sub->SetValue( $val, $data );
+    } elsif(  defined($subkey)  ) {
+	croak "${PACK}->STORE:  For ", $sub->Path.$subkey.$delim, ",\n",
+	      "  subkey data must be a HASH reference"
+	  unless  ref($data)  &&  "$data" =~ /(^|=)HASH/;
+	$sub->StoreKey( $subkey, $data );
+    } elsif(  defined($ambig)  ) {
+	if(  ref($data)  &&  "$data" =~ /(^|=)HASH/  ) {
+	    $sub->StoreKey( $ambig, $data );
+	} else {
+	    $sub->SetValue( $ambig, $data );
+	}
+    } elsif(  defined($key)  ) {
+	croak "${PACK}->STORE:  For ", $sub->Path.$key.$delim, ",\n",
+	      "  subkey data must be a HASH reference"
+	  unless  ref($data)  &&  "$data" =~ /(^|=)HASH/;
+	$sub->StoreKey( $key, $data );
+    } else {
+	croak "${PACK}->STORE:  Key ($ent) can never be created nor set";
+    }
+}
+
+
+sub EXISTS
+{
+    my $self= shift(@_);
+    my $ent= shift(@_);
+    return defined( $self->FETCH($ent) );
+}
+
+
+sub FIRSTKEY
+{
+    my $self= shift(@_);
+    my $members= $self->_MemberNames;
+    $self->{PREVIDX}= 0;
+    return @{$members} ? $members->[0] : undef;
+}
+
+
+sub NEXTKEY
+{
+    my $self= shift(@_);
+    my $prev= shift(@_);
+    my $idx= $self->{PREVIDX};
+    my $members= $self->_MemberNames;
+    if(  ! defined($idx)  ||  $prev ne $members->[$idx]  ) {
+	$idx= 0;
+	while(  $idx < @$members  &&  $prev ne $members->[$idx]  ) {
+	    $idx++;
+	}
+    }
+    $self->{PREVIDX}= ++$idx;
+    return $members->[$idx];
+}
+
+
+sub DESTROY
+{
+    my $self= shift(@_);
+    return   if  tied(%$self);
+    my $unload;
+    eval { $unload= $self->{UNLOADME}; 1 }
+	or  return;
+    my $debug= $ENV{DEBUG_TIE_REGISTRY};
+    if(  defined($debug)  ) {
+	if(  1 < $debug  ) {
+	    my $hand= $self->Handle;
+	    my $dep= $self->{DEPENDON};
+	    carp "${PACK} destroying ", $self->Path, " (",
+		 "NONE" eq $hand ? $hand : sprintf("0x%lX",$hand), ")",
+		 defined($dep) ? (" [depends on ",$dep->Path,"]") : ();
+	} else {
+	    warn "${PACK} destroying ", $self->Path, ".\n";
+	}
+    }
+    $self->RegCloseKey
+      unless  "NONE" eq $self->Handle;
+    if(  defined($unload)  ) {
+	if(  defined($debug)  &&  1 < $debug  ) {
+	    my( $obj, $subKey, $file )= @$unload;
+	    warn "Unloading ", $self->Path,
+	      " (from ", $obj->Path, ", $subKey)...\n";
+	}
+	$self->UnLoad
+	  ||  warn "Couldn't unload ", $self->Path, ": ", _ErrMsg, "\n";
+	## carp "Never unloaded ${PACK}::Load($$unload[2])";
+    }
+    #delete $self->{DEPENDON};
+}
+
+
+use vars qw( @CreateKey_Opts %CreateKey_Opts %_KeyDispNames );
+@CreateKey_Opts= qw( Access Class Options Delimiter
+		     Disposition Security Volatile Backup );
+@CreateKey_Opts{@CreateKey_Opts}= (1) x @CreateKey_Opts;
+%_KeyDispNames= ( REG_CREATED_NEW_KEY() => "REG_CREATED_NEW_KEY",
+		  REG_OPENED_EXISTING_KEY() => "REG_OPENED_EXISTING_KEY" );
+
+sub CreateKey
+{
+    my $self= shift(@_);
+    my $tied= tied(%$self);
+    $self= tied(%$self)   if  $tied;
+    my( $subKey, $opts )= @_;
+    my( $sam )= $self->Access;
+    my( $delim )= $self->Delimiter;
+    my( $class )= "";
+    my( $flags )= 0;
+    my( $secure )= [];
+    my( $garb )= [];
+    my( $result )= \$garb;
+    my( $handle )= 0;
+    if(  @_ < 1  ||  2 < @_
+     ||  2 == @_ && "HASH" ne ref($opts)  ) {
+	croak "Usage:  \$new= \$old->CreateKey( \$subKey, {OPT=>VAL,...} );\n",
+	      "  options: @CreateKey_Opts\nCalled";
+    }
+    if(  defined($opts)  ) {
+	$sam= $opts->{"Access"}   if  defined($opts->{"Access"});
+	$class= $opts->{Class}   if  defined($opts->{Class});
+	$flags= $opts->{Options}   if  defined($opts->{Options});
+	$delim= $opts->{"Delimiter"}   if  defined($opts->{"Delimiter"});
+	$secure= $opts->{Security}   if  defined($opts->{Security});
+	if(  defined($opts->{Disposition})  ) {
+	    "SCALAR" eq ref($opts->{Disposition})
+	      or  croak "${PACK}->CreateKey option `Disposition'",
+			" must provide a scalar reference";
+	    $result= $opts->{Disposition};
+	}
+	if(  0 == $flags  ) {
+	    $flags |= REG_OPTION_VOLATILE
+	      if  defined($opts->{Volatile})  &&  $opts->{Volatile};
+	    $flags |= REG_OPTION_BACKUP_RESTORE
+	      if  defined($opts->{Backup})  &&  $opts->{Backup};
+	}
+    }
+    my $subPath= ref($subKey) ? $subKey : $self->_split($subKey,$delim);
+    $subKey= join( $self->OS_Delimiter, @$subPath );
+    $self->RegCreateKeyEx( $subKey, 0, $class, $flags, $sam,
+			   $secure, $handle, $$result )
+      or  return ();
+    if(  ! ref($$result)  &&  $self->DualTypes  ) {
+	$$result= _DualVal( \%_KeyDispNames, $$result );
+    }
+    my $new= $self->_new( $handle, [ @{$self->_Path}, @{$subPath} ] );
+    $new->{ACCESS}= $sam;
+    $new->{DELIM}= $delim;
+    $new= $new->TiedRef   if  $tied;
+    return $new;
+}
+
+
+use vars qw( $Load_Cnt @Load_Opts %Load_Opts );
+$Load_Cnt= 0;
+@Load_Opts= qw(NewSubKey);
+@Load_Opts{@Load_Opts}= (1) x @Load_Opts;
+
+sub Load
+{
+    my $this= shift(@_);
+    my $tied=  ref($this)  &&  tied(%$this);
+    $this= tied(%$this)   if  $tied;
+    my( $file, $subKey, $opts )= @_;
+    if(  2 == @_  &&  "HASH" eq ref($subKey)  ) {
+	$opts= $subKey;
+	undef $subKey;
+    }
+    @_ < 1  ||  3 < @_  ||  defined($opts) && "HASH" ne ref($opts)
+      and  croak "Usage:  \$key= ",
+	     "${PACK}->Load( \$fileName, [\$newSubKey,] {OPT=>VAL...} );\n",
+	     "  options: @Load_Opts @new_Opts\nCalled";
+    if(  defined($opts)  &&  exists($opts->{NewSubKey})  ) {
+	$subKey= delete $opts->{NewSubKey};
+    }
+    if(  ! defined( $subKey )  ) {
+	if(  "" ne $this->Machine  ) {
+	    ( $this )= $this->_connect( [$this->Machine,"LMachine"] );
+	} else {
+	    ( $this )= $this->_rootKey( "LMachine" );	# Could also be "Users"
+	}
+	$subKey= "PerlTie:$$." . ++$Load_Cnt;
+    }
+    $this->RegLoadKey( $subKey, $file )
+      or  return ();
+    my $self= $this->new( $subKey, defined($opts) ? $opts : () );
+    if(  ! defined( $self )  ) {
+	{ my $err= Win32::GetLastError();
+	#{ local( $^E ); #}
+	    $this->RegUnLoadKey( $subKey )  or  carp
+	      "Can't unload $subKey from ", $this->Path, ": ", _ErrMsg, "\n";
+	    Win32::SetLastError($err);
+	}
+	return ();
+    }
+    $self->{UNLOADME}= [ $this, $subKey, $file ];
+    $self= $self->TiedRef   if  $tied;
+    return $self;
+}
+
+
+sub UnLoad
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    @_  and  croak "Usage:  \$key->UnLoad;";
+    my $unload= $self->{UNLOADME};
+    "ARRAY" eq ref($unload)
+      or  croak "${PACK}->UnLoad called on a key which was not Load()ed";
+    my( $obj, $subKey, $file )= @$unload;
+    $self->RegCloseKey;
+    return Win32API::Registry::RegUnLoadKey( $obj->Handle, $subKey );
+}
+
+
+sub AllowSave
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    return $self->AllowPriv( "SeBackupPrivilege", @_ );
+}
+
+
+sub AllowLoad
+{
+    my $self= shift(@_);
+    $self= tied(%$self)   if  tied(%$self);
+    return $self->AllowPriv( "SeRestorePrivilege", @_ );
+}
+
+
+# RegNotifyChangeKeyValue( hKey, bWatchSubtree, iNotifyFilter, hEvent, bAsync )
+
+
+sub RegCloseKey { my $self= shift(@_);
+    Win32API::Registry::RegCloseKey $self->Handle, @_; }
+sub RegConnectRegistry { my $self= shift(@_);
+    Win32API::Registry::RegConnectRegistry @_; }
+sub RegCreateKey { my $self= shift(@_);
+    Win32API::Registry::RegCreateKey $self->Handle, @_; }
+sub RegCreateKeyEx { my $self= shift(@_);
+    Win32API::Registry::RegCreateKeyEx $self->Handle, @_; }
+sub RegDeleteKey { my $self= shift(@_);
+    Win32API::Registry::RegDeleteKey $self->Handle, @_; }
+sub RegDeleteValue { my $self= shift(@_);
+    Win32API::Registry::RegDeleteValue $self->Handle, @_; }
+sub RegEnumKey { my $self= shift(@_);
+    Win32API::Registry::RegEnumKey $self->Handle, @_; }
+sub RegEnumKeyEx { my $self= shift(@_);
+    Win32API::Registry::RegEnumKeyEx $self->Handle, @_; }
+sub RegEnumValue { my $self= shift(@_);
+    Win32API::Registry::RegEnumValue $self->Handle, @_; }
+sub RegFlushKey { my $self= shift(@_);
+    Win32API::Registry::RegFlushKey $self->Handle, @_; }
+sub RegGetKeySecurity { my $self= shift(@_);
+    Win32API::Registry::RegGetKeySecurity $self->Handle, @_; }
+sub RegLoadKey { my $self= shift(@_);
+    Win32API::Registry::RegLoadKey $self->Handle, @_; }
+sub RegNotifyChangeKeyValue { my $self= shift(@_);
+    Win32API::Registry::RegNotifyChangeKeyValue $self->Handle, @_; }
+sub RegOpenKey { my $self= shift(@_);
+    Win32API::Registry::RegOpenKey $self->Handle, @_; }
+sub RegOpenKeyEx { my $self= shift(@_);
+    Win32API::Registry::RegOpenKeyEx $self->Handle, @_; }
+sub RegQueryInfoKey { my $self= shift(@_);
+    Win32API::Registry::RegQueryInfoKey $self->Handle, @_; }
+sub RegQueryMultipleValues { my $self= shift(@_);
+    Win32API::Registry::RegQueryMultipleValues $self->Handle, @_; }
+sub RegQueryValue { my $self= shift(@_);
+    Win32API::Registry::RegQueryValue $self->Handle, @_; }
+sub RegQueryValueEx { my $self= shift(@_);
+    Win32API::Registry::RegQueryValueEx $self->Handle, @_; }
+sub RegReplaceKey { my $self= shift(@_);
+    Win32API::Registry::RegReplaceKey $self->Handle, @_; }
+sub RegRestoreKey { my $self= shift(@_);
+    Win32API::Registry::RegRestoreKey $self->Handle, @_; }
+sub RegSaveKey { my $self= shift(@_);
+    Win32API::Registry::RegSaveKey $self->Handle, @_; }
+sub RegSetKeySecurity { my $self= shift(@_);
+    Win32API::Registry::RegSetKeySecurity $self->Handle, @_; }
+sub RegSetValue { my $self= shift(@_);
+    Win32API::Registry::RegSetValue $self->Handle, @_; }
+sub RegSetValueEx { my $self= shift(@_);
+    Win32API::Registry::RegSetValueEx $self->Handle, @_; }
+sub RegUnLoadKey { my $self= shift(@_);
+    Win32API::Registry::RegUnLoadKey $self->Handle, @_; }
+sub AllowPriv { my $self= shift(@_);
+    Win32API::Registry::AllowPriv @_; }
+
+
+# Autoload methods go after =cut, and are processed by the autosplit program.
+
+1;
+__END__
+
+=head1 NAME
+
+Win32::TieRegistry - Powerful and easy ways to manipulate a registry
+[on Win32 for now].
+
+=head1 SYNOPSIS
+
+  use Win32::TieRegistry 0.20 ( UseOptionName=>UseOptionValue[,...] );
+
+  $Registry->SomeMethodCall(arg1,...);
+
+  $subKey= $Registry->{"Key\\SubKey\\"};
+  $valueData= $Registry->{"Key\\SubKey\\\\ValueName"};
+  $Registry->{"Key\\SubKey\\"}= { "NewSubKey" => {...} };
+  $Registry->{"Key\\SubKey\\\\ValueName"}= "NewValueData";
+  $Registry->{"\\ValueName"}= [ pack("fmt",$data), REG_DATATYPE ];
+
+=head1 EXAMPLES
+
+  use Win32::TieRegistry( Delimiter=>"#", ArrayValues=>0 );
+  $pound= $Registry->Delimiter("/");
+  $diskKey= $Registry->{"LMachine/System/Disk/"}
+    or  die "Can't read LMachine/System/Disk key: $^E\n";
+  $data= $key->{"/Information"}
+    or  die "Can't read LMachine/System/Disk//Information value: $^E\n";
+  $remoteKey= $Registry->{"//ServerA/LMachine/System/"}
+    or  die "Can't read //ServerA/LMachine/System/ key: $^E\n";
+  $remoteData= $remoteKey->{"Disk//Information"}
+    or  die "Can't read ServerA's System/Disk//Information value: $^E\n";
+  foreach $entry (  keys(%$diskKey)  ) {
+      ...
+  }
+  foreach $subKey (  $diskKey->SubKeyNames  ) {
+      ...
+  }
+  $diskKey->AllowSave( 1 );
+  $diskKey->RegSaveKey( "C:/TEMP/DiskReg", [] );
+
+=head1 DESCRIPTION
+
+The I<Win32::TieRegistry> module lets you manipulate the Registry
+via objects [as in "object oriented"] or via tied hashes.  But
+you will probably mostly use a combination reference, that is, a
+reference to a tied hash that has also been made an object so that
+you can mix both access methods [as shown above].
+
+If you did not get this module as part of L<libwin32>, you might
+want to get a recent version of L<libwin32> from CPAN which should
+include this module and the I<Win32API::Registry> module that it
+uses.
+
+Skip to the L<SUMMARY> section if you just want to dive in and start
+using the Registry from Perl.
+
+Accessing and manipulating the registry is extremely simple using
+I<Win32::TieRegistry>.  A single, simple expression can return
+you almost any bit of information stored in the Registry.
+I<Win32::TieRegistry> also gives you full access to the "raw"
+underlying API calls so that you can do anything with the Registry
+in Perl that you could do in C.  But the "simple" interface has
+been carefully designed to handle almost all operations itself
+without imposing arbitrary limits while providing sensible
+defaults so you can list only the parameters you care about.
+
+But first, an overview of the Registry itself.
+
+=head2 The Registry
+
+The Registry is a forest:  a collection of several tree structures.
+The root of each tree is a key.  These root keys are identified by
+predefined constants whose names start with "HKEY_".  Although all
+keys have a few attributes associated with each [a class, a time
+stamp, and security information], the most important aspect of keys
+is that each can contain subkeys and can contain values.
+
+Each subkey has a name:  a string which cannot be blank and cannot
+contain the delimiter character [backslash: C<'\\'>] nor nul
+[C<'\0'>].  Each subkey is also a key and so can contain subkeys
+and values [and has a class, time stamp, and security information].
+
+Each value has a name:  a string which E<can> be blank and E<can>
+contain the delimiter character [backslash: C<'\\'>] and any
+character except for null, C<'\0'>.  Each value also has data
+associated with it.  Each value's data is a contiguous chunk of
+bytes, which is exactly what a Perl string value is so Perl
+strings will usually be used to represent value data.
+
+Each value also has a data type which says how to interpret the
+value data.  The primary data types are:
+
+=over
+
+=item REG_SZ
+
+A null-terminated string.
+
+=item REG_EXPAND_SZ
+
+A null-terminated string which contains substrings consisting of a
+percent sign [C<'%'>], an environment variable name, then a percent
+sign, that should be replaced with the value associate with that
+environment variable.  The system does I<not> automatically do this
+substitution.
+
+=item REG_BINARY
+
+Some arbitrary binary value.  You can think of these as being
+"packed" into a string.
+
+If your system has the L<SetDualVar> module installed,
+the C<DualBinVals()> option wasn't turned off, and you
+fetch a C<REG_BINARY> value of 4 bytes or fewer, then
+you can use the returned value in a numeric context to
+get at the "unpacked" numeric value.  See C<GetValue()>
+for more information.
+
+=item REG_MULTI_SZ
+
+Several null-terminated strings concatenated together with an
+extra trailing C<'\0'> at the end of the list.  Note that the list
+can include empty strings so use the value's length to determine
+the end of the list, not the first occurrence of C<'\0\0'>.
+It is best to set the C<SplitMultis()> option so I<Win32::TieRegistry>
+will split these values into an array of strings for you.
+
+=item REG_DWORD
+
+A long [4-byte] integer value.  These values are expected either
+packed into a 4-character string or as a hex string of E<more than>
+4 characters [but I<not> as a numeric value, unfortunately, as there is
+no sure way to tell a numeric value from a packed 4-byte string that
+just happens to be a string containing a valid numeric value].
+
+How such values are returned depends on the C<DualBinVals()> and
+C<DWordsToHex()> options.  See C<GetValue()> for details.
+
+=back
+
+In the underlying Registry calls, most places which take a
+subkey name also allow you to pass in a subkey "path" -- a
+string of several subkey names separated by the delimiter
+character, backslash [C<'\\'>].  For example, doing
+C<RegOpenKeyEx(HKEY_LOCAL_MACHINE,"SYSTEM\\DISK",...)> is much
+like opening the C<"SYSTEM"> subkey of C<HKEY_LOCAL_MACHINE>,
+then opening its C<"DISK"> subkey, then closing the C<"SYSTEM">
+subkey.
+
+All of the I<Win32::TieRegistry> features allow you to use your
+own delimiter in place of the system's delimiter, [C<'\\'>].  In
+most of our examples we will use a forward slash [C<'/'>] as our
+delimiter as it is easier to read and less error prone to use when
+writing Perl code since you have to type two backslashes for each
+backslash you want in a string.  Note that this is true even when
+using single quotes -- C<'\\HostName\LMachine\'> is an invalid
+string and must be written as C<'\\\\HostName\\LMachine\\'>.
+
+You can also connect to the registry of other computers on your
+network.  This will be discussed more later.
+
+Although the Registry does not have a single root key, the
+I<Win32::TieRegistry> module creates a virtual root key for you
+which has all of the I<HKEY_*> keys as subkeys.
+
+=head2 Tied Hashes Documentation
+
+Before you can use a tied hash, you must create one.  One way to
+do that is via:
+
+    use Win32::TieRegistry ( TiedHash => '%RegHash' );
+
+which exports a C<%RegHash> variable into your package and ties it
+to the virtual root key of the Registry.  An alternate method is:
+
+    my %RegHash;
+    use Win32::TieRegistry ( TiedHash => \%RegHash );
+
+There are also several ways you can tie a hash variable to any
+other key of the Registry, which are discussed later.
+
+Note that you will most likely use C<$Registry> instead of using
+a tied hash.  C<$Registry> is a reference to a hash that has
+been tied to the virtual root of your computer's Registry [as if,
+C<$Registry= \%RegHash>].  So you would use C<$Registry-E<gt>{Key}>
+rather than C<$RegHash{Key}> and use C<keys %{$Registry}> rather
+than C<keys %RegHash>, for example.
+
+For each hash which has been tied to a Registry key, the Perl
+C<keys> function will return a list containing the name of each
+of the key's subkeys with a delimiter character appended to it and
+containing the name of each of the key's values with a delimiter
+prepended to it.  For example:
+
+    keys( %{ $Registry->{"HKEY_CLASSES_ROOT\\batfile\\"} } )
+
+might yield the following list value:
+
+    ( "DefaultIcon\\",  # The subkey named "DefaultIcon"
+      "shell\\",        # The subkey named "shell"
+      "shellex\\",      # The subkey named "shellex"
+      "\\",             # The default value [named ""]
+      "\\EditFlags" )   # The value named "EditFlags"
+
+For the virtual root key, short-hand subkey names are used as
+shown below.  You can use the short-hand name, the regular
+I<HKEY_*> name, or any numeric value to access these keys, but
+the short-hand names are all that will be returned by the C<keys>
+function.
+
+=over
+
+=item "Classes" for HKEY_CLASSES_ROOT
+
+Contains mappings between file name extensions and the uses
+for such files along with configuration information for COM
+[MicroSoft's Common Object Model] objects.  Usually a link to
+the C<"SOFTWARE\\Classes"> subkey of the C<HKEY_LOCAL_MACHINE>
+key.
+
+=item "CUser" for HKEY_CURRENT_USER
+
+Contains information specific to the currently logged-in user.
+Mostly software configuration information.  Usually a link to
+a subkey of the C<HKEY_USERS> key.
+
+=item "LMachine" for HKEY_LOCAL_MACHINE
+
+Contains all manner of information about the computer.
+
+=item "Users" for HKEY_USERS
+
+Contains one subkey, C<".DEFAULT">, which gets copied to a new
+subkey whenever a new user is added.  Also contains a subkey for
+each user of the system, though only those for active users
+[usually only one] are loaded at any given time.
+
+=item "PerfData" for HKEY_PERFORMANCE_DATA
+
+Used to access data about system performance.  Access via this key
+is "special" and all but the most carefully constructed calls will
+fail, usually with C<ERROR_INSUFFICIENT_BUFFER>.  For example, you
+can't enumerate key names without also enumerating values which
+require huge buffers but the exact buffer size required cannot be
+determined beforehand because C<RegQueryInfoKey()> E<always> fails
+with C<ERROR_INSUFFICIENT_BUFFER> for C<HKEY_PERFORMANCE_DATA> no
+matter how it is called.  So it is currently not very useful to
+tie a hash to this key.  You can use it to create an object to use
+for making carefully constructed calls to the underlying Reg*()
+routines.
+
+=item "CConfig" for HKEY_CURRENT_CONFIG
+
+Contains minimal information about the computer's current
+configuration that is required very early in the boot process.
+For example, setting for the display adapter such as screen
+resolution and refresh rate are found in here.
+
+=item "DynData" for HKEY_DYN_DATA
+
+Dynamic data.  We have found no documentation for this key.
+
+=back
+
+A tied hash is much like a regular hash variable in Perl -- you give
+it a key string inside braces, [C<{> and C<}>], and it gives you
+back a value [or lets you set a value].  For I<Win32::TieRegistry>
+hashes, there are two types of values that will be returned.
+
+=over
+
+=item SubKeys
+
+If you give it a string which represents a subkey, then it will
+give you back a reference to a hash which has been tied to that
+subkey.  It can't return the hash itself, so it returns a
+reference to it.  It also blesses that reference so that it is
+also an object so you can use it to call method functions.
+
+=item Values
+
+If you give it a string which is a value name, then it will give
+you back a string which is the data for that value.  Alternately,
+you can request that it give you both the data value string and
+the data value type [we discuss how to request this later].  In
+this case, it would return a reference to an array where the value
+data string is element C<[0]> and the value data type is element
+C<[1]>.
+
+=back
+
+The key string which you use in the tied hash must be interpreted
+to determine whether it is a value name or a key name or a path
+that combines several of these or even other things.  There are
+two simple rules that make this interpretation easy and
+unambiguous:
+
+    Put a delimiter after each key name.
+    Put a delimiter in front of each value name.
+
+Exactly how the key string will be intepreted is governed by the
+following cases, in the order listed.  These cases are designed
+to "do what you mean".  Most of the time you won't have to think
+about them, especially if you follow the two simple rules above.
+After the list of cases we give several examples which should be
+clear enough so feel free to skip to them unless you are worried
+about the details.
+
+=over
+
+=item Remote machines
+
+If the hash is tied to the virtual root of the registry [or the
+virtual root of a remote machine's registry], then we treat hash
+key strings which start with the delimiter character specially.
+
+If the hash key string starts with two delimiters in a row, then
+those should be immediately followed by the name of a remote
+machine whose registry we wish to connect to.  That can be
+followed by a delimiter and more subkey names, etc.  If the
+machine name is not following by anything, then a virtual root
+for the remote machine's registry is created, a hash is tied to
+it, and a reference to that hash it is returned.
+
+=item Hash key string starts with the delimiter
+
+If the hash is tied to a virtual root key, then the leading
+delimiter is ignored.  It should be followed by a valid Registry
+root key name [either a short-hand name like C<"LMachine">, an
+I<HKEY_*> value, or a numeric value].   This alternate notation is
+allowed in order to be more consistant with the C<Open()> method
+function.
+
+For all other Registry keys, the leading delimiter indicates
+that the rest of the string is a value name.  The leading
+delimiter is stripped and the rest of the string [which can
+be empty and can contain more delimiters] is used as a value
+name with no further parsing.
+
+=item Exact match with direct subkey name followed by delimiter
+
+If you have already called the Perl C<keys> function on the tied
+hash [or have already called C<MemberNames> on the object] and the
+hash key string exactly matches one of the strings returned, then
+no further parsing is done.  In other words, if the key string
+exactly matches the name of a direct subkey with a delimiter
+appended, then a reference to a hash tied to that subkey is
+returned [but only if C<keys> or C<MemberNames> has already
+been called for that tied hash].
+
+This is only important if you have selected a delimiter other than
+the system default delimiter and one of the subkey names contains
+the delimiter you have chosen.  This rule allows you to deal with
+subkeys which contain your chosen delimiter in their name as long
+as you only traverse subkeys one level at a time and always
+enumerate the list of members before doing so.
+
+The main advantage of this is that Perl code which recursively
+traverses a hash will work on hashes tied to Registry keys even if
+a non-default delimiter has been selected.
+
+=item Hash key string contains two delimiters in a row
+
+If the hash key string contains two [or more] delimiters in a row,
+then the string is split between the first pair of delimiters.
+The first part is interpreted as a subkey name or a path of subkey
+names separated by delimiters and with a trailing delimiter.  The
+second part is interpreted as a value name with one leading
+delimiter [any extra delimiters are considered part of the value
+name].
+
+=item Hash key string ends with a delimiter
+
+If the key string ends with a delimiter, then it is treated
+as a subkey name or path of subkey names separated by delimiters.
+
+=item Hash key string contains a delimiter
+
+If the key string contains a delimiter, then it is split after
+the last delimiter.  The first part is treated as a subkey name or
+path of subkey names separated by delimiters.  The second part
+is ambiguous and is treated as outlined in the next item.
+
+=item Hash key string contains no delimiters
+
+If the hash key string contains no delimiters, then it is ambiguous.
+
+If you are reading from the hash [fetching], then we first use the
+key string as a value name.  If there is a value with a matching
+name in the Registry key which the hash is tied to, then the value
+data string [and possibly the value data type] is returned.
+Otherwise, we retry by using the hash key string as a subkey name.
+If there is a subkey with a matching name, then we return a
+reference to a hash tied to that subkey.  Otherwise we return
+C<undef>.
+
+If you are writing to the hash [storing], then we use the key
+string as a subkey name only if the value you are storing is a
+reference to a hash value.  Otherwise we use the key string as
+a value name.
+
+=back
+
+=head3 Examples
+
+Here are some examples showing different ways of accessing Registry
+information using references to tied hashes:
+
+=over
+
+=item Canonical value fetch
+
+    $tip18= $Registry->{"HKEY_LOCAL_MACHINE\\Software\\Microsoft\\"
+               . 'Windows\\CurrentVersion\\Explorer\\Tips\\\\18'};
+
+Should return the text of important tip number 18.  Note that two
+backslashes, C<"\\">, are required to get a single backslash into
+a Perl double-quoted or single-qouted string.  Note that C<"\\">
+is appended to each key name [C<"HKEY_LOCAL_MACHINE"> through
+C<"Tips">] and C<"\\"> is prepended to the value name, C<"18">.
+
+=item Changing your delimiter
+
+    $Registry->Delimiter("/");
+    $tip18= $Registry->{"HKEY_LOCAL_MACHINE/Software/Microsoft/"
+               . 'Windows/CurrentVersion/Explorer/Tips//18'};
+
+This usually makes things easier to read when working in Perl.
+All remaining examples will assume the delimiter has been changed
+as above.
+
+=item Using intermediate keys
+
+    $ms= $Registry->{"LMachine/Software/Microsoft/"};
+    $tips= $ms->{"Windows/CurrentVersion/Explorer/Tips/"};
+    $tip18= $winlogon->{"/18"};
+
+Same as above but opens more keys into the Registry which lets you
+efficiently re-access those intermediate keys.  This is slightly
+less efficient if you never reuse those intermediate keys.
+
+=item Chaining in a single statement
+
+    $tip18= $Registry->{"LMachine/Software/Microsoft/"}->
+              {"Windows/CurrentVersion/Explorer/Tips/"}->{"/18"};
+
+Like above, this creates intermediate key objects then uses
+them to access other data.  Once this statement finishes, the
+intermediate key objects are destroyed.  Several handles into
+the Registry are opened and closed by this statement so it is
+less efficient but there are times when this will be useful.
+
+=item Even less efficient example of chaining
+
+    $tip18= $Registry->{"LMachine/Software/Microsoft"}->
+              {"Windows/CurrentVersion/Explorer/Tips"}->{"/18"};
+
+Because we left off the trailing delimiters, I<Win32::TieRegistry>
+doesn't know whether final names, C<"Microsoft"> and C<"Tips">,
+are subkey names or value names.  So this statement ends up
+executing the same code as the next one.
+
+=item What the above really does
+
+    $tip18= $Registry->{"LMachine/Software/"}->{"Microsoft"}->
+              {"Windows/CurrentVersion/Explorer/"}->{"Tips"}->{"/18"};
+
+With more chains to go through, more temporary objects are created
+and later destroyed than in our first chaining example.  Also,
+when C<"Microsoft"> is looked up, I<Win32::TieRegistry> first
+tries to open it as a value and fails then tries it as a subkey.
+The same is true for when it looks up C<"Tips">.
+
+=item Getting all of the tips
+
+    $tips= $Registry->{"LMachine/Software/Microsoft/"}->
+              {"Windows/CurrentVersion/Explorer/Tips/"}
+      or  die "Can't find the Windows tips: $^E\n";
+    foreach(  keys %$tips  ) {
+        print "$_: ", $tips->{$_}, "\n";
+    }
+
+First notice that we actually check for failure for the first
+time.  We are assuming that the C<"Tips"> key contains no subkeys. 
+Otherwise the C<print> statement would show something like
+C<"Win32::TieRegistry=HASH(0xc03ebc)"> for each subkey.
+
+The output from the above code will start something like:
+
+    /0: If you don't know how to do something,[...]
+
+=back
+
+=head3 Deleting items
+
+You can use the Perl C<delete> function to delete a value from a
+Registry key or to delete a subkey as long that subkey contains
+no subkeys of its own.  See L<More Examples>, below, for more
+information.
+
+=head3 Storing items
+
+You can use the Perl assignment operator [C<=>] to create new
+keys, create new values, or replace values.  The values you store
+should be in the same format as the values you would fetch from a
+tied hash.  For example, you can use a single assignment statement
+to copy an entire Registry tree.  The following statement:
+
+    $Registry->{"LMachine/Software/Classes/Tie_Registry/"}=
+      $Registry->{"LMachine/Software/Classes/batfile/"};
+
+creates a C<"Tie_Registry"> subkey under the C<"Software\\Classes">
+subkey of the C<HKEY_LOCAL_MACHINE> key.  Then it populates it
+with copies of all of the subkeys and values in the C<"batfile">
+subkey and all of its subkeys.  Note that you need to have
+called C<$Registry-E<gt>ArrayValues(1)> for the proper value data
+type information to be copied.  Note also that this release of
+I<Win32::TieRegistry> does not copy key attributes such as class
+name and security information [this is planned for a future release].
+
+The following statement creates a whole subtree in the Registry:
+
+    $Registry->{"LMachine/Software/FooCorp/"}= {
+        "FooWriter/" => {
+            "/Version" => "4.032",
+            "Startup/" => {
+                "/Title" => "Foo Writer Deluxe ][",
+                "/WindowSize" => [ pack("LL",$wid,$ht), "REG_BINARY" ],
+                "/TaskBarIcon" => [ "0x0001", "REG_DWORD" ],
+            },
+            "Compatibility/" => {
+                "/AutoConvert" => "Always",
+                "/Default Palette" => "Windows Colors",
+            },
+        },
+        "/License", => "0123-9C8EF1-09-FC",
+    };
+
+Note that all but the last Registry key used on the left-hand
+side of the assignment [that is, "LMachine/Software/" but not
+"FooCorp/"] must already exist for this statement to succeed.
+
+By using the leading a trailing delimiters on each subkey name and
+value name, I<Win32::TieRegistry> will tell you if you try to assign
+subkey information to a value or visa-versa.
+
+=head3 More examples
+
+=over
+
+=item Adding a new tip
+
+    $tips= $Registry->{"LMachine/Software/Microsoft/"}->
+              {"Windows/CurrentVersion/Explorer/Tips/"}
+      or  die "Can't find the Windows tips: $^E\n";
+    $tips{'/186'}= "Be very careful when making changes to the Registry!";
+
+=item Deleting our new tip
+
+    $tips= $Registry->{"LMachine/Software/Microsoft/"}->
+              {"Windows/CurrentVersion/Explorer/Tips/"}
+      or  die "Can't find the Windows tips: $^E\n";
+    $tip186= delete $tips{'/186'};
+
+Note that Perl's C<delete> function returns the value that was deleted.
+
+=item Adding a new tip differently
+
+    $Registry->{"LMachine/Software/Microsoft/" .
+                "Windows/CurrentVersion/Explorer/Tips//186"}=
+      "Be very careful when making changes to the Registry!";
+
+=item Deleting differently
+
+    $tip186= delete $Registry->{"LMachine/Software/Microsoft/Windows/" .
+                                "CurrentVersion/Explorer/Tips//186"};
+
+Note that this only deletes the tail of what we looked up, the
+C<"186"> value, not any of the keys listed.
+
+=item Deleting a key
+
+WARNING:  The following code will delete all information about the
+current user's tip preferences.  Actually executing this command
+would probably cause the user to see the Welcome screen the next
+time they log in and may cause more serious problems.  This
+statement is shown as an example only and should not be used when
+experimenting.
+
+    $tips= delete $Registry->{"CUser/Software/Microsoft/Windows/" .
+                              "CurrentVersion/Explorer/Tips/"};
+
+This deletes the C<"Tips"> key and the values it contains.  The
+C<delete> function will return a reference to a hash [not a tied
+hash] containing the value names and value data that were deleted.
+
+The information to be returned is copied from the Registry into a
+regular Perl hash before the key is deleted.  If the key has many
+subkeys, this copying could take a significant amount of memory
+and/or processor time.  So you can disable this process by calling
+the C<FastDelete> member function:
+
+    $prevSetting= $regKey->FastDelete(1);
+
+which will cause all subsequent delete operations via C<$regKey>
+to simply return a true value if they succeed.  This optimization
+is automatically done if you use C<delete> in a void context.
+
+=item Technical notes on deleting
+
+If you use C<delete> to delete a Registry key or value and use
+the return value, then I<Win32::TieRegistry> usually looks up the
+current contents of that key or value so they can be returned if
+the deletion is successful.  If the deletion succeeds but the
+attempt to lookup the old contents failed, then the return value
+of C<delete> will be C<$^E> from the failed part of the operation.
+
+=item Undeleting a key
+
+    $Registry->{"LMachine/Software/Microsoft/Windows/" .
+                "CurrentVersion/Explorer/Tips/"}= $tips;
+
+This adds back what we just deleted.  Note that this version of
+I<Win32::TieRegistry> will use defaults for the key attributes
+[such as class name and security] and will not restore the
+previous attributes.
+
+=item Not deleting a key
+
+WARNING:  Actually executing the following code could cause
+serious problems.  This statement is shown as an example only and
+should not be used when experimenting.
+
+    $res= delete $Registry->{"CUser/Software/Microsoft/Windows/"}
+    defined($res)  ||  die "Can't delete URL key: $^E\n";
+
+Since the "Windows" key should contain subkeys, that C<delete>
+statement should make no changes to the Registry, return C<undef>,
+and set C<$^E> to "Access is denied".
+
+=item Not deleting again
+
+    $tips= $Registry->{"CUser/Software/Microsoft/Windows/" .
+                       "CurrentVersion/Explorer/Tips/"};
+    delete $tips;
+
+The Perl C<delete> function requires that its argument be an
+expression that ends in a hash element lookup [or hash slice],
+which is not the case here.  The C<delete> function doesn't
+know which hash $tips came from and so can't delete it.
+
+=back
+
+=head2 Objects Documentation
+
+The following member functions are defined for use on
+I<Win32::TieRegistry> objects:
+
+=over
+
+=item new
+
+The C<new> method creates a new I<Win32::TieRegistry> object.
+C<new> is mostly a synonym for C<Open()> so see C<Open()> below for
+information on what arguments to pass in.  Examples:
+
+    $machKey= new Win32::TieRegistry "LMachine"
+      or  die "Can't access HKEY_LOCAL_MACHINE key: $^E\n";
+    $userKey= Win32::TieRegistry->new("CUser")
+      or  die "Can't access HKEY_CURRENT_USER key: $^E\n";
+
+Note that calling C<new> via a reference to a tied hash returns
+a simple object, not a reference to a tied hash.
+
+=item Open
+
+=item $subKey= $key->Open( $sSubKey, $rhOptions )
+
+The C<Open> method opens a Registry key and returns a new
+I<Win32::TieRegistry> object associated with that Registry key.
+If C<Open> is called via a reference to a tied hash, then C<Open>
+returns another reference to a tied hash.  Otherwise C<Open>
+returns a simple object and you should then use C<TiedRef> to get
+a reference to a tied hash.
+
+C<$sSubKey> is a string specifying a subkey to be opened.
+Alternately C<$sSubKey> can be a reference to an array value
+containing the list of increasingly deep subkeys specifying the
+path to the subkey to be opened.
+
+C<$rhOptions> is an optional reference to a hash containing extra
+options.  The C<Open> method supports two options, C<"Delimiter">
+and C<"Access">, and C<$rhOptions> should have only have zero or
+more of these strings as keys.  See the "Examples" section below
+for more information.
+
+The C<"Delimiter"> option specifies what string [usually a single
+character] will be used as the delimiter to be appended to subkey
+names and prepended to value names.  If this option is not specified,
+the new key [C<$subKey>] inherits the delimiter of the old key
+[C<$key>].
+
+The C<"Access"> option specifies what level of access to the
+Registry key you wish to have once it has been opened.  If this
+option is not specified, the new key [C<$subKey>] is opened with
+the same access level used when the old key [C<$key>] was opened.
+The virtual root of the Registry pretends it was opened with
+access C<KEY_READ()|KEY_WRITE()> so this is the default access when
+opening keys directory via C<$Registry>.  If you don't plan on
+modifying a key, you should open it with C<KEY_READ> access as
+you may not have C<KEY_WRITE> access to it or some of its subkeys.
+
+If the C<"Access"> option value is a string that starts with
+C<"KEY_">, then it should match E<one> of the predefined access
+levels [probably C<"KEY_READ">, C<"KEY_WRITE">, or
+C<"KEY_ALL_ACCESS">] exported by the I<Win32API::Registry> module.
+Otherwise, a numeric value is expected.  For maximum flexibility,
+include C<use Win32::TieRegistry qw(:KEY_);>, for example, near
+the top of your script so you can specify more complicated access
+levels such as C<KEY_READ()|KEY_WRITE()>.
+
+If C<$sSubKey> does not begin with the delimiter [or C<$sSubKey>
+is an array reference], then the path to the subkey to be opened
+will be relative to the path of the original key [C<$key>].  If
+C<$sSubKey> begins with a single delimiter, then the path to the
+subkey to be opened will be relative to the virtual root of the
+Registry on whichever machine the original key resides.  If
+C<$sSubKey> begins with two consectutive delimiters, then those
+must be followed by a machine name which causes the C<Connect()>
+method function to be called.
+
+Examples:
+
+    $machKey= $Registry->Open( "LMachine", {Access=>KEY_READ(),Delimiter=>"/"} )
+      or  die "Can't open HKEY_LOCAL_MACHINE key: $^E\n";
+    $swKey= $machKey->Open( "Software" );
+    $logonKey= $swKey->Open( "Microsoft/Windows NT/CurrentVersion/Winlogon/" );
+    $NTversKey= $swKey->Open( ["Microsoft","Windows NT","CurrentVersion"] );
+    $versKey= $swKey->Open( qw(Microsoft Windows CurrentVersion) );
+
+    $remoteKey= $Registry->Open( "//HostA/LMachine/System/", {Delimiter=>"/"} )
+      or  die "Can't connect to HostA or can't open subkey: $^E\n";
+
+=item Clone
+
+=item $copy= $key->Clone
+
+Creates a new object that is associated with the same Registry key
+as the invoking object.
+
+=item Connect
+
+=item $remoteKey= $Registry->Connect( $sMachineName, $sKeyPath, $rhOptions )
+
+The C<Connect> method connects to the Registry of a remote machine,
+and opens a key within it, then returns a new I<Win32::TieRegistry>
+object associated with that remote Registry key.  If C<Connect>
+was called using a reference to a tied hash, then the return value
+will also be a reference to a tied hash [or C<undef>].  Otherwise,
+if you wish to use the returned object as a tied hash [not just as
+an object], then use the C<TiedRef> method function after C<Connect>.
+
+C<$sMachineName> is the name of the remote machine.  You don't have
+to preceed the machine name with two delimiter characters.
+
+C<$sKeyPath> is a string specifying the remote key to be opened.
+Alternately C<$sKeyPath> can be a reference to an array value
+containing the list of increasingly deep keys specifying the path
+to the key to be opened.
+
+C<$rhOptions> is an optional reference to a hash containing extra
+options.  The C<Connect> method supports two options, C<"Delimiter">
+and C<"Access">.  See the C<Open> method documentation for more
+information on these options.
+
+C<$sKeyPath> is already relative to the virtual root of the Registry
+of the remote machine.  A single leading delimiter on C<sKeyPath>
+will be ignored and is not required.
+
+C<$sKeyPath> can be empty in which case C<Connect> will return an
+object representing the virtual root key of the remote Registry.
+Each subsequent use of C<Open> on this virtual root key will call
+the system C<RegConnectRegistry> function.
+
+The C<Connect> method can be called via any I<Win32::TieRegistry>
+object, not just C<$Registry>.  Attributes such as the desired
+level of access and the delimiter will be inherited from the
+object used but the C<$sKeyPath> will always be relative to the
+virtual root of the remote machine's registry.
+
+Examples:
+
+    $remMachKey= $Registry->Connect( "HostA", "LMachine", {Delimiter->"/"} )
+      or  die "Can't connect to HostA's HKEY_LOCAL_MACHINE key: $^E\n";
+
+    $remVersKey= $remMachKey->Connect( "www.microsoft.com",
+                   "LMachine/Software/Microsoft/Inetsrv/CurrentVersion/",
+                   { Access=>KEY_READ, Delimiter=>"/" } )
+      or  die "Can't check what version of IIS Microsoft is running: $^E\n";
+
+    $remVersKey= $remMachKey->Connect( "www",
+                   qw(LMachine Software Microsoft Inetsrv CurrentVersion) )
+      or  die "Can't check what version of IIS we are running: $^E\n";
+
+=item ObjectRef
+
+=item $object_ref= $obj_or_hash_ref->ObjectRef
+
+For a simple object, just returns itself [C<$obj == $obj->ObjectRef>].
+
+For a reference to a tied hash [if it is also an object], C<ObjectRef>
+returns the simple object that the hash is tied to.
+
+This is primarilly useful when debugging since typing C<x $Registry>
+will try to display your I<entire> registry contents to your screen.
+But the debugger command C<x $Registry->ObjectRef> will just dump
+the implementation details of the underlying object to your screen.
+
+=item Flush( $bFlush )
+
+Flushes all cached information about the Registry key so that future
+uses will get fresh data from the Registry.
+
+If the optional C<$bFlush> is specified and a true value, then
+C<RegFlushKey()> will be called, which is almost never necessary.
+
+=item GetValue
+
+=item $ValueData= $key->GetValue( $sValueName )
+
+=item ($ValueData,$ValueType)= $key->GetValue( $sValueName )
+
+Gets a Registry value's data and data type.
+
+C<$ValueData> is usually just a Perl string that contains the
+value data [packed into it].  For certain types of data, however,
+C<$ValueData> may be processed as described below.
+
+C<$ValueType> is the C<REG_*> constant describing the type of value
+data stored in C<$ValueData>.  If the C<DualTypes()> option is on,
+then C<$ValueType> will be a dual value.  That is, when used in a
+numeric context, C<$ValueType> will give the numeric value of a
+C<REG_*> constant.  However, when used in a non-numeric context,
+C<$ValueType> will return the name of the C<REG_*> constant, for
+example C<"REG_SZ"> [note the quotes].  So both of the following
+can be true at the same time:
+
+    $ValueType == REG_SZ()
+    $ValueType eq "REG_SZ"
+
+=over
+
+=item REG_SZ and REG_EXPAND_SZ
+
+If the C<FixSzNulls()> option is on, then the trailing C<'\0'> will be
+stripped [unless there isn't one] before values of type C<REG_SZ>
+and C<REG_EXPAND_SZ> are returned.  Note that C<SetValue()> will add
+a trailing C<'\0'> under similar circumstances.
+
+=item REG_MULTI_SZ
+
+If the C<SplitMultis()> option is on, then values of this type are
+returned as a reference to an array containing the strings.  For
+example, a value that, with C<SplitMultis()> off, would be returned as:
+
+    "Value1\000Value2\000\000"
+
+would be returned, with C<SplitMultis()> on, as:
+
+    [ "Value1", "Value2" ]
+
+=item REG_DWORD
+
+If the C<DualBinVals()> option is on, then the value is returned
+as a scalar containing both a string and a number [much like
+the C<$!> variable -- see the L<SetDualVar> module for more
+information] where the number part is the "unpacked" value.
+Use the returned value in a numeric context to access this part
+of the value.  For example:
+
+    $num= 0 + $Registry->{"CUser/Console//ColorTable01"};
+
+If the C<DWordsToHex()> option is off, the string part of the
+returned value is a packed, 4-byte string [use C<unpack("L",$value)>
+to get the numeric value.
+
+If C<DWordsToHex()> is on, the string part of the returned value is
+a 10-character hex strings [with leading "0x"].  You can use
+C<hex($value)> to get the numeric value.
+
+Note that C<SetValue()> will properly understand each of these
+returned value formats no matter how C<DualBinVals()> is set.
+
+=back
+
+=item ValueNames
+
+=item @names= $key->ValueNames
+
+Returns the list of value names stored directly in a Registry key.
+Note that the names returned do I<not> have a delimiter prepended
+to them like with C<MemberNames()> and tied hashes.
+
+Once you request this information, it is cached in the object and
+future requests will always return the same list unless C<Flush()>
+has been called.
+
+=item SubKeyNames
+
+=item @key_names= $key->SubKeyNames
+
+Returns the list of subkey names stored directly in a Registry key.
+Note that the names returned do I<not> have a delimiter appended
+to them like with C<MemberNames()> and tied hashes.
+
+Once you request this information, it is cached in the object and
+future requests will always return the same list unless C<Flush()>
+has been called.
+
+=item SubKeyClasses
+
+=item @classes= $key->SubKeyClasses
+
+Returns the list of classes for subkeys stored directly in a
+Registry key.  The classes are returned in the same order as
+the subkey names returned by C<SubKeyNames()>.
+
+=item SubKeyTimes
+
+=item @times= $key->SubKeyTimes
+
+Returns the list of last-modified times for subkeys stored
+directly in a Registry key.  The times are returned in the same
+order as the subkey names returned by C<SubKeyNames()>.  Each
+time is a C<FILETIME> structure packed into a Perl string.
+
+Once you request this information, it is cached in the object and
+future requests will always return the same list unless C<Flush()>
+has been called.
+
+=item MemberNames
+
+=item @members= $key->MemberNames
+
+Returns the list of subkey names and value names stored directly
+in a Registry key.  Subkey names have a delimiter appended to the
+end and value names have a delimiter prepended to the front.
+
+Note that a value name could end in a delimiter [or could be C<"">
+so that the member name returned is just a delimiter] so the
+presence or absence of the leading delimiter is what should be
+used to determine whether a particular name is for a subkey or a
+value, not the presence or absence of a trailing delimiter.
+
+Once you request this information, it is cached in the object and
+future requests will always return the same list unless C<Flush()>
+has been called.
+
+=item Information
+
+=item %info= $key->Information
+
+=item @items= $key->Information( @itemNames );
+
+Returns the following information about a Registry key:
+
+=over
+
+=item LastWrite
+
+A C<FILETIME> structure indicating when the key was last modified
+and packed into a Perl string.
+
+=item CntSubKeys
+
+The number of subkeys stored directly in this key.
+
+=item CntValues
+
+The number of values stored directly in this key.
+
+=item SecurityLen
+
+The length [in bytes] of the largest[?] C<SECURITY_DESCRIPTOR>
+associated with the Registry key.
+
+=item MaxValDataLen
+
+The length [in bytes] of the longest value data associated with
+a value stored in this key.
+
+=item MaxSubKeyLen
+
+The length [in chars] of the longest subkey name associated with
+a subkey stored in this key.
+
+=item MaxSubClassLen
+
+The length [in chars] of the longest class name associated with
+a subkey stored directly in this key.
+
+=item MaxValNameLen
+
+The length [in chars] of the longest value name associated with
+a value stored in this key.
+
+=back
+
+With no arguments, returns a hash [not a reference to a hash] where
+the keys are the names for the items given above and the values
+are the information describe above.  For example:
+
+    %info= ( "CntValues" => 25,         # Key contains 25 values.
+             "MaxValNameLen" => 20,     # One of which has a 20-char name.
+             "MaxValDataLen" => 42,     # One of which has a 42-byte value.
+             "CntSubKeys" => 1,         # Key has 1 immediate subkey.
+             "MaxSubKeyLen" => 13,      # One of which has a 12-char name.
+             "MaxSubClassLen" => 0,     # All of which have class names of "".
+             "SecurityLen" => 232,      # One SECURITY_DESCRIPTOR is 232 bytes.
+             "LastWrite" => "\x90mZ\cX{\xA3\xBD\cA\c@\cA"
+                           # Key was last modifed 1998/06/01 16:29:32 GMT
+           );
+
+With arguments, each one must be the name of a item given above.
+The return value is the information associated with the listed
+names.  In other words:
+
+    return $key->Information( @names );
+
+returns the same list as:
+
+    %info= $key->Information;
+    return @info{@names};
+
+=item Delimiter
+
+=item $oldDelim= $key->Delimiter
+
+=item $oldDelim= $key->Delimiter( $newDelim )
+
+Gets and possibly changes the delimiter used for this object.  The
+delimiter is appended to subkey names and prepended to value names
+in many return values.  It is also used when parsing keys passed
+to tied hashes.
+
+The delimiter defaults to backslash (C<'\\'>) but is inherited from
+the object used to create a new object and can be specified by an
+option when a new object is created.
+
+=item Handle
+
+=item $handle= $key->Handle
+
+Returns the raw C<HKEY> handle for the associated Registry key as
+an integer value.  This value can then be used to Reg*() calls
+from I<Win32API::Registry>.  However, it is usually easier to just
+call the I<Win32API::Registry> calls directly via:
+
+    $key->RegNotifyChangeKeyValue( ... );
+
+For the virtual root of the local or a remote Registry,
+C<Handle()> return C<"NONE">.
+
+=item Path
+
+=item $path= $key->Path
+
+Returns a string describing the path of key names to this
+Registry key.  The string is built so that if it were passed
+to C<$Registry->Open()>, it would reopen the same Registry key
+[except in the rare case where one of the key names contains
+C<$key->Delimiter>].
+
+=item Machine
+
+=item $computerName= $key->Machine
+
+Returns the name of the computer [or "machine"] on which this Registry
+key resides.  Returns C<""> for local Registry keys.
+
+=item Access
+
+Returns the numeric value of the bit mask used to specify the
+types of access requested when this Registry key was opened.  Can
+be compared to C<KEY_*> values.
+
+=item OS_Delimiter
+
+Returns the delimiter used by the operating system's RegOpenKeyEx()
+call.  For Win32, this is always backslash (C<"\\">).
+
+=item Roots
+
+Returns the mapping from root key names like C<"LMachine"> to their
+associated C<HKEY_*> constants.  Primarily for internal use and
+subject to change.
+
+=item Tie
+
+=item $key->Tie( \%hash );
+
+Ties the referenced hash to that Registry key.  Pretty much the
+same as
+
+    tie %hash, ref($key), $key;
+
+Since C<ref($key)> is the class [package] to tie the hash to and
+C<TIEHASH()> just returns its argument, C<$key>, [without calling
+C<new()>] when it sees that it is already a blessed object.
+
+=item TiedRef
+
+=item $TiedHashRef= $hash_or_obj_ref->TiedRef
+
+For a simple object, returns a reference to a hash tied to the
+object.  Used to promote a simple object into a combined object
+and hash ref.
+
+If already a reference to a tied hash [that is also an object],
+it just returns itself [C<$ref == $ref->TiedRef>].
+
+Mostly used internally.
+
+=item ArrayValues
+
+=item $oldBool= $key->ArrayValues
+
+=item $oldBool= $key->ArrayValues( $newBool )
+
+Gets the current setting of the C<ArrayValues> option and possibly
+turns it on or off.
+
+When off, Registry values fetched via a tied hash are returned as
+just a value scalar [the same as C<GetValue()> in a scalar context].
+When on, they are returned as a reference to an array containing
+the value data as the C<[0]> element and the data type as the C<[1]>
+element.
+
+=item TieValues
+
+=item $oldBool= TieValues
+
+=item $oldBool= TieValues( $newBool )
+
+Gets the current setting of the C<TieValues> option and possibly
+turns it on or off.
+
+Turning this option on is not yet supported in this release of
+I<Win32::TieRegistry>.  In a future release, turning this option
+on will cause Registry values returned from a tied hash to be
+a tied array that you can use to modify the value in the Registry.
+
+=item FastDelete
+
+=item $oldBool= $key->FastDelete
+
+=item $oldBool= $key->FastDelete( $newBool )
+
+Gets the current setting of the C<FastDelete> option and possibly
+turns it on or off.
+
+When on, successfully deleting a Registry key [via a tied hash]
+simply returns C<1>.
+
+When off, successfully deleting a Registry key [via a tied hash
+and not in a void context] returns a reference to a hash that
+contains the values present in the key when it was deleted.  This
+hash is just like that returned when referencing the key before it
+was deleted except that it is an ordinary hash, not one tied to
+the I<Win32::TieRegistry> package.
+
+Note that deleting either a Registry key or value via a tied hash
+I<in a void context> prevents any overhead in trying to build an
+appropriate return value.
+
+Note that deleting a Registry I<value> via a tied hash [not in
+a void context] returns the value data even if <FastDelete> is on.
+
+=item SplitMultis
+
+=item $oldBool= $key->SplitMultis
+
+=item $oldBool= $key->SplitMultis( $newBool )
+
+Gets the current setting of the C<SplitMultis> option and possibly
+turns it on or off.
+
+If on, Registry values of type C<REG_MULTI_SZ> are returned as
+a reference to an array of strings.  See C<GetValue()> for more
+information.
+
+=item DWordsToHex
+
+=item $oldBool= $key->DWordsToHex
+
+=item $oldBool= $key->DWordsToHex( $newBool )
+
+Gets the current setting of the C<DWordsToHex> option and possibly
+turns it on or off.
+
+If on, Registry values of type C<REG_DWORD> are returned as a hex
+string with leading C<"0x"> and longer than 4 characters.  See
+C<GetValue()> for more information.
+
+=item FixSzNulls
+
+=item $oldBool= $key->FixSzNulls
+
+=item $oldBool= $key->FixSzNulls( $newBool )
+
+Gets the current setting of the C<FixSzNulls> option and possibly
+turns it on or off.
+
+If on, Registry values of type C<REG_SZ> and C<REG_EXPAND_SZ> have
+trailing C<'\0'>s added before they are set and stripped before
+they are returned.  See C<GetValue()> and C<SetValue()> for more
+information.
+
+=item DualTypes
+
+=item $oldBool= $key->DualTypes
+
+=item $oldBool= $key->DualTypes( $newBool )
+
+Gets the current setting of the C<DualTypes> option and possibly
+turns it on or off.
+
+If on, data types are returned as a combined numeric/string value
+holding both the numeric value of a C<REG_*> constant and the
+string value of the constant's name.  See C<GetValue()> for
+more information.
+
+=item DualBinVals
+
+=item $oldBool= $key->DualBinVals
+
+=item $oldBool= $key->DualBinVals( $newBool )
+
+Gets the current setting of the C<DualBinVals> option and possibly
+turns it on or off.
+
+If on, Registry value data of type C<REG_BINARY> and no more than
+4 bytes long and Registry values of type C<REG_DWORD> are returned
+as a combined numeric/string value where the numeric value is the
+"unpacked" binary value as returned by:
+
+        hex reverse unpack( "h*", $valData )
+
+on a "little-endian" computer.  [Would be C<hex unpack("H*",$valData)>
+on a "big-endian" computer if this module is ever ported to one.]
+
+See C<GetValue()> for more information.
+
+=item GetOptions
+
+=item @oldOptValues= $key->GetOptions( @optionNames )
+
+=item $refHashOfOldOpts= $key->GetOptions()
+
+=item $key->GetOptions( \%hashForOldOpts )
+
+Returns the current setting of any of the following options:
+
+    Delimiter     FixSzNulls    DWordsToHex
+    ArrayValues   SplitMultis   DualBinVals
+    TieValues     FastDelete    DualTypes
+
+Pass in one or more of the above names (as strings) to get back
+an array of the corresponding current settings in the same order:
+
+  my( $fastDel, $delim )= $key->GetOptions("FastDelete","Delimiter");
+
+Pass in no arguments to get back a reference to a hash where
+the above option names are the keys and the values are
+the corresponding current settings for each option:
+
+  my $href= $key->GetOptions();
+  my $delim= $href->{Delimiter};
+
+Pass in a single reference to a hash to have the above key/value
+pairs I<added> to the referenced hash.  For this case, the
+return value is the original object so further methods can be
+chained after the call to GetOptions:
+
+  my %oldOpts;
+  $key->GetOptions( \%oldOpts )->SetOptions( Delimiter => "/" );
+
+=item SetOptions
+
+=item @oldOpts= $key->SetOptions( optNames=>$optValue,... )
+
+Changes the current setting of any of the following options,
+returning the previous setting(s):
+
+    Delimiter     FixSzNulls    DWordsToHex   AllowLoad
+    ArrayValues   SplitMultis   DualBinVals   AllowSave
+    TieValues     FastDelete    DualTypes
+
+For C<AllowLoad> and C<AllowSave>, instead of the previous
+setting, C<SetOptions> returns whether or not the change was
+successful.
+
+In a scalar context, returns only the last item.  The last
+option can also be specified as C<"ref"> or C<"r"> [which doesn't
+need to be followed by a value] to allow chaining:
+
+    $key->SetOptions(AllowSave=>1,"ref")->RegSaveKey(...)
+
+=item SetValue
+
+=item $okay= $key->SetValue( $ValueName, $ValueData );
+
+=item $okay= $key->SetValue( $ValueName, $ValueData, $ValueType );
+
+Adds or replaces a Registry value.  Returns a true value if
+successfully, false otherwise.
+
+C<$ValueName> is the name of the value to add or replace and
+should I<not> have a delimiter prepended to it.  Case is ignored.
+
+C<$ValueType> is assumed to be C<REG_SZ> if it is omitted.  Otherwise,
+it should be one the C<REG_*> constants.
+
+C<$ValueData> is the data to be stored in the value, probably packed
+into a Perl string.  Other supported formats for value data are
+listed below for each posible C<$ValueType>.
+
+=over
+
+=item REG_SZ or REG_EXPAND_SZ
+
+The only special processing for these values is the addition of
+the required trailing C<'\0'> if it is missing.  This can be
+turned off by disabling the C<FixSzNulls> option.
+
+=item REG_MULTI_SZ
+
+These values can also be specified as a reference to a list of
+strings.  For example, the following two lines are equivalent:
+
+    $key->SetValue( "Val1\000Value2\000LastVal\000\000", "REG_MULTI_SZ" );
+    $key->SetValue( ["Val1","Value2","LastVal"], "REG_MULTI_SZ" );
+
+Note that if the required two trailing nulls (C<"\000\000">) are
+missing, then this release of C<SetValue()> will I<not> add them.
+
+=item REG_DWORD
+
+These values can also be specified as a hex value with the leading
+C<"0x"> included and totaling I<more than> 4 bytes.  These will be
+packed into a 4-byte string via:
+
+    $data= pack( "L", hex($data) );
+
+=item REG_BINARY
+
+This value type is listed just to emphasize that no alternate
+format is supported for it.  In particular, you should I<not> pass
+in a numeric value for this type of data.  C<SetValue()> cannot
+distinguish such from a packed string that just happens to match
+a numeric value and so will treat it as a packed string.
+
+=back
+
+An alternate calling format:
+
+    $okay= $key->SetValue( $ValueName, [ $ValueData, $ValueType ] );
+
+[two arguments, the second of which is a reference to an array
+containing the value data and value type] is supported to ease
+using tied hashes with C<SetValue()>.
+
+=item CreateKey
+
+=item $newKey= $key->CreateKey( $subKey );
+
+=item $newKey= $key->CreateKey( $subKey, { Option=>OptVal,... } );
+
+Creates a Registry key or just updates attributes of one.  Calls
+C<RegCreateKeyEx()> then, if it succeeded, creates an object
+associated with the [possibly new] subkey.
+
+C<$subKey> is the name of a subkey [or a path to one] to be
+created or updated.  It can also be a reference to an array
+containing a list of subkey names.
+
+The second argument, if it exists, should be a reference to a
+hash specifying options either to be passed to C<RegCreateKeyEx()>
+or to be used when creating the associated object.  The following
+items are the supported keys for this options hash:
+
+=over
+
+=item Delimiter
+
+Specifies the delimiter to be used to parse C<$subKey> and to be
+used in the new object.  Defaults to C<$key->Delimiter>.
+
+=item Access
+
+Specifies the types of access requested when the subkey is opened.
+Should be a numeric bit mask that combines one or more C<KEY_*>
+constant values.
+
+=item Class
+
+The name to assign as the class of the new or updated subkey.
+Defaults to C<""> as we have never seen a use for this information.
+
+=item Disposition
+
+Lets you specify a reference to a scalar where, upon success, will be
+stored either C<REG_CREATED_NEW_KEY()> or C<REG_OPENED_EXISTING_KEY()>
+depending on whether a new key was created or an existing key was
+opened.
+
+If you, for example, did C<use Win32::TieRegistry qw(REG_CREATED_NEW_KEY)>
+then you can use C<REG_CREATED_NEW_KEY()> to compare against the numeric
+value stored in the referenced scalar.
+
+If the C<DualTypes> option is enabled, then in addition to the
+numeric value described above, the referenced scalar will also
+have a string value equal to either C<"REG_CREATED_NEW_KEY"> or
+C<"REG_OPENED_EXISTING_KEY">, as appropriate.
+
+=item Security
+
+Lets you specify a C<SECURITY_ATTRIBUTES> structure packed into a
+Perl string.  See C<Win32API::Registry::RegCreateKeyEx()> for more
+information.
+
+=item Volatile
+
+If true, specifies that the new key should be volatile, that is,
+stored only in memory and not backed by a hive file [and not saved
+if the computer is rebooted].  This option is ignored under
+Windows 95.  Specifying C<Volatile=E<GT>1>  is the same as
+specifying C<Options=E<GT>REG_OPTION_VOLATILE>.
+
+=item Backup
+
+If true, specifies that the new key should be opened for
+backup/restore access.  The C<Access> option is ignored.  If the
+calling process has enabled C<"SeBackupPrivilege">, then the
+subkey is opened with C<KEY_READ> access as the C<"LocalSystem">
+user which should have access to all subkeys.  If the calling
+process has enabled C<"SeRestorePrivilege">, then the subkey is
+opened with C<KEY_WRITE> access as the C<"LocalSystem"> user which
+should have access to all subkeys.
+
+This option is ignored under Windows 95.  Specifying C<Backup=E<GT>1>
+is the same as specifying C<Options=E<GT>REG_OPTION_BACKUP_RESTORE>.
+
+=item Options
+
+Lets you specify options to the C<RegOpenKeyEx()> call.  The value
+for this option should be a numeric value combining zero or more
+of the C<REG_OPTION_*> bit masks.  You may with to used the
+C<Volatile> and/or C<Backup> options instead of this one.
+
+=back
+
+=item StoreKey
+
+=item $newKey= $key->StoreKey( $subKey, \%Contents );
+
+Primarily for internal use.
+
+Used to create or update a Registry key and any number of subkeys
+or values under it or its subkeys.
+
+C<$subKey> is the name of a subkey to be created [or a path of
+subkey names separated by delimiters].  If that subkey already
+exists, then it is updated.
+
+C<\%Contents> is a reference to a hash containing pairs of
+value names with value data and/or subkey names with hash
+references similar to C<\%Contents>.  Each of these cause
+a value or subkey of C<$subKey> to be created or updated.
+
+If C<$Contents{""}> exists and is a reference to a hash, then
+it used as the options argument when C<CreateKey()> is called
+for C<$subKey>.  This allows you to specify ...
+
+    if(  defined( $$data{""} )  &&  "HASH" eq ref($$data{""})  ) {
+        $self= $this->CreateKey( $subKey, delete $$data{""} );
+
+=item Load
+
+=item $newKey= $key->Load( $file )
+
+=item $newKey= $key->Load( $file, $newSubKey )
+
+=item $newKey= $key->Load( $file, $newSubKey, { Option=>OptVal... } )
+
+=item $newKey= $key->Load( $file, { Option=>OptVal... } )
+
+Loads a hive file into a Registry.  That is, creates a new subkey
+and associates a hive file with it.
+
+C<$file> is a hive file, that is a file created by calling
+C<RegSaveKey()>.  The C<$file> path is interpreted relative to
+C<%SystemRoot%/System32/config> on the machine where C<$key>
+resides.
+
+C<$newSubKey> is the name to be given to the new subkey.  If
+C<$newSubKey> is specified, then C<$key> must be
+C<HKEY_LOCAL_MACHINE> or C<HKEY_USERS> of the local computer
+or a remote computer and C<$newSubKey> should not contain any
+occurrences of either the delimiter or the OS delimiter.
+
+If C<$newSubKey> is not specified, then it is as if C<$key>
+was C<$Registry-E<GT>{LMachine}> and C<$newSubKey> is
+C<"PerlTie:999"> where C<"999"> is actually a sequence number
+incremented each time this process calls C<Load()>.
+
+You can specify as the last argument a reference to a hash
+containing options.  You can specify the same options that you
+can specify to C<Open()>.  See C<Open()> for more information on
+those.  In addition, you can specify the option C<"NewSubKey">.
+The value of this option is interpretted exactly as if it was
+specified as the C<$newSubKey> parameter and overrides the
+C<$newSubKey> if one was specified.
+
+The hive is automatically unloaded when the returned object
+[C<$newKey>] is destroyed.  Registry key objects opened within
+the hive will keep a reference to the C<$newKey> object so that
+it will not be destroyed before these keys are closed.
+
+=item UnLoad
+
+=item $okay= $key->UnLoad
+
+Unloads a hive that was loaded via C<Load()>.  Cannot unload other
+hives.  C<$key> must be the return from a previous call to C<Load()>.
+C<$key> is closed and then the hive is unloaded.
+
+=item AllowSave
+
+=item $okay= AllowSave( $bool )
+
+Enables or disables the C<"ReBackupPrivilege"> privilege for the
+current process.  You will probably have to enable this privilege
+before you can use C<RegSaveKey()>.
+
+The return value indicates whether the operation succeeded, not
+whether the privilege was previously enabled.
+
+=item AllowLoad
+
+=item $okay= AllowLoad( $bool )
+
+Enables or disables the C<"ReRestorePrivilege"> privilege for the
+current process.  You will probably have to enable this privilege
+before you can use C<RegLoadKey()>, C<RegUnLoadKey()>,
+C<RegReplaceKey()>, or C<RegRestoreKey> and thus C<Load()> and
+C<UnLoad()>.
+
+The return value indicates whether the operation succeeded, not
+whether the privilege was previously enabled.
+
+=back
+
+=head2 Exports [C<use> and C<import()>]
+
+To have nothing imported into your package, use something like:
+
+    use Win32::TieRegistry 0.20 ();
+
+which would verify that you have at least version 0.20 but wouldn't
+call C<import()>.  The F<Changes> file can be useful in figuring out
+which, if any, prior versions of I<Win32::TieRegistry> you want to
+support in your script.
+
+The code
+
+    use Win32::TieRegistry;
+
+imports the variable C<$Registry> into your package and sets it
+to be a reference to a hash tied to a copy of the master Registry
+virtual root object with the default options.  One disadvantage
+to this "default" usage is that Perl does not support checking
+the module version when you use it.
+
+Alternately, you can specify a list of arguments on the C<use>
+line that will be passed to the C<Win32::TieRegistry->import()>
+method to control what items to import into your package.  These
+arguments fall into the following broad categories:
+
+=over
+
+=item Import a reference to a hash tied to a Registry virtual root
+
+You can request that a scalar variable be imported (possibly)
+and set to be a reference to a hash tied to a Registry virtual root
+using any of the following types of arguments or argument pairs:
+
+=over
+
+=item "TiedRef", '$scalar'
+
+=item "TiedRef", '$pack::scalar'
+
+=item "TiedRef", 'scalar'
+
+=item "TiedRef", 'pack::scalar'
+
+All of the above import a scalar named C<$scalar> into your package
+(or the package named "pack") and then sets it.
+
+=item '$scalar'
+
+=item '$pack::scalar'
+
+These are equivalent to the previous items to support a more
+traditional appearance to the list of exports.  Note that the
+scalar name cannot be "RegObj" here.
+
+=item "TiedRef", \$scalar
+
+=item \$scalar
+
+These versions don't import anything but set the referenced C<$scalar>.
+
+=back
+
+=item Import a hash tied to the Registry virtual root
+
+You can request that a hash variable be imported (possibly)
+and tied to a Registry virtual root using any of the following
+types of arguments or argument pairs:
+
+=over
+
+=item "TiedHash", '%hash'
+
+=item "TiedHash", '%pack::hash'
+
+=item "TiedHash", 'hash'
+
+=item "TiedHash", 'pack::hash'
+
+All of the above import a hash named C<%hash> into your package
+(or the package named "pack") and then sets it.
+
+=item '%hash'
+
+=item '%pack::hash'
+
+These are equivalent to the previous items to support a more
+traditional appearance to the list of exports.
+
+=item "TiedHash", \%hash
+
+=item \%hash
+
+These versions don't import anything but set the referenced C<%hash>.
+
+=back
+
+=item Import a Registry virtual root object
+
+You can request that a scalar variable be imported (possibly)
+and set to be a Registry virtual root object using any of the
+following types of arguments or argument pairs:
+
+=over
+
+=item "ObjectRef", '$scalar'
+
+=item "ObjectRef", '$pack::scalar'
+
+=item "ObjectRef", 'scalar'
+
+=item "ObjectRef", 'pack::scalar'
+
+All of the above import a scalar named C<$scalar> into your package
+(or the package named "pack") and then sets it.
+
+=item '$RegObj'
+
+This is equivalent to the previous items for backward compatibility.
+
+=item "ObjectRef", \$scalar
+
+This version doesn't import anything but sets the referenced C<$scalar>.
+
+=back
+
+=item Import constant(s) exported by I<Win32API::Registry>
+
+You can list any constants that are exported by I<Win32API::Registry>
+to have them imported into your package.  These constants have names
+starting with "KEY_" or "REG_" (or even "HKEY_").
+
+You can also specify C<":KEY_">, C<":REG_">, and even C<":HKEY_"> to
+import a whole set of constants.
+
+See I<Win32API::Registry> documentation for more information.
+
+=item Options
+
+You can list any option names that can be listed in the C<SetOptions()>
+method call, each folowed by the value to use for that option.
+A Registry virtual root object is created, all of these options are
+set for it, then each variable to be imported/set is associated with
+this object.
+
+In addition, the following special options are supported:
+
+=over
+
+=item ExportLevel
+
+Whether to import variables into your package or some
+package that uses your package.  Defaults to the value of
+C<$Exporter::ExportLevel> and has the same meaning.  See
+the L<Exporter> module for more information.
+
+=item ExportTo
+
+The name of the package to import variables and constants into.
+Overrides I<ExportLevel>.
+
+=back
+
+=back
+
+=head3 Specifying constants in your Perl code
+
+This module was written with a strong emphasis on the convenience of
+the module user.  Therefore, most places where you can specify a
+constant like C<REG_SZ()> also allow you to specify a string
+containing the name of the constant, C<"REG_SZ">.  This is convenient
+because you may not have imported that symbolic constant.
+
+Perl also emphasizes programmer convenience so the code C<REG_SZ>
+can be used to mean C<REG_SZ()> or C<"REG_SZ"> or be illegal.
+Note that using C<&REG_SZ> (as we've seen in much Win32 Perl code)
+is not a good idea since it passes the current C<@_> to the
+C<constant()> routine of the module which, at the least, can give
+you a warning under B<-w>.
+
+Although greatly a matter of style, the "safest" practice is probably
+to specifically list all constants in the C<use Win32::TieRegistry>
+statement, specify C<use strict> [or at least C<use strict qw(subs)>],
+and use bare constant names when you want the numeric value.  This will
+detect mispelled constant names at compile time.
+
+    use strict;
+    my $Registry;
+    use Win32::TieRegistry 0.20 (
+        TiedRef => \$Registry,  Delimiter => "/",  ArrayValues => 1,
+	SplitMultis => 1,  AllowLoad => 1,
+        qw( REG_SZ REG_EXPAND_SZ REG_DWORD REG_BINARY REG_MULTI_SZ
+	    KEY_READ KEY_WRITE KEY_ALL_ACCESS ),
+    );
+    $Registry->{"LMachine/Software/FooCorp/"}= {
+        "FooWriter/" => {
+            "/Fonts" => [ ["Times","Courier","Lucinda"], REG_MULTI_SZ ],
+	    "/WindowSize" => [ pack("LL",24,80), REG_BINARY ],
+	    "/TaskBarIcon" => [ "0x0001", REG_DWORD ],
+	},
+    }  or  die "Can't create Software/FooCorp/: $^E\n";
+
+If you don't want to C<use strict qw(subs)>, the second safest practice
+is similar to the above but use the C<REG_SZ()> form for constants
+when possible and quoted constant names when required.  Note that
+C<qw()> is a form of quoting.
+
+    use Win32::TieRegistry 0.20 qw(
+        TiedRef $Registry
+        Delimiter /  ArrayValues 1  SplitMultis 1  AllowLoad 1
+        REG_SZ REG_EXPAND_SZ REG_DWORD REG_BINARY REG_MULTI_SZ
+        KEY_READ KEY_WRITE KEY_ALL_ACCESS
+    );
+    $Registry->{"LMachine/Software/FooCorp/"}= {
+        "FooWriter/" => {
+            "/Fonts" => [ ["Times","Courier","Lucinda"], REG_MULTI_SZ() ],
+	    "/WindowSize" => [ pack("LL",24,80), REG_BINARY() ],
+	    "/TaskBarIcon" => [ "0x0001", REG_DWORD() ],
+	},
+    }  or  die "Can't create Software/FooCorp/: $^E\n";
+
+The examples in this document mostly use quoted constant names
+(C<"REG_SZ">) since that works regardless of which constants
+you imported and whether or not you have C<use strict> in your
+script.  It is not the best choice for you to use for real
+scripts (vs. examples) because it is less efficient and is not
+supported by most other similar modules.
+
+=head1 SUMMARY
+
+Most things can be done most easily via tied hashes.  Skip down to the
+the L<Tied Hashes Summary> to get started quickly.
+
+=head2 Objects Summary
+
+Here are quick examples that document the most common functionality
+of all of the method functions [except for a few almost useless ones].
+
+    # Just another way of saying Open():
+    $key= new Win32::TieRegistry "LMachine\\Software\\",
+      { Access=>KEY_READ()|KEY_WRITE(), Delimiter=>"\\" };
+
+    # Open a Registry key:
+    $subKey= $key->Open( "SubKey/SubSubKey/",
+      { Access=>KEY_ALL_ACCESS, Delimiter=>"/" } );
+
+    # Connect to a remote Registry key:
+    $remKey= $Registry->Connect( "MachineName", "LMachine/",
+      { Access=>KEY_READ, Delimiter=>"/" } );
+
+    # Get value data:
+    $valueString= $key->GetValue("ValueName");
+    ( $valueString, $valueType )= $key->GetValue("ValueName");
+
+    # Get list of value names:
+    @valueNames= $key->ValueNames;
+
+    # Get list of subkey names:
+    @subKeyNames= $key->SubKeyNames;
+
+    # Get combined list of value names (with leading delimiters)
+    # and subkey names (with trailing delimiters):
+    @memberNames= $key->MemberNames;
+
+    # Get all information about a key:
+    %keyInfo= $key->Information;
+    # keys(%keyInfo)= qw( Class LastWrite SecurityLen
+    #   CntSubKeys MaxSubKeyLen MaxSubClassLen
+    #   CntValues MaxValNameLen MaxValDataLen );
+
+    # Get selected information about a key:
+    ( $class, $cntSubKeys )= $key->Information( "Class", "CntSubKeys" );
+
+    # Get and/or set delimiter:
+    $delim= $key->Delimiter;
+    $oldDelim= $key->Delimiter( $newDelim );
+
+    # Get "path" for an open key:
+    $path= $key->Path;
+    # For example, "/CUser/Control Panel/Mouse/"
+    # or "//HostName/LMachine/System/DISK/".
+
+    # Get name of machine where key is from:
+    $mach= $key->Machine;
+    # Will usually be "" indicating key is on local machine.
+
+    # Control different options (see main documentation for descriptions):
+    $oldBool= $key->ArrayValues( $newBool );
+    $oldBool= $key->FastDelete( $newBool );
+    $oldBool= $key->FixSzNulls( $newBool );
+    $oldBool= $key->SplitMultis( $newBool );
+    $oldBool= $key->DWordsToHex( $newBool );
+    $oldBool= $key->DualBinVals( $newBool );
+    $oldBool= $key->DualTypes( $newBool );
+    @oldBools= $key->SetOptions( ArrayValues=>1, FastDelete=>1, FixSzNulls=>0,
+      Delimiter=>"/", AllowLoad=>1, AllowSave=>1 );
+    @oldBools= $key->GetOptions( ArrayValues, FastDelete, FixSzNulls );
+
+    # Add or set a value:
+    $key->SetValue( "ValueName", $valueDataString );
+    $key->SetValue( "ValueName", pack($format,$valueData), "REG_BINARY" );
+
+    # Add or set a key:
+    $key->CreateKey( "SubKeyName" );
+    $key->CreateKey( "SubKeyName",
+      { Access=>"KEY_ALL_ACCESS", Class=>"ClassName",
+        Delimiter=>"/", Volatile=>1, Backup=>1 } );
+
+    # Load an off-line Registry hive file into the on-line Registry:
+    $newKey= $Registry->Load( "C:/Path/To/Hive/FileName" );
+    $newKey= $key->Load( "C:/Path/To/Hive/FileName", "NewSubKeyName",
+                     { Access=>"KEY_READ" } );
+    # Unload a Registry hive file loaded via the Load() method:
+    $newKey->UnLoad;
+
+    # (Dis)Allow yourself to load Registry hive files:
+    $success= $Registry->AllowLoad( $bool );
+
+    # (Dis)Allow yourself to save a Registry key to a hive file:
+    $success= $Registry->AllowSave( $bool );
+
+    # Save a Registry key to a new hive file:
+    $key->RegSaveKey( "C:/Path/To/Hive/FileName", [] );
+
+=head3 Other Useful Methods
+
+See I<Win32API::Registry> for more information on these methods.
+These methods are provided for coding convenience and are
+identical to the I<Win32API::Registry> functions except that these
+don't take a handle to a Registry key, instead getting the handle
+from the invoking object [C<$key>].
+
+    $key->RegGetKeySecurity( $iSecInfo, $sSecDesc, $lenSecDesc );
+    $key->RegLoadKey( $sSubKeyName, $sPathToFile );
+    $key->RegNotifyChangeKeyValue(
+      $bWatchSubtree, $iNotifyFilter, $hEvent, $bAsync );
+    $key->RegQueryMultipleValues(
+      $structValueEnts, $cntValueEnts, $Buffer, $lenBuffer );
+    $key->RegReplaceKey( $sSubKeyName, $sPathToNewFile, $sPathToBackupFile );
+    $key->RegRestoreKey( $sPathToFile, $iFlags );
+    $key->RegSetKeySecurity( $iSecInfo, $sSecDesc );
+    $key->RegUnLoadKey( $sSubKeyName );
+
+=head2 Tied Hashes Summary
+
+For fast learners, this may be the only section you need to read.
+Always append one delimiter to the end of each Registry key name
+and prepend one delimiter to the front of each Registry value name.
+
+=head3 Opening keys
+
+    use Win32::TieRegistry ( Delimiter=>"/", ArrayValues=>1 );
+    $Registry->Delimiter("/");                  # Set delimiter to "/".
+    $swKey= $Registry->{"LMachine/Software/"};
+    $winKey= $swKey->{"Microsoft/Windows/CurrentVersion/"};
+    $userKey= $Registry->
+      {"CUser/Software/Microsoft/Windows/CurrentVersion/"};
+    $remoteKey= $Registry->{"//HostName/LMachine/"};
+
+=head3 Reading values
+
+    $progDir= $winKey->{"/ProgramFilesDir"};    # "C:\\Program Files"
+    $tip21= $winKey->{"Explorer/Tips//21"};     # Text of tip #21.
+
+    $winKey->ArrayValues(1);
+    ( $devPath, $type )= $winKey->{"/DevicePath"};
+    # $devPath eq "%SystemRoot%\\inf"
+    # $type eq "REG_EXPAND_SZ"  [if you have SetDualVar.pm installed]
+    # $type == REG_EXPAND_SZ()  [if did C<use Win32::TieRegistry qw(:REG_)>]
+
+=head3 Setting values
+
+    $winKey->{"Setup//SourcePath"}= "\\\\SwServer\\SwShare\\Windows";
+    # Simple.  Assumes data type of REG_SZ.
+
+    $winKey->{"Setup//Installation Sources"}=
+      [ "D:\x00\\\\SwServer\\SwShare\\Windows\0\0", "REG_MULTI_SZ" ];
+    # "\x00" and "\0" used to mark ends of each string and end of list.
+
+    $winKey->{"Setup//Installation Sources"}=
+      [ ["D:","\\\\SwServer\\SwShare\\Windows"], "REG_MULTI_SZ" ];
+    # Alternate method that is easier to read.
+
+    $userKey->{"Explorer/Tips//DisplayInitialTipWindow"}=
+      [ pack("L",0), "REG_DWORD" ];
+    $userKey->{"Explorer/Tips//Next"}= [ pack("S",3), "REG_BINARY" ];
+    $userKey->{"Explorer/Tips//Show"}= [ pack("L",0), "REG_BINARY" ];
+
+=head3 Adding keys
+
+    $swKey->{"FooCorp/"}= {
+        "FooWriter/" => {
+            "/Version" => "4.032",
+            "Startup/" => {
+                "/Title" => "Foo Writer Deluxe ][",
+                "/WindowSize" => [ pack("LL",$wid,$ht), "REG_BINARY" ],
+                "/TaskBarIcon" => [ "0x0001", "REG_DWORD" ],
+            },
+            "Compatibility/" => {
+                "/AutoConvert" => "Always",
+                "/Default Palette" => "Windows Colors",
+            },
+        },
+        "/License", => "0123-9C8EF1-09-FC",
+    };
+
+=head3 Listing all subkeys and values
+
+    @members= keys( %{$swKey} );
+    @subKeys= grep(  m#^/#,  keys( %{$swKey->{"Classes/batfile/"}} )  );
+    # @subKeys= ( "/", "/EditFlags" );
+    @valueNames= grep(  ! m#^/#,  keys( %{$swKey->{"Classes/batfile/"}} )  );
+    # @valueNames= ( "DefaultIcon/", "shell/", "shellex/" );
+
+=head3 Deleting values or keys with no subkeys
+
+    $oldValue= delete $userKey->{"Explorer/Tips//Next"};
+
+    $oldValues= delete $userKey->{"Explorer/Tips/"};
+    # $oldValues will be reference to hash containing deleted keys values.
+
+=head3 Closing keys
+
+    undef $swKey;               # Explicit way to close a key.
+    $winKey= "Anything else";   # Implicitly closes a key.
+    exit 0;                     # Implicitly closes all keys.
+
+=head2 Tie::Registry
+
+This module was originally called I<Tie::Registry>.  Changing code
+that used I<Tie::Registry> over to I<Win32::TieRegistry> is trivial
+as the module name should only be mentioned once, in the C<use>
+line.  However, finding all of the places that used I<Tie::Registry>
+may not be completely trivial so we have included F<Tie/Registry.pm>
+which you can install to provide backward compatibility.
+
+=head1 AUTHOR
+
+Tye McQueen.  See http://www.metronet.com/~tye/ or e-mail
+tye@metronet.com with bug reports.
+
+=head1 SEE ALSO
+
+I<Win32API::Registry> - Provides access to C<Reg*()>, C<HKEY_*>,
+C<KEY_*>, C<REG_*> [required].
+
+I<Win32::WinError> - Defines C<ERROR_*> values [optional].
+
+L<SetDualVar> - For returning C<REG_*> values as combined
+string/integer values [optional].
+
+=head1 BUGS
+
+Perl5.004_02 has bugs that make I<Win32::TieRegistry> fail in
+strange and subtle ways.
+
+Using I<Win32::TieRegistry> with versions of Perl prior to 5.005
+can be tricky or impossible.  Most notes about this have been
+removed from the documentation (they get rather complicated
+and confusing).  This includes references to C<$^E> perhaps not
+being meaningful.
+
+Because Perl hashes are case sensitive, certain lookups are also
+case sensistive.  In particular, the root keys ("Classes", "CUser",
+"LMachine", "Users", "PerfData", "CConfig", "DynData", and HKEY_*)
+must always be entered without changing between upper and lower
+case letters.  Also, the special rule for matching subkey names
+that contain the user-selected delimiter only works if case is
+matched.  All other key name and value name lookups should be case
+insensitive because the underlying Reg*() calls ignore case.
+
+Information about each key is cached when using a tied hash.
+This cache is not flushed nor updated when changes are made,
+I<even when the same tied hash is used> to make the changes.
+
+Current implementations of Perl's "global destruction" phase can
+cause objects returned by C<Load()> to be destroyed while keys
+within the hive are still open, if the objects still exist when
+the script starts to exit.  When this happens, the automatic
+C<UnLoad()> will report a failure and the hive will remain loaded
+in the Registry.
+
+Trying to C<Load()> a hive file that is located on a remote network
+share may silently delete all data from the hive.  This is a bug
+in the Win32 APIs, not any Perl code or modules.  This module does
+not try to protect you from this bug.
+
+There is no test suite.
+
+=head1 FUTURE DIRECTIONS
+
+The following items are desired by the author and may appear in a
+future release of this module.
+
+=over
+
+=item TieValues option
+
+Currently described in main documentation but no yet implemented.
+
+=item AutoRefresh option
+
+Trigger use of C<RegNotifyChangeKeyValue()> to keep tied hash
+caches up-to-date even when other programs make changes.
+
+=item Error options
+
+Allow the user to have unchecked calls (calls in a "void context")
+to automatically report errors via C<warn> or C<die>.
+
+For complex operations, such a copying an entire subtree, provide
+access to detailed information about errors (and perhaps some
+warnings) that were encountered.  Let the user control whether
+the complex operation continues in spite of errors.
+
+=back
+
+=cut
+
+# Autoload not currently supported by Perl under Windows.
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/WinError.pm
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/WinError.pm	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/WinError.pm	(revision 14139)
@@ -0,0 +1,1017 @@
+package Win32::WinError;
+
+require Exporter;
+require DynaLoader;
+
+$VERSION = '0.02';
+
+@ISA = qw(Exporter DynaLoader);
+# Items to export into callers namespace by default. Note: do not export
+# names by default without a very good reason. Use EXPORT_OK instead.
+# Do not simply export all your public functions/methods/constants.
+@EXPORT = qw(
+	GetLastError
+	CACHE_E_FIRST
+	CACHE_E_LAST
+	CACHE_E_NOCACHE_UPDATED
+	CACHE_S_FIRST
+	CACHE_S_FORMATETC_NOTSUPPORTED
+	CACHE_S_LAST
+	CACHE_S_SAMECACHE
+	CACHE_S_SOMECACHES_NOTUPDATED
+	CLASSFACTORY_E_FIRST
+	CLASSFACTORY_E_LAST
+	CLASSFACTORY_S_FIRST
+	CLASSFACTORY_S_LAST
+	CLASS_E_CLASSNOTAVAILABLE
+	CLASS_E_NOAGGREGATION
+	CLIENTSITE_E_FIRST
+	CLIENTSITE_E_LAST
+	CLIENTSITE_S_FIRST
+	CLIENTSITE_S_LAST
+	CLIPBRD_E_BAD_DATA
+	CLIPBRD_E_CANT_CLOSE
+	CLIPBRD_E_CANT_EMPTY
+	CLIPBRD_E_CANT_OPEN
+	CLIPBRD_E_CANT_SET
+	CLIPBRD_E_FIRST
+	CLIPBRD_E_LAST
+	CLIPBRD_S_FIRST
+	CLIPBRD_S_LAST
+	CONVERT10_E_FIRST
+	CONVERT10_E_LAST
+	CONVERT10_E_OLESTREAM_BITMAP_TO_DIB
+	CONVERT10_E_OLESTREAM_FMT
+	CONVERT10_E_OLESTREAM_GET
+	CONVERT10_E_OLESTREAM_PUT
+	CONVERT10_E_STG_DIB_TO_BITMAP
+	CONVERT10_E_STG_FMT
+	CONVERT10_E_STG_NO_STD_STREAM
+	CONVERT10_S_FIRST
+	CONVERT10_S_LAST
+	CONVERT10_S_NO_PRESENTATION
+	CO_E_ALREADYINITIALIZED
+	CO_E_APPDIDNTREG
+	CO_E_APPNOTFOUND
+	CO_E_APPSINGLEUSE
+	CO_E_BAD_PATH
+	CO_E_CANTDETERMINECLASS
+	CO_E_CLASSSTRING
+	CO_E_CLASS_CREATE_FAILED
+	CO_E_DLLNOTFOUND
+	CO_E_ERRORINAPP
+	CO_E_ERRORINDLL
+	CO_E_FIRST
+	CO_E_IIDSTRING
+	CO_E_INIT_CLASS_CACHE
+	CO_E_INIT_MEMORY_ALLOCATOR
+	CO_E_INIT_ONLY_SINGLE_THREADED
+	CO_E_INIT_RPC_CHANNEL
+	CO_E_INIT_SCM_EXEC_FAILURE
+	CO_E_INIT_SCM_FILE_MAPPING_EXISTS
+	CO_E_INIT_SCM_MAP_VIEW_OF_FILE
+	CO_E_INIT_SCM_MUTEX_EXISTS
+	CO_E_INIT_SHARED_ALLOCATOR
+	CO_E_INIT_TLS
+	CO_E_INIT_TLS_CHANNEL_CONTROL
+	CO_E_INIT_TLS_SET_CHANNEL_CONTROL
+	CO_E_INIT_UNACCEPTED_USER_ALLOCATOR
+	CO_E_LAST
+	CO_E_NOTINITIALIZED
+	CO_E_OBJISREG
+	CO_E_OBJNOTCONNECTED
+	CO_E_OBJNOTREG
+	CO_E_OBJSRV_RPC_FAILURE
+	CO_E_RELEASED
+	CO_E_SCM_ERROR
+	CO_E_SCM_RPC_FAILURE
+	CO_E_SERVER_EXEC_FAILURE
+	CO_E_SERVER_STOPPING
+	CO_E_WRONGOSFORAPP
+	CO_S_FIRST
+	CO_S_LAST
+	DATA_E_FIRST
+	DATA_E_LAST
+	DATA_S_FIRST
+	DATA_S_LAST
+	DATA_S_SAMEFORMATETC
+	DISP_E_ARRAYISLOCKED
+	DISP_E_BADCALLEE
+	DISP_E_BADINDEX
+	DISP_E_BADPARAMCOUNT
+	DISP_E_BADVARTYPE
+	DISP_E_EXCEPTION
+	DISP_E_MEMBERNOTFOUND
+	DISP_E_NONAMEDARGS
+	DISP_E_NOTACOLLECTION
+	DISP_E_OVERFLOW
+	DISP_E_PARAMNOTFOUND
+	DISP_E_PARAMNOTOPTIONAL
+	DISP_E_TYPEMISMATCH
+	DISP_E_UNKNOWNINTERFACE
+	DISP_E_UNKNOWNLCID
+	DISP_E_UNKNOWNNAME
+	DRAGDROP_E_ALREADYREGISTERED
+	DRAGDROP_E_FIRST
+	DRAGDROP_E_INVALIDHWND
+	DRAGDROP_E_LAST
+	DRAGDROP_E_NOTREGISTERED
+	DRAGDROP_S_CANCEL
+	DRAGDROP_S_DROP
+	DRAGDROP_S_FIRST
+	DRAGDROP_S_LAST
+	DRAGDROP_S_USEDEFAULTCURSORS
+	DV_E_CLIPFORMAT
+	DV_E_DVASPECT
+	DV_E_DVTARGETDEVICE
+	DV_E_DVTARGETDEVICE_SIZE
+	DV_E_FORMATETC
+	DV_E_LINDEX
+	DV_E_NOIVIEWOBJECT
+	DV_E_STATDATA
+	DV_E_STGMEDIUM
+	DV_E_TYMED
+	ENUM_E_FIRST
+	ENUM_E_LAST
+	ENUM_S_FIRST
+	ENUM_S_LAST
+	EPT_S_CANT_CREATE
+	EPT_S_CANT_PERFORM_OP
+	EPT_S_INVALID_ENTRY
+	EPT_S_NOT_REGISTERED
+	ERROR_ACCESS_DENIED
+	ERROR_ACCOUNT_DISABLED
+	ERROR_ACCOUNT_EXPIRED
+	ERROR_ACCOUNT_LOCKED_OUT
+	ERROR_ACCOUNT_RESTRICTION
+	ERROR_ACTIVE_CONNECTIONS
+	ERROR_ADAP_HDW_ERR
+	ERROR_ADDRESS_ALREADY_ASSOCIATED
+	ERROR_ADDRESS_NOT_ASSOCIATED
+	ERROR_ALIAS_EXISTS
+	ERROR_ALLOTTED_SPACE_EXCEEDED
+	ERROR_ALREADY_ASSIGNED
+	ERROR_ALREADY_EXISTS
+	ERROR_ALREADY_REGISTERED
+	ERROR_ALREADY_RUNNING_LKG
+	ERROR_ALREADY_WAITING
+	ERROR_ARENA_TRASHED
+	ERROR_ARITHMETIC_OVERFLOW
+	ERROR_ATOMIC_LOCKS_NOT_SUPPORTED
+	ERROR_AUTODATASEG_EXCEEDS_64k
+	ERROR_BADDB
+	ERROR_BADKEY
+	ERROR_BAD_ARGUMENTS
+	ERROR_BAD_COMMAND
+	ERROR_BAD_DESCRIPTOR_FORMAT
+	ERROR_BAD_DEVICE
+	ERROR_BAD_DEV_TYPE
+	ERROR_BAD_DRIVER
+	ERROR_BAD_DRIVER_LEVEL
+	ERROR_BAD_ENVIRONMENT
+	ERROR_BAD_EXE_FORMAT
+	ERROR_BAD_FORMAT
+	ERROR_BAD_IMPERSONATION_LEVEL
+	ERROR_BAD_INHERITANCE_ACL
+	ERROR_BAD_LENGTH
+	ERROR_BAD_LOGON_SESSION_STATE
+	ERROR_BAD_NETPATH
+	ERROR_BAD_NET_NAME
+	ERROR_BAD_NET_RESP
+	ERROR_BAD_PATHNAME
+	ERROR_BAD_PIPE
+	ERROR_BAD_PROFILE
+	ERROR_BAD_PROVIDER
+	ERROR_BAD_REM_ADAP
+	ERROR_BAD_THREADID_ADDR
+	ERROR_BAD_TOKEN_TYPE
+	ERROR_BAD_UNIT
+	ERROR_BAD_USERNAME
+	ERROR_BAD_VALIDATION_CLASS
+	ERROR_BEGINNING_OF_MEDIA
+	ERROR_BOOT_ALREADY_ACCEPTED
+	ERROR_BROKEN_PIPE
+	ERROR_BUFFER_OVERFLOW
+	ERROR_BUSY
+	ERROR_BUSY_DRIVE
+	ERROR_BUS_RESET
+	ERROR_CALL_NOT_IMPLEMENTED
+	ERROR_CANCELLED
+	ERROR_CANCEL_VIOLATION
+	ERROR_CANNOT_COPY
+	ERROR_CANNOT_FIND_WND_CLASS
+	ERROR_CANNOT_IMPERSONATE
+	ERROR_CANNOT_MAKE
+	ERROR_CANNOT_OPEN_PROFILE
+	ERROR_CANTOPEN
+	ERROR_CANTREAD
+	ERROR_CANTWRITE
+	ERROR_CANT_ACCESS_DOMAIN_INFO
+	ERROR_CANT_DISABLE_MANDATORY
+	ERROR_CANT_OPEN_ANONYMOUS
+	ERROR_CAN_NOT_COMPLETE
+	ERROR_CAN_NOT_DEL_LOCAL_WINS
+	ERROR_CHILD_MUST_BE_VOLATILE
+	ERROR_CHILD_NOT_COMPLETE
+	ERROR_CHILD_WINDOW_MENU
+	ERROR_CIRCULAR_DEPENDENCY
+	ERROR_CLASS_ALREADY_EXISTS
+	ERROR_CLASS_DOES_NOT_EXIST
+	ERROR_CLASS_HAS_WINDOWS
+	ERROR_CLIPBOARD_NOT_OPEN
+	ERROR_CLIPPING_NOT_SUPPORTED
+	ERROR_CONNECTION_ABORTED
+	ERROR_CONNECTION_ACTIVE
+	ERROR_CONNECTION_COUNT_LIMIT
+	ERROR_CONNECTION_INVALID
+	ERROR_CONNECTION_REFUSED
+	ERROR_CONNECTION_UNAVAIL
+	ERROR_CONTROL_ID_NOT_FOUND
+	ERROR_COUNTER_TIMEOUT
+	ERROR_CRC
+	ERROR_CURRENT_DIRECTORY
+	ERROR_DATABASE_DOES_NOT_EXIST
+	ERROR_DC_NOT_FOUND
+	ERROR_DEPENDENT_SERVICES_RUNNING
+	ERROR_DESTROY_OBJECT_OF_OTHER_THREAD
+	ERROR_DEVICE_ALREADY_REMEMBERED
+	ERROR_DEVICE_IN_USE
+	ERROR_DEVICE_NOT_PARTITIONED
+	ERROR_DEV_NOT_EXIST
+	ERROR_DIRECTORY
+	ERROR_DIRECT_ACCESS_HANDLE
+	ERROR_DIR_NOT_EMPTY
+	ERROR_DIR_NOT_ROOT
+	ERROR_DISCARDED
+	ERROR_DISK_CHANGE
+	ERROR_DISK_CORRUPT
+	ERROR_DISK_FULL
+	ERROR_DISK_OPERATION_FAILED
+	ERROR_DISK_RECALIBRATE_FAILED
+	ERROR_DISK_RESET_FAILED
+	ERROR_DLL_INIT_FAILED
+	ERROR_DOMAIN_CONTROLLER_NOT_FOUND
+	ERROR_DOMAIN_EXISTS
+	ERROR_DOMAIN_LIMIT_EXCEEDED
+	ERROR_DOMAIN_TRUST_INCONSISTENT
+	ERROR_DRIVE_LOCKED
+	ERROR_DUPLICATE_SERVICE_NAME
+	ERROR_DUP_DOMAINNAME
+	ERROR_DUP_NAME
+	ERROR_DYNLINK_FROM_INVALID_RING
+	ERROR_EAS_DIDNT_FIT
+	ERROR_EAS_NOT_SUPPORTED
+	ERROR_EA_ACCESS_DENIED
+	ERROR_EA_FILE_CORRUPT
+	ERROR_EA_LIST_INCONSISTENT
+	ERROR_EA_TABLE_FULL
+	ERROR_END_OF_MEDIA
+	ERROR_ENVVAR_NOT_FOUND
+	ERROR_EOM_OVERFLOW
+	ERROR_EVENTLOG_CANT_START
+	ERROR_EVENTLOG_FILE_CHANGED
+	ERROR_EVENTLOG_FILE_CORRUPT
+	ERROR_EXCEPTION_IN_SERVICE
+	ERROR_EXCL_SEM_ALREADY_OWNED
+	ERROR_EXE_MARKED_INVALID
+	ERROR_EXTENDED_ERROR
+	ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
+	ERROR_FAIL_I24
+	ERROR_FILEMARK_DETECTED
+	ERROR_FILENAME_EXCED_RANGE
+	ERROR_FILE_CORRUPT
+	ERROR_FILE_EXISTS
+	ERROR_FILE_INVALID
+	ERROR_FILE_NOT_FOUND
+	ERROR_FLOPPY_BAD_REGISTERS
+	ERROR_FLOPPY_ID_MARK_NOT_FOUND
+	ERROR_FLOPPY_UNKNOWN_ERROR
+	ERROR_FLOPPY_WRONG_CYLINDER
+	ERROR_FULLSCREEN_MODE
+	ERROR_FULL_BACKUP
+	ERROR_GENERIC_NOT_MAPPED
+	ERROR_GEN_FAILURE
+	ERROR_GLOBAL_ONLY_HOOK
+	ERROR_GRACEFUL_DISCONNECT
+	ERROR_GROUP_EXISTS
+	ERROR_HANDLE_DISK_FULL
+	ERROR_HANDLE_EOF
+	ERROR_HOOK_NEEDS_HMOD
+	ERROR_HOOK_NOT_INSTALLED
+	ERROR_HOST_UNREACHABLE
+	ERROR_HOTKEY_ALREADY_REGISTERED
+	ERROR_HOTKEY_NOT_REGISTERED
+	ERROR_HWNDS_HAVE_DIFF_PARENT
+	ERROR_ILL_FORMED_PASSWORD
+	ERROR_INCORRECT_ADDRESS
+	ERROR_INC_BACKUP
+	ERROR_INFLOOP_IN_RELOC_CHAIN
+	ERROR_INSUFFICIENT_BUFFER
+	ERROR_INTERNAL_DB_CORRUPTION
+	ERROR_INTERNAL_DB_ERROR
+	ERROR_INTERNAL_ERROR
+	ERROR_INVALID_ACCEL_HANDLE
+	ERROR_INVALID_ACCESS
+	ERROR_INVALID_ACCOUNT_NAME
+	ERROR_INVALID_ACL
+	ERROR_INVALID_ADDRESS
+	ERROR_INVALID_AT_INTERRUPT_TIME
+	ERROR_INVALID_BLOCK
+	ERROR_INVALID_BLOCK_LENGTH
+	ERROR_INVALID_CATEGORY
+	ERROR_INVALID_COMBOBOX_MESSAGE
+	ERROR_INVALID_COMPUTERNAME
+	ERROR_INVALID_CURSOR_HANDLE
+	ERROR_INVALID_DATA
+	ERROR_INVALID_DATATYPE
+	ERROR_INVALID_DOMAINNAME
+	ERROR_INVALID_DOMAIN_ROLE
+	ERROR_INVALID_DOMAIN_STATE
+	ERROR_INVALID_DRIVE
+	ERROR_INVALID_DWP_HANDLE
+	ERROR_INVALID_EA_HANDLE
+	ERROR_INVALID_EA_NAME
+	ERROR_INVALID_EDIT_HEIGHT
+	ERROR_INVALID_ENVIRONMENT
+	ERROR_INVALID_EVENTNAME
+	ERROR_INVALID_EVENT_COUNT
+	ERROR_INVALID_EXE_SIGNATURE
+	ERROR_INVALID_FILTER_PROC
+	ERROR_INVALID_FLAGS
+	ERROR_INVALID_FLAG_NUMBER
+	ERROR_INVALID_FORM_NAME
+	ERROR_INVALID_FORM_SIZE
+	ERROR_INVALID_FUNCTION
+	ERROR_INVALID_GROUPNAME
+	ERROR_INVALID_GROUP_ATTRIBUTES
+	ERROR_INVALID_GW_COMMAND
+	ERROR_INVALID_HANDLE
+	ERROR_INVALID_HOOK_FILTER
+	ERROR_INVALID_HOOK_HANDLE
+	ERROR_INVALID_ICON_HANDLE
+	ERROR_INVALID_ID_AUTHORITY
+	ERROR_INVALID_INDEX
+	ERROR_INVALID_LB_MESSAGE
+	ERROR_INVALID_LEVEL
+	ERROR_INVALID_LIST_FORMAT
+	ERROR_INVALID_LOGON_HOURS
+	ERROR_INVALID_LOGON_TYPE
+	ERROR_INVALID_MEMBER
+	ERROR_INVALID_MENU_HANDLE
+	ERROR_INVALID_MESSAGE
+	ERROR_INVALID_MESSAGEDEST
+	ERROR_INVALID_MESSAGENAME
+	ERROR_INVALID_MINALLOCSIZE
+	ERROR_INVALID_MODULETYPE
+	ERROR_INVALID_MSGBOX_STYLE
+	ERROR_INVALID_NAME
+	ERROR_INVALID_NETNAME
+	ERROR_INVALID_ORDINAL
+	ERROR_INVALID_OWNER
+	ERROR_INVALID_PARAMETER
+	ERROR_INVALID_PASSWORD
+	ERROR_INVALID_PASSWORDNAME
+	ERROR_INVALID_PIXEL_FORMAT
+	ERROR_INVALID_PRIMARY_GROUP
+	ERROR_INVALID_PRINTER_COMMAND
+	ERROR_INVALID_PRINTER_NAME
+	ERROR_INVALID_PRINTER_STATE
+	ERROR_INVALID_PRIORITY
+	ERROR_INVALID_SCROLLBAR_RANGE
+	ERROR_INVALID_SECURITY_DESCR
+	ERROR_INVALID_SEGDPL
+	ERROR_INVALID_SEGMENT_NUMBER
+	ERROR_INVALID_SEPARATOR_FILE
+	ERROR_INVALID_SERVER_STATE
+	ERROR_INVALID_SERVICENAME
+	ERROR_INVALID_SERVICE_ACCOUNT
+	ERROR_INVALID_SERVICE_CONTROL
+	ERROR_INVALID_SERVICE_LOCK
+	ERROR_INVALID_SHARENAME
+	ERROR_INVALID_SHOWWIN_COMMAND
+	ERROR_INVALID_SID
+	ERROR_INVALID_SIGNAL_NUMBER
+	ERROR_INVALID_SPI_VALUE
+	ERROR_INVALID_STACKSEG
+	ERROR_INVALID_STARTING_CODESEG
+	ERROR_INVALID_SUB_AUTHORITY
+	ERROR_INVALID_TARGET_HANDLE
+	ERROR_INVALID_THREAD_ID
+	ERROR_INVALID_TIME
+	ERROR_INVALID_USER_BUFFER
+	ERROR_INVALID_VERIFY_SWITCH
+	ERROR_INVALID_WINDOW_HANDLE
+	ERROR_INVALID_WINDOW_STYLE
+	ERROR_INVALID_WORKSTATION
+	ERROR_IOPL_NOT_ENABLED
+	ERROR_IO_DEVICE
+	ERROR_IO_INCOMPLETE
+	ERROR_IO_PENDING
+	ERROR_IRQ_BUSY
+	ERROR_IS_JOINED
+	ERROR_IS_JOIN_PATH
+	ERROR_IS_JOIN_TARGET
+	ERROR_IS_SUBSTED
+	ERROR_IS_SUBST_PATH
+	ERROR_IS_SUBST_TARGET
+	ERROR_ITERATED_DATA_EXCEEDS_64k
+	ERROR_JOIN_TO_JOIN
+	ERROR_JOIN_TO_SUBST
+	ERROR_JOURNAL_HOOK_SET
+	ERROR_KEY_DELETED
+	ERROR_KEY_HAS_CHILDREN
+	ERROR_LABEL_TOO_LONG
+	ERROR_LAST_ADMIN
+	ERROR_LB_WITHOUT_TABSTOPS
+	ERROR_LISTBOX_ID_NOT_FOUND
+	ERROR_LM_CROSS_ENCRYPTION_REQUIRED
+	ERROR_LOCAL_USER_SESSION_KEY
+	ERROR_LOCKED
+	ERROR_LOCK_FAILED
+	ERROR_LOCK_VIOLATION
+	ERROR_LOGIN_TIME_RESTRICTION
+	ERROR_LOGIN_WKSTA_RESTRICTION
+	ERROR_LOGON_FAILURE
+	ERROR_LOGON_NOT_GRANTED
+	ERROR_LOGON_SESSION_COLLISION
+	ERROR_LOGON_SESSION_EXISTS
+	ERROR_LOGON_TYPE_NOT_GRANTED
+	ERROR_LOG_FILE_FULL
+	ERROR_LUIDS_EXHAUSTED
+	ERROR_MAPPED_ALIGNMENT
+	ERROR_MAX_THRDS_REACHED
+	ERROR_MEDIA_CHANGED
+	ERROR_MEMBERS_PRIMARY_GROUP
+	ERROR_MEMBER_IN_ALIAS
+	ERROR_MEMBER_IN_GROUP
+	ERROR_MEMBER_NOT_IN_ALIAS
+	ERROR_MEMBER_NOT_IN_GROUP
+	ERROR_METAFILE_NOT_SUPPORTED
+	ERROR_META_EXPANSION_TOO_LONG
+	ERROR_MOD_NOT_FOUND
+	ERROR_MORE_DATA
+	ERROR_MORE_WRITES
+	ERROR_MR_MID_NOT_FOUND
+	ERROR_NEGATIVE_SEEK
+	ERROR_NESTING_NOT_ALLOWED
+	ERROR_NETLOGON_NOT_STARTED
+	ERROR_NETNAME_DELETED
+	ERROR_NETWORK_ACCESS_DENIED
+	ERROR_NETWORK_BUSY
+	ERROR_NETWORK_UNREACHABLE
+	ERROR_NET_WRITE_FAULT
+	ERROR_NOACCESS
+	ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT
+	ERROR_NOLOGON_SERVER_TRUST_ACCOUNT
+	ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT
+	ERROR_NONE_MAPPED
+	ERROR_NON_MDICHILD_WINDOW
+	ERROR_NOTIFY_ENUM_DIR
+	ERROR_NOT_ALL_ASSIGNED
+	ERROR_NOT_CHILD_WINDOW
+	ERROR_NOT_CONNECTED
+	ERROR_NOT_CONTAINER
+	ERROR_NOT_DOS_DISK
+	ERROR_NOT_ENOUGH_MEMORY
+	ERROR_NOT_ENOUGH_QUOTA
+	ERROR_NOT_ENOUGH_SERVER_MEMORY
+	ERROR_NOT_JOINED
+	ERROR_NOT_LOCKED
+	ERROR_NOT_LOGON_PROCESS
+	ERROR_NOT_OWNER
+	ERROR_NOT_READY
+	ERROR_NOT_REGISTRY_FILE
+	ERROR_NOT_SAME_DEVICE
+	ERROR_NOT_SUBSTED
+	ERROR_NOT_SUPPORTED
+	ERROR_NO_BROWSER_SERVERS_FOUND
+	ERROR_NO_DATA
+	ERROR_NO_DATA_DETECTED
+	ERROR_NO_IMPERSONATION_TOKEN
+	ERROR_NO_INHERITANCE
+	ERROR_NO_LOGON_SERVERS
+	ERROR_NO_LOG_SPACE
+	ERROR_NO_MEDIA_IN_DRIVE
+	ERROR_NO_MORE_FILES
+	ERROR_NO_MORE_ITEMS
+	ERROR_NO_MORE_SEARCH_HANDLES
+	ERROR_NO_NETWORK
+	ERROR_NO_NET_OR_BAD_PATH
+	ERROR_NO_PROC_SLOTS
+	ERROR_NO_QUOTAS_FOR_ACCOUNT
+	ERROR_NO_SCROLLBARS
+	ERROR_NO_SECURITY_ON_OBJECT
+	ERROR_NO_SHUTDOWN_IN_PROGRESS
+	ERROR_NO_SIGNAL_SENT
+	ERROR_NO_SPOOL_SPACE
+	ERROR_NO_SUCH_ALIAS
+	ERROR_NO_SUCH_DOMAIN
+	ERROR_NO_SUCH_GROUP
+	ERROR_NO_SUCH_LOGON_SESSION
+	ERROR_NO_SUCH_MEMBER
+	ERROR_NO_SUCH_PACKAGE
+	ERROR_NO_SUCH_PRIVILEGE
+	ERROR_NO_SUCH_USER
+	ERROR_NO_SYSTEM_MENU
+	ERROR_NO_TOKEN
+	ERROR_NO_TRUST_LSA_SECRET
+	ERROR_NO_TRUST_SAM_ACCOUNT
+	ERROR_NO_UNICODE_TRANSLATION
+	ERROR_NO_USER_SESSION_KEY
+	ERROR_NO_VOLUME_LABEL
+	ERROR_NO_WILDCARD_CHARACTERS
+	ERROR_NT_CROSS_ENCRYPTION_REQUIRED
+	ERROR_NULL_LM_PASSWORD
+	ERROR_OPEN_FAILED
+	ERROR_OPEN_FILES
+	ERROR_OPERATION_ABORTED
+	ERROR_OUTOFMEMORY
+	ERROR_OUT_OF_PAPER
+	ERROR_OUT_OF_STRUCTURES
+	ERROR_PARTIAL_COPY
+	ERROR_PARTITION_FAILURE
+	ERROR_PASSWORD_EXPIRED
+	ERROR_PASSWORD_MUST_CHANGE
+	ERROR_PASSWORD_RESTRICTION
+	ERROR_PATH_BUSY
+	ERROR_PATH_NOT_FOUND
+	ERROR_PIPE_BUSY
+	ERROR_PIPE_CONNECTED
+	ERROR_PIPE_LISTENING
+	ERROR_PIPE_NOT_CONNECTED
+	ERROR_POPUP_ALREADY_ACTIVE
+	ERROR_PORT_UNREACHABLE
+	ERROR_POSSIBLE_DEADLOCK
+	ERROR_PRINTER_ALREADY_EXISTS
+	ERROR_PRINTER_DELETED
+	ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
+	ERROR_PRINTER_DRIVER_IN_USE
+	ERROR_PRINTQ_FULL
+	ERROR_PRINT_CANCELLED
+	ERROR_PRINT_MONITOR_ALREADY_INSTALLED
+	ERROR_PRINT_PROCESSOR_ALREADY_INSTALLED
+	ERROR_PRIVATE_DIALOG_INDEX
+	ERROR_PRIVILEGE_NOT_HELD
+	ERROR_PROCESS_ABORTED
+	ERROR_PROC_NOT_FOUND
+	ERROR_PROTOCOL_UNREACHABLE
+	ERROR_READ_FAULT
+	ERROR_REC_NON_EXISTENT
+	ERROR_REDIRECTOR_HAS_OPEN_HANDLES
+	ERROR_REDIR_PAUSED
+	ERROR_REGISTRY_CORRUPT
+	ERROR_REGISTRY_IO_FAILED
+	ERROR_REGISTRY_RECOVERED
+	ERROR_RELOC_CHAIN_XEEDS_SEGLIM
+	ERROR_REMOTE_SESSION_LIMIT_EXCEEDED
+	ERROR_REM_NOT_LIST
+	ERROR_REQUEST_ABORTED
+	ERROR_REQ_NOT_ACCEP
+	ERROR_RESOURCE_DATA_NOT_FOUND
+	ERROR_RESOURCE_LANG_NOT_FOUND
+	ERROR_RESOURCE_NAME_NOT_FOUND
+	ERROR_RESOURCE_TYPE_NOT_FOUND
+	ERROR_RETRY
+	ERROR_REVISION_MISMATCH
+	ERROR_RING2SEG_MUST_BE_MOVABLE
+	ERROR_RING2_STACK_IN_USE
+	ERROR_RPL_NOT_ALLOWED
+	ERROR_RXACT_COMMIT_FAILURE
+	ERROR_RXACT_INVALID_STATE
+	ERROR_SAME_DRIVE
+	ERROR_SCREEN_ALREADY_LOCKED
+	ERROR_SECRET_TOO_LONG
+	ERROR_SECTOR_NOT_FOUND
+	ERROR_SEEK
+	ERROR_SEEK_ON_DEVICE
+	ERROR_SEM_IS_SET
+	ERROR_SEM_NOT_FOUND
+	ERROR_SEM_OWNER_DIED
+	ERROR_SEM_TIMEOUT
+	ERROR_SEM_USER_LIMIT
+	ERROR_SERIAL_NO_DEVICE
+	ERROR_SERVER_DISABLED
+	ERROR_SERVER_HAS_OPEN_HANDLES
+	ERROR_SERVER_NOT_DISABLED
+	ERROR_SERVICE_ALREADY_RUNNING
+	ERROR_SERVICE_CANNOT_ACCEPT_CTRL
+	ERROR_SERVICE_DATABASE_LOCKED
+	ERROR_SERVICE_DEPENDENCY_DELETED
+	ERROR_SERVICE_DEPENDENCY_FAIL
+	ERROR_SERVICE_DISABLED
+	ERROR_SERVICE_DOES_NOT_EXIST
+	ERROR_SERVICE_EXISTS
+	ERROR_SERVICE_LOGON_FAILED
+	ERROR_SERVICE_MARKED_FOR_DELETE
+	ERROR_SERVICE_NEVER_STARTED
+	ERROR_SERVICE_NOT_ACTIVE
+	ERROR_SERVICE_NOT_FOUND
+	ERROR_SERVICE_NO_THREAD
+	ERROR_SERVICE_REQUEST_TIMEOUT
+	ERROR_SERVICE_SPECIFIC_ERROR
+	ERROR_SERVICE_START_HANG
+	ERROR_SESSION_CREDENTIAL_CONFLICT
+	ERROR_SETCOUNT_ON_BAD_LB
+	ERROR_SETMARK_DETECTED
+	ERROR_SHARING_BUFFER_EXCEEDED
+	ERROR_SHARING_PAUSED
+	ERROR_SHARING_VIOLATION
+	ERROR_SHUTDOWN_IN_PROGRESS
+	ERROR_SIGNAL_PENDING
+	ERROR_SIGNAL_REFUSED
+	ERROR_SOME_NOT_MAPPED
+	ERROR_SPECIAL_ACCOUNT
+	ERROR_SPECIAL_GROUP
+	ERROR_SPECIAL_USER
+	ERROR_SPL_NO_ADDJOB
+	ERROR_SPL_NO_STARTDOC
+	ERROR_SPOOL_FILE_NOT_FOUND
+	ERROR_STACK_OVERFLOW
+	ERROR_STATIC_INIT
+	ERROR_SUBST_TO_JOIN
+	ERROR_SUBST_TO_SUBST
+	ERROR_SUCCESS
+	ERROR_SWAPERROR
+	ERROR_SYSTEM_TRACE
+	ERROR_THREAD_1_INACTIVE
+	ERROR_TLW_WITH_WSCHILD
+	ERROR_TOKEN_ALREADY_IN_USE
+	ERROR_TOO_MANY_CMDS
+	ERROR_TOO_MANY_CONTEXT_IDS
+	ERROR_TOO_MANY_LUIDS_REQUESTED
+	ERROR_TOO_MANY_MODULES
+	ERROR_TOO_MANY_MUXWAITERS
+	ERROR_TOO_MANY_NAMES
+	ERROR_TOO_MANY_OPEN_FILES
+	ERROR_TOO_MANY_POSTS
+	ERROR_TOO_MANY_SECRETS
+	ERROR_TOO_MANY_SEMAPHORES
+	ERROR_TOO_MANY_SEM_REQUESTS
+	ERROR_TOO_MANY_SESS
+	ERROR_TOO_MANY_SIDS
+	ERROR_TOO_MANY_TCBS
+	ERROR_TRANSFORM_NOT_SUPPORTED
+	ERROR_TRUSTED_DOMAIN_FAILURE
+	ERROR_TRUSTED_RELATIONSHIP_FAILURE
+	ERROR_TRUST_FAILURE
+	ERROR_UNABLE_TO_LOCK_MEDIA
+	ERROR_UNABLE_TO_UNLOAD_MEDIA
+	ERROR_UNEXP_NET_ERR
+	ERROR_UNKNOWN_PORT
+	ERROR_UNKNOWN_PRINTER_DRIVER
+	ERROR_UNKNOWN_PRINTPROCESSOR
+	ERROR_UNKNOWN_PRINT_MONITOR
+	ERROR_UNKNOWN_REVISION
+	ERROR_UNRECOGNIZED_MEDIA
+	ERROR_UNRECOGNIZED_VOLUME
+	ERROR_USER_EXISTS
+	ERROR_USER_MAPPED_FILE
+	ERROR_VC_DISCONNECTED
+	ERROR_WAIT_NO_CHILDREN
+	ERROR_WINDOW_NOT_COMBOBOX
+	ERROR_WINDOW_NOT_DIALOG
+	ERROR_WINDOW_OF_OTHER_THREAD
+	ERROR_WINS_INTERNAL
+	ERROR_WRITE_FAULT
+	ERROR_WRITE_PROTECT
+	ERROR_WRONG_DISK
+	ERROR_WRONG_PASSWORD
+	E_ABORT
+	E_ACCESSDENIED
+	E_FAIL
+	E_HANDLE
+	E_INVALIDARG
+	E_NOINTERFACE
+	E_NOTIMPL
+	E_OUTOFMEMORY
+	E_POINTER
+	E_UNEXPECTED
+	FACILITY_CONTROL
+	FACILITY_DISPATCH
+	FACILITY_ITF
+	FACILITY_NT_BIT
+	FACILITY_NULL
+	FACILITY_RPC
+	FACILITY_STORAGE
+	FACILITY_WIN32
+	FACILITY_WINDOWS
+	INPLACE_E_FIRST
+	INPLACE_E_LAST
+	INPLACE_E_NOTOOLSPACE
+	INPLACE_E_NOTUNDOABLE
+	INPLACE_S_FIRST
+	INPLACE_S_LAST
+	INPLACE_S_TRUNCATED
+	MARSHAL_E_FIRST
+	MARSHAL_E_LAST
+	MARSHAL_S_FIRST
+	MARSHAL_S_LAST
+	MEM_E_INVALID_LINK
+	MEM_E_INVALID_ROOT
+	MEM_E_INVALID_SIZE
+	MK_E_CANTOPENFILE
+	MK_E_CONNECTMANUALLY
+	MK_E_ENUMERATION_FAILED
+	MK_E_EXCEEDEDDEADLINE
+	MK_E_FIRST
+	MK_E_INTERMEDIATEINTERFACENOTSUPPORTED
+	MK_E_INVALIDEXTENSION
+	MK_E_LAST
+	MK_E_MUSTBOTHERUSER
+	MK_E_NEEDGENERIC
+	MK_E_NOINVERSE
+	MK_E_NOOBJECT
+	MK_E_NOPREFIX
+	MK_E_NOSTORAGE
+	MK_E_NOTBINDABLE
+	MK_E_NOTBOUND
+	MK_E_NO_NORMALIZED
+	MK_E_SYNTAX
+	MK_E_UNAVAILABLE
+	MK_S_FIRST
+	MK_S_HIM
+	MK_S_LAST
+	MK_S_ME
+	MK_S_MONIKERALREADYREGISTERED
+	MK_S_REDUCED_TO_SELF
+	MK_S_US
+	NOERROR
+	NO_ERROR
+	OLEOBJ_E_FIRST
+	OLEOBJ_E_INVALIDVERB
+	OLEOBJ_E_LAST
+	OLEOBJ_E_NOVERBS
+	OLEOBJ_S_CANNOT_DOVERB_NOW
+	OLEOBJ_S_FIRST
+	OLEOBJ_S_INVALIDHWND
+	OLEOBJ_S_INVALIDVERB
+	OLEOBJ_S_LAST
+	OLE_E_ADVF
+	OLE_E_ADVISENOTSUPPORTED
+	OLE_E_BLANK
+	OLE_E_CANTCONVERT
+	OLE_E_CANT_BINDTOSOURCE
+	OLE_E_CANT_GETMONIKER
+	OLE_E_CLASSDIFF
+	OLE_E_ENUM_NOMORE
+	OLE_E_FIRST
+	OLE_E_INVALIDHWND
+	OLE_E_INVALIDRECT
+	OLE_E_LAST
+	OLE_E_NOCACHE
+	OLE_E_NOCONNECTION
+	OLE_E_NOSTORAGE
+	OLE_E_NOTRUNNING
+	OLE_E_NOT_INPLACEACTIVE
+	OLE_E_OLEVERB
+	OLE_E_PROMPTSAVECANCELLED
+	OLE_E_STATIC
+	OLE_E_WRONGCOMPOBJ
+	OLE_S_FIRST
+	OLE_S_LAST
+	OLE_S_MAC_CLIPFORMAT
+	OLE_S_STATIC
+	OLE_S_USEREG
+	REGDB_E_CLASSNOTREG
+	REGDB_E_FIRST
+	REGDB_E_IIDNOTREG
+	REGDB_E_INVALIDVALUE
+	REGDB_E_KEYMISSING
+	REGDB_E_LAST
+	REGDB_E_READREGDB
+	REGDB_E_WRITEREGDB
+	REGDB_S_FIRST
+	REGDB_S_LAST
+	RPC_E_ATTEMPTED_MULTITHREAD
+	RPC_E_CALL_CANCELED
+	RPC_E_CALL_REJECTED
+	RPC_E_CANTCALLOUT_AGAIN
+	RPC_E_CANTCALLOUT_INASYNCCALL
+	RPC_E_CANTCALLOUT_INEXTERNALCALL
+	RPC_E_CANTCALLOUT_ININPUTSYNCCALL
+	RPC_E_CANTPOST_INSENDCALL
+	RPC_E_CANTTRANSMIT_CALL
+	RPC_E_CHANGED_MODE
+	RPC_E_CLIENT_CANTMARSHAL_DATA
+	RPC_E_CLIENT_CANTUNMARSHAL_DATA
+	RPC_E_CLIENT_DIED
+	RPC_E_CONNECTION_TERMINATED
+	RPC_E_DISCONNECTED
+	RPC_E_FAULT
+	RPC_E_INVALIDMETHOD
+	RPC_E_INVALID_CALLDATA
+	RPC_E_INVALID_DATA
+	RPC_E_INVALID_DATAPACKET
+	RPC_E_INVALID_PARAMETER
+	RPC_E_NOT_REGISTERED
+	RPC_E_OUT_OF_RESOURCES
+	RPC_E_RETRY
+	RPC_E_SERVERCALL_REJECTED
+	RPC_E_SERVERCALL_RETRYLATER
+	RPC_E_SERVERFAULT
+	RPC_E_SERVER_CANTMARSHAL_DATA
+	RPC_E_SERVER_CANTUNMARSHAL_DATA
+	RPC_E_SERVER_DIED
+	RPC_E_SERVER_DIED_DNE
+	RPC_E_SYS_CALL_FAILED
+	RPC_E_THREAD_NOT_INIT
+	RPC_E_UNEXPECTED
+	RPC_E_WRONG_THREAD
+	RPC_S_ADDRESS_ERROR
+	RPC_S_ALREADY_LISTENING
+	RPC_S_ALREADY_REGISTERED
+	RPC_S_BINDING_HAS_NO_AUTH
+	RPC_S_BINDING_INCOMPLETE
+	RPC_S_CALL_CANCELLED
+	RPC_S_CALL_FAILED
+	RPC_S_CALL_FAILED_DNE
+	RPC_S_CALL_IN_PROGRESS
+	RPC_S_CANNOT_SUPPORT
+	RPC_S_CANT_CREATE_ENDPOINT
+	RPC_S_COMM_FAILURE
+	RPC_S_DUPLICATE_ENDPOINT
+	RPC_S_ENTRY_ALREADY_EXISTS
+	RPC_S_ENTRY_NOT_FOUND
+	RPC_S_FP_DIV_ZERO
+	RPC_S_FP_OVERFLOW
+	RPC_S_FP_UNDERFLOW
+	RPC_S_GROUP_MEMBER_NOT_FOUND
+	RPC_S_INCOMPLETE_NAME
+	RPC_S_INTERFACE_NOT_FOUND
+	RPC_S_INTERNAL_ERROR
+	RPC_S_INVALID_AUTH_IDENTITY
+	RPC_S_INVALID_BINDING
+	RPC_S_INVALID_BOUND
+	RPC_S_INVALID_ENDPOINT_FORMAT
+	RPC_S_INVALID_NAF_ID
+	RPC_S_INVALID_NAME_SYNTAX
+	RPC_S_INVALID_NETWORK_OPTIONS
+	RPC_S_INVALID_NET_ADDR
+	RPC_S_INVALID_OBJECT
+	RPC_S_INVALID_RPC_PROTSEQ
+	RPC_S_INVALID_STRING_BINDING
+	RPC_S_INVALID_STRING_UUID
+	RPC_S_INVALID_TAG
+	RPC_S_INVALID_TIMEOUT
+	RPC_S_INVALID_VERS_OPTION
+	RPC_S_MAX_CALLS_TOO_SMALL
+	RPC_S_NAME_SERVICE_UNAVAILABLE
+	RPC_S_NOTHING_TO_EXPORT
+	RPC_S_NOT_ALL_OBJS_UNEXPORTED
+	RPC_S_NOT_CANCELLED
+	RPC_S_NOT_LISTENING
+	RPC_S_NOT_RPC_ERROR
+	RPC_S_NO_BINDINGS
+	RPC_S_NO_CALL_ACTIVE
+	RPC_S_NO_CONTEXT_AVAILABLE
+	RPC_S_NO_ENDPOINT_FOUND
+	RPC_S_NO_ENTRY_NAME
+	RPC_S_NO_INTERFACES
+	RPC_S_NO_MORE_BINDINGS
+	RPC_S_NO_MORE_MEMBERS
+	RPC_S_NO_PRINC_NAME
+	RPC_S_NO_PROTSEQS
+	RPC_S_NO_PROTSEQS_REGISTERED
+	RPC_S_OBJECT_NOT_FOUND
+	RPC_S_OUT_OF_RESOURCES
+	RPC_S_PROCNUM_OUT_OF_RANGE
+	RPC_S_PROTOCOL_ERROR
+	RPC_S_PROTSEQ_NOT_FOUND
+	RPC_S_PROTSEQ_NOT_SUPPORTED
+	RPC_S_SEC_PKG_ERROR
+	RPC_S_SERVER_TOO_BUSY
+	RPC_S_SERVER_UNAVAILABLE
+	RPC_S_STRING_TOO_LONG
+	RPC_S_TYPE_ALREADY_REGISTERED
+	RPC_S_UNKNOWN_AUTHN_LEVEL
+	RPC_S_UNKNOWN_AUTHN_SERVICE
+	RPC_S_UNKNOWN_AUTHN_TYPE
+	RPC_S_UNKNOWN_AUTHZ_SERVICE
+	RPC_S_UNKNOWN_IF
+	RPC_S_UNKNOWN_MGR_TYPE
+	RPC_S_UNSUPPORTED_AUTHN_LEVEL
+	RPC_S_UNSUPPORTED_NAME_SYNTAX
+	RPC_S_UNSUPPORTED_TRANS_SYN
+	RPC_S_UNSUPPORTED_TYPE
+	RPC_S_UUID_LOCAL_ONLY
+	RPC_S_UUID_NO_ADDRESS
+	RPC_S_WRONG_KIND_OF_BINDING
+	RPC_S_ZERO_DIVIDE
+	RPC_X_BAD_STUB_DATA
+	RPC_X_BYTE_COUNT_TOO_SMALL
+	RPC_X_ENUM_VALUE_OUT_OF_RANGE
+	RPC_X_INVALID_ES_ACTION
+	RPC_X_NO_MORE_ENTRIES
+	RPC_X_NULL_REF_POINTER
+	RPC_X_SS_CANNOT_GET_CALL_HANDLE
+	RPC_X_SS_CHAR_TRANS_OPEN_FAIL
+	RPC_X_SS_CHAR_TRANS_SHORT_FILE
+	RPC_X_SS_CONTEXT_DAMAGED
+	RPC_X_SS_HANDLES_MISMATCH
+	RPC_X_SS_IN_NULL_CONTEXT
+	RPC_X_WRONG_ES_VERSION
+	RPC_X_WRONG_STUB_VERSION
+	SEVERITY_ERROR
+	SEVERITY_SUCCESS
+	STG_E_ABNORMALAPIEXIT
+	STG_E_ACCESSDENIED
+	STG_E_CANTSAVE
+	STG_E_DISKISWRITEPROTECTED
+	STG_E_EXTANTMARSHALLINGS
+	STG_E_FILEALREADYEXISTS
+	STG_E_FILENOTFOUND
+	STG_E_INSUFFICIENTMEMORY
+	STG_E_INUSE
+	STG_E_INVALIDFLAG
+	STG_E_INVALIDFUNCTION
+	STG_E_INVALIDHANDLE
+	STG_E_INVALIDHEADER
+	STG_E_INVALIDNAME
+	STG_E_INVALIDPARAMETER
+	STG_E_INVALIDPOINTER
+	STG_E_LOCKVIOLATION
+	STG_E_MEDIUMFULL
+	STG_E_NOMOREFILES
+	STG_E_NOTCURRENT
+	STG_E_NOTFILEBASEDSTORAGE
+	STG_E_OLDDLL
+	STG_E_OLDFORMAT
+	STG_E_PATHNOTFOUND
+	STG_E_READFAULT
+	STG_E_REVERTED
+	STG_E_SEEKERROR
+	STG_E_SHAREREQUIRED
+	STG_E_SHAREVIOLATION
+	STG_E_TOOMANYOPENFILES
+	STG_E_UNIMPLEMENTEDFUNCTION
+	STG_E_UNKNOWN
+	STG_E_WRITEFAULT
+	STG_S_CONVERTED
+	S_FALSE
+	S_OK
+	TYPE_E_AMBIGUOUSNAME
+	TYPE_E_BADMODULEKIND
+	TYPE_E_BUFFERTOOSMALL
+	TYPE_E_CANTCREATETMPFILE
+	TYPE_E_CANTLOADLIBRARY
+	TYPE_E_CIRCULARTYPE
+	TYPE_E_DLLFUNCTIONNOTFOUND
+	TYPE_E_DUPLICATEID
+	TYPE_E_ELEMENTNOTFOUND
+	TYPE_E_INCONSISTENTPROPFUNCS
+	TYPE_E_INVALIDID
+	TYPE_E_INVALIDSTATE
+	TYPE_E_INVDATAREAD
+	TYPE_E_IOERROR
+	TYPE_E_LIBNOTREGISTERED
+	TYPE_E_NAMECONFLICT
+	TYPE_E_OUTOFBOUNDS
+	TYPE_E_QUALIFIEDNAMEDISALLOWED
+	TYPE_E_REGISTRYACCESS
+	TYPE_E_SIZETOOBIG
+	TYPE_E_TYPEMISMATCH
+	TYPE_E_UNDEFINEDTYPE
+	TYPE_E_UNKNOWNLCID
+	TYPE_E_UNSUPFORMAT
+	TYPE_E_WRONGTYPEKIND
+	VIEW_E_DRAW
+	VIEW_E_FIRST
+	VIEW_E_LAST
+	VIEW_S_ALREADY_FROZEN
+	VIEW_S_FIRST
+	VIEW_S_LAST
+);
+
+sub AUTOLOAD {
+    # This AUTOLOAD is used to 'autoload' constants from the constant()
+    # XS function.  If a constant is not found then control is passed
+    # to the AUTOLOAD in AutoLoader.
+
+    my($constname);
+    ($constname = $AUTOLOAD) =~ s/.*:://;
+    #reset $! to zero to reset any current errors.
+    local $! = 0;
+    local $^E = 0;
+    my $val = constant($constname, @_ ? $_[0] : 0);
+    if ($! != 0) {
+	if ($! =~ /Invalid/) {
+	    $AutoLoader::AUTOLOAD = $AUTOLOAD;
+	    goto &AutoLoader::AUTOLOAD;
+	}
+	else {
+	    ($pack,$file,$line) = caller;
+	    die "Your vendor has not defined Win32::WinError macro $constname, used at $file line $line.";
+	}
+    }
+    eval "sub $AUTOLOAD { $val }";
+    goto &$AUTOLOAD;
+}
+
+bootstrap Win32::WinError;
+
+# Preloaded methods go here.
+
+# Autoload methods go after __END__, and are processed by the autosplit program.
+
+1;
+__END__
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/test-async.pl
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/test-async.pl	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/Win32/test-async.pl	(revision 14139)
@@ -0,0 +1,129 @@
+#
+# TEST-ASYNC.PL
+# Test Win32::Internet's Asynchronous Operations
+# by Aldo Calpini <dada@divinf.it>
+#
+# WARNING: this code is most likely to fail with almost-random errors
+#          I don't know what is wrong here, any hint will be greatly
+#          appreciated! 
+
+use Win32::Internet;
+
+$params{'flags'} = INTERNET_FLAG_ASYNC;
+$params{'opentype'} = INTERNET_OPEN_TYPE_DIRECT;
+$I = new Win32::Internet(\%params);
+
+# print "Error: ", $I->Error(), "\n";
+print "I.handle=", $I->{'handle'}, "\n";
+
+$return = $I->SetStatusCallback();
+print "SetStatusCallback=$return";
+print "ERROR" if $return eq undef;
+print "\n";
+
+$buffer = $I->QueryOption(INTERNET_OPTION_READ_BUFFER_SIZE);
+print "Buffer=$buffer\n";
+
+$host = "ftp.activeware.com";
+$user = "anonymous";
+$pass = "dada\@divinf.it";
+
+
+print "Doing FTP()...\n";
+
+$handle2 = $I->FTP($FTP, $host, $user, $pass, 21, 1);
+
+print "Returned from FTP()...\n";
+
+($n, $t) = $I->Error();
+
+if($n == 997) {
+  print "Going asynchronous...\n";
+  ($status, $info) = $I->GetStatusCallback(1);
+  while($status != 100 and $status != 70) {
+    if($oldstatus != $status) {
+      if($status == 60) {
+        $FTP->{'handle'} = $info;
+      } elsif($status == 10) {
+        print "resolving name...                   \n";
+      } elsif($status == 11) {
+        print "name resolved...                    \n";
+      } elsif($status == 20) {
+        print "connecting...                       \n";
+      } elsif($status == 21) {
+        print "connected...                        \n";
+      } elsif($status == 30) {
+        print "sending...                          \n";
+      } elsif($status == 31) {
+        print "$info bytes sent.                   \n";
+      } elsif($status == 40) {    
+        print "receiving...                        \n";
+      } elsif($status == 41) {      
+        print "$info bytes received.               \n";
+      } else {
+        print "status=$status\n";
+      }    
+    }
+    $oldstatus = $status;
+    ($status, $info) = $I->GetStatusCallback(1);
+  }
+} else {
+  print "Error=", $I->Error(), "\n";
+}
+print "FTP.handle=", $FTP->{'handle'}, "\n";
+print "STATUS(after FTP)=", $I->GetStatusCallback(1), "\n";
+
+#                                    "/pub/microsoft/sdk/activex13.exe",
+
+print "Doing Get()...\n";
+
+$file = "/Perl-Win32/perl5.001m/currentBuild/110-i86.zip";
+
+$FTP->Get($file, "110-i86.zip", 1, 0, 2);
+
+print "Returned from Get()...\n";
+
+($n, $t) = $I->Error();
+if($n == 997) {
+  print "Going asynchronous...\n";
+  $bytes = 0;
+  $oldstatus = 0;
+  ($status, $info) = $I->GetStatusCallback(2);
+  while($status != 100 and $status != 70) {
+    # print "status=$status info=$info\n";
+    # if($oldstatus!=$status) {
+      if($status == 10) {
+        print "resolving name...                   \n";
+      } elsif($status == 11) {
+        print "name resolved...                    \n";
+      } elsif($status == 20) {
+        print "connecting...                       \n";
+      } elsif($status == 21) {
+        print "connected...                        \n";
+      #} elsif($status == 30) {
+      #  print "sending...                          \n";
+      } elsif($status == 31) {
+        print "$info bytes sent.                   \n";
+      #} elsif($status == 40) {    
+      #  print "receiving...                       \n";
+      } elsif($status == 41) {      
+        $bytes = $bytes+$info;
+        print "$bytes bytes received.              \n";
+      #} else {
+      #  print "status=$status\n";
+      }
+    # }
+    $oldstatus = $status;
+    undef $status, $info;
+    ($status, $info) = $I->GetStatusCallback(2);
+  } 
+} else {
+  print "Error=[$n] $t\n";
+}
+print "\n";
+($status, $info) = $I->GetStatusCallback(2);
+print "STATUS(after Get)=$status\n";
+print "Error=", $I->Error(), "\n";
+exit(0);
+
+
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/ActivePerl/DocTools/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/ActivePerl/DocTools/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/ActivePerl/DocTools/.packlist	(revision 14139)
@@ -0,0 +1,7 @@
+C:\mdewsnip\perl-5.6.1\site\lib\ActivePerl\DocTools.pm
+C:\mdewsnip\perl-5.6.1\site\lib\ActivePerl\DocTools\PSP\Searcher.pm
+C:\mdewsnip\perl-5.6.1\site\lib\ActivePerl\DocTools\PSP\Socket.pm
+C:\mdewsnip\perl-5.6.1\site\lib\ActivePerl\DocTools\TOC.pm
+C:\mdewsnip\perl-5.6.1\site\lib\ActivePerl\DocTools\TOC\HTML.pm
+C:\mdewsnip\perl-5.6.1\site\lib\ActivePerl\DocTools\TOC\RDF.pm
+C:\mdewsnip\perl-5.6.1\site\lib\ActivePerl\DocTools\Tree\HTML.pm
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/ActiveState/RelocateTree/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/ActiveState/RelocateTree/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/ActiveState/RelocateTree/.packlist	(revision 14139)
@@ -0,0 +1,4 @@
+C:\mdewsnip\perl-5.6.1\bin\reloc_perl
+C:\mdewsnip\perl-5.6.1\bin\reloc_perl.bat
+C:\mdewsnip\perl-5.6.1\site\lib\ActiveState\RelocateTree.pm
+C:\mdewsnip\perl-5.6.1\site\lib\ActiveState\RelocateTree.pod
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/ActiveState/Rx/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/ActiveState/Rx/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/ActiveState/Rx/.packlist	(revision 14139)
@@ -0,0 +1,6 @@
+C:\mdewsnip\perl-5.6.1\site\lib\ActiveState\Rx.pm
+C:\mdewsnip\perl-5.6.1\site\lib\ActiveState\Rx\Info.pm
+C:\mdewsnip\perl-5.6.1\site\lib\auto\ActiveState\Rx\Rx.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\ActiveState\Rx\Rx.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\ActiveState\Rx\Rx.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\ActiveState\Rx\Rx.lib
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Archive/Tar/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Archive/Tar/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Archive/Tar/.packlist	(revision 14139)
@@ -0,0 +1,3 @@
+C:\mdewsnip\perl-5.6.1\site\lib\Archive\Tar.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Archive\Tar\Constant.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Archive\Tar\File.pm
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Archive/Zip/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Archive/Zip/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Archive/Zip/.packlist	(revision 14139)
@@ -0,0 +1,6 @@
+C:\mdewsnip\perl-5.6.1\bin\crc32
+C:\mdewsnip\perl-5.6.1\bin\crc32.bat
+C:\mdewsnip\perl-5.6.1\site\lib\Archive\Zip.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Archive\Zip\BufferedFileHandle.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Archive\Zip\MockFileHandle.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Archive\Zip\Tree.pm
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Compress/Zlib/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Compress/Zlib/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Compress/Zlib/.packlist	(revision 14139)
@@ -0,0 +1,8 @@
+C:\mdewsnip\perl-5.6.1\site\lib\Compress\Zlib.pm
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Compress\Zlib\Zlib.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Compress\Zlib\Zlib.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Compress\Zlib\Zlib.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Compress\Zlib\Zlib.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Compress\Zlib\Zlib.pdb
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Compress\Zlib\autosplit.ix
+C:\mdewsnip\perl-5.6.1\site\lib\auto\zlib\extralibs.ld
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Compress/Zlib/autosplit.ix
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Compress/Zlib/autosplit.ix	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Compress/Zlib/autosplit.ix	(revision 14139)
@@ -0,0 +1,3 @@
+# Index created by AutoSplit for blib\lib\Compress\Zlib.pm
+#    (file acts as timestamp)
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/DBD/ODBC/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/DBD/ODBC/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/DBD/ODBC/.packlist	(revision 14139)
@@ -0,0 +1,7 @@
+C:\mdewsnip\perl-5.6.1\site\lib\DBD\ODBC.pm
+C:\mdewsnip\perl-5.6.1\site\lib\DBD\ODBC\Changes.pm
+C:\mdewsnip\perl-5.6.1\site\lib\auto\DBD\ODBC\ODBC.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\DBD\ODBC\ODBC.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\DBD\ODBC\ODBC.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\DBD\ODBC\ODBC.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\DBD\ODBC\ODBC.pdb
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/DBI/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/DBI/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/DBI/.packlist	(revision 14139)
@@ -0,0 +1,43 @@
+C:\mdewsnip\perl-5.6.1\bin\dbiprof
+C:\mdewsnip\perl-5.6.1\bin\dbiprof.bat
+C:\mdewsnip\perl-5.6.1\bin\dbiproxy
+C:\mdewsnip\perl-5.6.1\bin\dbiproxy.bat
+C:\mdewsnip\perl-5.6.1\site\lib\Bundle\DBI.pm
+C:\mdewsnip\perl-5.6.1\site\lib\DBD\DBM.pm
+C:\mdewsnip\perl-5.6.1\site\lib\DBD\ExampleP.pm
+C:\mdewsnip\perl-5.6.1\site\lib\DBD\File.pm
+C:\mdewsnip\perl-5.6.1\site\lib\DBD\NullP.pm
+C:\mdewsnip\perl-5.6.1\site\lib\DBD\Proxy.pm
+C:\mdewsnip\perl-5.6.1\site\lib\DBD\Sponge.pm
+C:\mdewsnip\perl-5.6.1\site\lib\DBI.pm
+C:\mdewsnip\perl-5.6.1\site\lib\DBI\Changes.pm
+C:\mdewsnip\perl-5.6.1\site\lib\DBI\Const\GetInfoReturn.pm
+C:\mdewsnip\perl-5.6.1\site\lib\DBI\Const\GetInfoType.pm
+C:\mdewsnip\perl-5.6.1\site\lib\DBI\Const\GetInfo\ANSI.pm
+C:\mdewsnip\perl-5.6.1\site\lib\DBI\Const\GetInfo\ODBC.pm
+C:\mdewsnip\perl-5.6.1\site\lib\DBI\DBD.pm
+C:\mdewsnip\perl-5.6.1\site\lib\DBI\DBD\Metadata.pm
+C:\mdewsnip\perl-5.6.1\site\lib\DBI\FAQ.pm
+C:\mdewsnip\perl-5.6.1\site\lib\DBI\Profile.pm
+C:\mdewsnip\perl-5.6.1\site\lib\DBI\ProfileData.pm
+C:\mdewsnip\perl-5.6.1\site\lib\DBI\ProfileDumper.pm
+C:\mdewsnip\perl-5.6.1\site\lib\DBI\ProfileDumper\Apache.pm
+C:\mdewsnip\perl-5.6.1\site\lib\DBI\ProxyServer.pm
+C:\mdewsnip\perl-5.6.1\site\lib\DBI\PurePerl.pm
+C:\mdewsnip\perl-5.6.1\site\lib\DBI\Roadmap.pm
+C:\mdewsnip\perl-5.6.1\site\lib\DBI\SQL\Nano.pm
+C:\mdewsnip\perl-5.6.1\site\lib\DBI\W32ODBC.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Roadmap.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\DBIODBC.pm
+C:\mdewsnip\perl-5.6.1\site\lib\auto\DBI\DBI.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\DBI\DBI.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\DBI\DBI.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\DBI\DBI.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\DBI\DBI.pdb
+C:\mdewsnip\perl-5.6.1\site\lib\auto\DBI\DBIXS.h
+C:\mdewsnip\perl-5.6.1\site\lib\auto\DBI\Driver.xst
+C:\mdewsnip\perl-5.6.1\site\lib\auto\DBI\Driver_xst.h
+C:\mdewsnip\perl-5.6.1\site\lib\auto\DBI\dbd_xsh.h
+C:\mdewsnip\perl-5.6.1\site\lib\auto\DBI\dbi_sql.h
+C:\mdewsnip\perl-5.6.1\site\lib\auto\DBI\dbipport.h
+C:\mdewsnip\perl-5.6.1\site\lib\auto\DBI\dbivport.h
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/DBI/DBIXS.h
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/DBI/DBIXS.h	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/DBI/DBIXS.h	(revision 14139)
@@ -0,0 +1,510 @@
+/* $Id$
+ *
+ * Copyright (c) 1994-2002  Tim Bunce  Ireland
+ *
+ * See COPYRIGHT section in DBI.pm for usage and distribution rights.
+ */
+
+/* DBI Interface Definitions for DBD Modules */
+
+#ifndef DBIXS_VERSION				/* prevent multiple inclusion */
+
+#ifndef DBIS
+#define DBIS	dbis	/* default name for dbistate_t variable	*/
+#endif
+
+/* first pull in the standard Perl header files for extensions	*/
+#define PERL_POLLUTE
+#include <EXTERN.h>
+#include <perl.h>
+#include <XSUB.h>
+
+#ifdef debug		/* causes problems with DBIS->debug	*/
+#undef debug
+#endif
+
+#ifdef std             /* causes problems with STLport <tscheresky@micron.com> */
+#undef std
+#endif
+
+/* Perl backwards compatibility definitions */
+#include "dbipport.h"
+
+/* DBI SQL_* type definitions */
+#include "dbi_sql.h"
+
+
+/* The DBIXS_VERSION value will be incremented whenever new code is
+ * added to the interface (this file) or significant changes are made.
+ * It's primary goal is to allow newer drivers to compile against an
+ * older installed DBI. This is mainly an issue whilst the API grows
+ * and learns from the needs of various drivers.  See also the
+ * DBISTATE_VERSION macro below. You can think of DBIXS_VERSION as
+ * being a compile time check and DBISTATE_VERSION as a runtime check.
+ */
+#define DBIXS_VERSION 93
+
+#ifdef NEED_DBIXS_VERSION
+#if NEED_DBIXS_VERSION > DBIXS_VERSION
+error You_need_to_upgrade_your_DBI_module_before_building_this_driver
+#endif
+#else
+#define NEED_DBIXS_VERSION DBIXS_VERSION
+#endif
+
+
+#define DBI_LOCK
+#define DBI_UNLOCK
+
+#ifndef DBI_NO_THREADS
+#ifdef USE_ITHREADS
+#define DBI_USE_THREADS
+#endif /* USE_ITHREADS */
+#endif /* DBI_NO_THREADS */
+
+
+/* forward struct declarations						*/
+
+typedef struct dbistate_st dbistate_t;
+/* implementor needs to define actual struct { dbih_??c_t com; ... }*/
+typedef struct imp_drh_st imp_drh_t;	/* driver			*/
+typedef struct imp_dbh_st imp_dbh_t;	/* database			*/
+typedef struct imp_sth_st imp_sth_t;	/* statement			*/
+typedef struct imp_fdh_st imp_fdh_t;	/* field descriptor		*/
+typedef struct imp_xxh_st imp_xxh_t;	/* any (defined below)		*/
+#define DBI_imp_data_ imp_xxh_t		/* friendly for take_imp_data	*/
+
+
+
+/* --- DBI Handle Common Data Structure (all handles have one) ---	*/
+
+/* Handle types. Code currently assumes child = parent + 1.		*/
+#define DBIt_DR		1
+#define DBIt_DB		2
+#define DBIt_ST		3
+#define DBIt_FD		4
+
+/* component structures */
+
+typedef struct dbih_com_std_st {
+    U32  flags;
+    int  call_depth;	/* used by DBI to track nested calls (int)	*/
+    U16  type;		/* DBIt_DR, DBIt_DB, DBIt_ST			*/
+    HV   *my_h;		/* copy of outer handle HV (not refcounted)	*/
+    SV   *parent_h;	/* parent inner handle (ref to hv) (r.c.inc)	*/
+    imp_xxh_t *parent_com;	/* parent com struct shortcut		*/
+    PerlInterpreter * thr_user;  /* thread that owns the handle         */
+
+    HV   *imp_stash;	/* who is the implementor for this handle	*/
+    SV   *imp_data;	/* optional implementors data (for perl imp's)	*/
+
+    I32  kids;		/* count of db's for dr's, st's for db's etc	*/
+    I32  active_kids;	/* kids which are currently DBIc_ACTIVE		*/
+    U32 pad;		/* keep binary compat */
+    dbistate_t *dbistate;
+} dbih_com_std_t;
+
+typedef struct dbih_com_attr_st {
+    /* These are copies of the Hash values (ref.cnt.inc'd)	*/
+    /* Many of the hash values are themselves references	*/
+    SV *TraceLevel;
+    SV *State;		/* Standard SQLSTATE, 5 char string	*/
+    SV *Err;		/* Native engine error code		*/
+    SV *Errstr;		/* Native engine error message		*/
+    UV ErrCount;
+    U32  LongReadLen;	/* auto read length for long/blob types	*/
+    SV *FetchHashKeyName;	/* for fetchrow_hashref		*/
+    /* (NEW FIELDS?... DON'T FORGET TO UPDATE dbih_clearcom()!)	*/
+} dbih_com_attr_t;
+
+
+struct dbih_com_st {	/* complete core structure (typedef'd above)	*/
+    dbih_com_std_t	std;
+    dbih_com_attr_t	attr;
+};
+
+/* This 'implementors' type the DBI defines by default as a way to	*/
+/* refer to the imp_??h data of a handle without considering its type.	*/
+struct imp_xxh_st { struct dbih_com_st com; };
+
+/* Define handle-type specific structures for implementors to include	*/
+/* at the start of their private structures.				*/
+
+typedef struct {		/* -- DRIVER --				*/
+    dbih_com_std_t	std;
+    dbih_com_attr_t	attr;
+    HV          *cached_kids;	/* $drh->connect_cached(...)		*/
+} dbih_drc_t;
+
+typedef struct {		/* -- DATABASE --			*/
+    dbih_com_std_t	std;	/* \__ standard structure		*/
+    dbih_com_attr_t	attr;	/* /   plus... (nothing else right now)	*/
+    HV          *cached_kids;	/* $dbh->prepare_cached(...)		*/
+} dbih_dbc_t;
+
+typedef struct {		/* -- STATEMENT --			*/
+    dbih_com_std_t	std;	/* \__ standard structure		*/
+    dbih_com_attr_t	attr;	/* /   plus ...				*/
+
+    int 	num_params;	/* number of placeholders		*/
+    int 	num_fields;	/* NUM_OF_FIELDS, must be set		*/
+    AV  	*fields_svav;	/* special row buffer (inc bind_cols)	*/
+    IV		row_count;	/* incremented by get_fbav()		*/
+
+    AV		*fields_fdav;	/* not used yet, may change */
+
+    I32  spare1;
+    void *spare2;
+} dbih_stc_t;
+
+
+/* XXX THIS STRUCTURE SHOULD NOT BE USED */
+typedef struct {		/* -- FIELD DESCRIPTOR --		*/
+    dbih_com_std_t	std;	/* standard structure (not fully setup)	*/
+
+    /* core attributes (from DescribeCol in ODBC)		*/
+    char *col_name;		/* see dbih_make_fdsv		*/
+    I16   col_name_len;
+    I16   col_sql_type;
+    I16   col_precision;
+    I16   col_scale;
+    I16   col_nullable;
+
+    /* additional attributes (from ColAttributes in ODBC)	*/
+    I32   col_length;
+    I32   col_disp_size;
+
+    I32  spare1;
+    void *spare2;
+} dbih_fdc_t;
+
+
+#define _imp2com(p,f)      	((p)->com.f)
+
+#define DBIc_FLAGS(imp)		_imp2com(imp, std.flags)
+#define DBIc_TYPE(imp)		_imp2com(imp, std.type)
+#define DBIc_CALL_DEPTH(imp)	_imp2com(imp, std.call_depth)
+#define DBIc_MY_H(imp)  	_imp2com(imp, std.my_h)
+#define DBIc_PARENT_H(imp)  	_imp2com(imp, std.parent_h)
+#define DBIc_PARENT_COM(imp)  	_imp2com(imp, std.parent_com)
+#define DBIc_THR_COND(imp)  	_imp2com(imp, std.thr_cond)
+#define DBIc_THR_USER(imp)  	_imp2com(imp, std.thr_user)
+#define DBIc_THR_USER_NONE  	(0xFFFF)
+#define DBIc_IMP_STASH(imp)  	_imp2com(imp, std.imp_stash)
+#define DBIc_IMP_DATA(imp)  	_imp2com(imp, std.imp_data)
+#define DBIc_DBISTATE(imp)  	_imp2com(imp, std.dbistate)
+#define DBIc_LOGPIO(imp)  	DBIc_DBISTATE(imp)->logfp
+#define DBIc_KIDS(imp)  	_imp2com(imp, std.kids)
+#define DBIc_ACTIVE_KIDS(imp)  	_imp2com(imp, std.active_kids)
+#define DBIc_LAST_METHOD(imp)  	_imp2com(imp, std.last_method)
+
+#define DBIc_TRACE_LEVEL_MASK	0x0000000F
+#define DBIc_TRACE_FLAGS_MASK	0xFFFFFF00
+#define DBIc_TRACE_SETTINGS(imp) (DBIc_DBISTATE(imp)->debug)
+#define DBIc_TRACE_LEVEL(imp)	(DBIc_TRACE_SETTINGS(imp) & DBIc_TRACE_LEVEL_MASK)
+#define DBIc_TRACE_FLAGS(imp)	(DBIc_TRACE_SETTINGS(imp) & DBIc_TRACE_FLAGS_MASK)
+/* DBIc_TRACE_MATCHES(this, crnt): true if this 'matches' (is within) crnt
+   DBIc_TRACE_MATCHES(foo, DBIc_TRACE_SETTINGS(imp))
+*/
+#define DBIc_TRACE_MATCHES(this, crnt)	\
+	(  ((crnt & DBIc_TRACE_LEVEL_MASK) >= (this & DBIc_TRACE_LEVEL_MASK)) \
+	|| ((crnt & DBIc_TRACE_FLAGS_MASK)  & (this & DBIc_TRACE_FLAGS_MASK)) )
+/* DBIc_TRACE: true if flags match & DBI level>=flaglevel, or if DBI level>level
+   This is the main trace testing macro to be used by drivers.
+   (Drivers should define their own DBDtf_* macros for the top 8 bits: 0xFF000000)
+   DBIc_TRACE(imp,         0, 0, 4) = if level >= 4
+   DBIc_TRACE(imp, DBDtf_FOO, 2, 4) = if tracing DBDtf_FOO & level>=2 or level>=4
+   DBIc_TRACE(imp, DBDtf_FOO, 2, 0) = as above but never trace just due to level
+*/
+#define DBIc_TRACE(imp, flags, flaglevel, level)	\
+	(  (flags && (DBIc_TRACE_FLAGS(imp) & flags) && (DBIc_TRACE_LEVEL(imp) >= flaglevel)) \
+	|| (level && DBIc_TRACE_LEVEL(imp) >= level) )
+
+#define DBIc_DEBUG(imp)		(_imp2com(imp, attr.TraceLevel)) /* deprecated */
+#define DBIc_DEBUGIV(imp)	SvIV(DBIc_DEBUG(imp))		 /* deprecated */
+#define DBIc_STATE(imp)		SvRV(_imp2com(imp, attr.State))
+#define DBIc_ERR(imp)		SvRV(_imp2com(imp, attr.Err))
+#define DBIc_ERRSTR(imp)	SvRV(_imp2com(imp, attr.Errstr))
+#define DBIc_ErrCount(imp)	_imp2com(imp, attr.ErrCount)
+#define DBIc_LongReadLen(imp)  	_imp2com(imp, attr.LongReadLen)
+#define DBIc_LongReadLen_init	80	/* may change */
+#define DBIc_FetchHashKeyName(imp) (_imp2com(imp, attr.FetchHashKeyName))
+
+/* handle sub-type specific fields						*/
+/*	dbh	*/
+#define DBIc_CACHED_KIDS(imp)  	_imp2com(imp, cached_kids)
+/*	sth	*/
+#define DBIc_NUM_FIELDS(imp)  	_imp2com(imp, num_fields)
+#define DBIc_NUM_PARAMS(imp)  	_imp2com(imp, num_params)
+#define DBIc_NUM_PARAMS_AT_EXECUTE	-9 /* see Driver.xst */
+#define DBIc_ROW_COUNT(imp)  	_imp2com(imp, row_count)
+#define DBIc_FIELDS_AV(imp)  	_imp2com(imp, fields_svav)
+#define DBIc_FDESC_AV(imp)  	_imp2com(imp, fields_fdav)
+#define DBIc_FDESC(imp, i)  	((imp_fdh_t*)(void*)SvPVX(AvARRAY(DBIc_FDESC_AV(imp))[i]))
+
+/* XXX --- DO NOT CHANGE THESE VALUES AS THEY ARE COMPILED INTO DRIVERS --- XXX */
+#define DBIcf_COMSET	  0x000001	/* needs to be clear'd before free'd	*/
+#define DBIcf_IMPSET	  0x000002	/* has implementor data to be clear'd	*/
+#define DBIcf_ACTIVE	  0x000004	/* needs finish/disconnect before clear	*/
+#define DBIcf_IADESTROY	  0x000008	/* do DBIc_ACTIVE_off before DESTROY	*/
+#define DBIcf_WARN  	  0x000010	/* warn about poor practice etc  	*/
+#define DBIcf_COMPAT  	  0x000020	/* compat/emulation mode (eg oraperl)	*/
+#define DBIcf_ChopBlanks  0x000040	/* rtrim spaces from fetch char columns	*/
+#define DBIcf_RaiseError  0x000080	/* throw exception (croak) on error	*/
+#define DBIcf_PrintError  0x000100	/* warn() on error			*/
+#define DBIcf_AutoCommit  0x000200	/* dbh only. used by drivers		*/
+#define DBIcf_LongTruncOk 0x000400	/* truncation to LongReadLen is okay	*/
+#define DBIcf_MultiThread 0x000800	/* allow multiple threads to enter	*/
+#define DBIcf_HandleSetErr 0x001000	/* has coderef HandleSetErr attribute	*/
+#define DBIcf_ShowErrorStatement  0x002000   /* include Statement in error	*/
+#define DBIcf_BegunWork   0x004000	/* between begin_work & commit/rollback */
+#define DBIcf_HandleError 0x008000	/* has coderef in HandleError attribute */
+#define DBIcf_Profile     0x010000	/* profile activity on this handle      */
+#define DBIcf_TaintIn     0x020000	/* check inputs for taintedness */
+#define DBIcf_TaintOut    0x040000	/* taint outgoing data */
+#define DBIcf_Executed    0x080000	/* do/execute called since commit/rollb */
+#define DBIcf_PrintWarn   0x100000	/* warn() on warning (err="0")		*/
+/* NOTE: new flags may require clone() to be updated */
+
+#define DBIcf_INHERITMASK		/* what NOT to pass on to children */	\
+  (U32)( DBIcf_COMSET | DBIcf_IMPSET | DBIcf_ACTIVE | DBIcf_IADESTROY		\
+  | DBIcf_AutoCommit | DBIcf_BegunWork | DBIcf_Executed )
+
+/* general purpose bit setting and testing macros			*/
+#define DBIbf_is( bitset,flag)		((bitset) &   (flag))
+#define DBIbf_has(bitset,flag)		DBIbf_is(bitset, flag) /* alias for _is */
+#define DBIbf_on( bitset,flag)		((bitset) |=  (flag))
+#define DBIbf_off(bitset,flag)		((bitset) &= ~(flag))
+#define DBIbf_set(bitset,flag,on)	((on) ? DBIbf_on(bitset, flag) : DBIbf_off(bitset,flag))
+
+/* as above, but specifically for DBIc_FLAGS imp flags (except ACTIVE)	*/
+#define DBIc_is(imp, flag)	DBIbf_is( DBIc_FLAGS(imp), flag)
+#define DBIc_has(imp,flag)	DBIc_is(imp, flag) /* alias for DBIc_is */
+#define DBIc_on(imp, flag)	DBIbf_on( DBIc_FLAGS(imp), flag)
+#define DBIc_off(imp,flag)	DBIbf_off(DBIc_FLAGS(imp), flag)
+#define DBIc_set(imp,flag,on)	DBIbf_set(DBIc_FLAGS(imp), flag, on)
+
+#define DBIc_COMSET(imp)	DBIc_is(imp, DBIcf_COMSET)
+#define DBIc_COMSET_on(imp)	DBIc_on(imp, DBIcf_COMSET)
+#define DBIc_COMSET_off(imp)	DBIc_off(imp,DBIcf_COMSET)
+
+#define DBIc_IMPSET(imp)	DBIc_is(imp, DBIcf_IMPSET)
+#define DBIc_IMPSET_on(imp)	DBIc_on(imp, DBIcf_IMPSET)
+#define DBIc_IMPSET_off(imp)	DBIc_off(imp,DBIcf_IMPSET)
+
+#define DBIc_ACTIVE(imp)	(DBIc_FLAGS(imp) &   DBIcf_ACTIVE)
+#define DBIc_ACTIVE_on(imp)	/* adjust parent's active kid count */	\
+    do {								\
+	imp_xxh_t *ph_com = DBIc_PARENT_COM(imp);			\
+	if (!DBIc_ACTIVE(imp) && ph_com && !dirty			\
+		&& ++DBIc_ACTIVE_KIDS(ph_com) > DBIc_KIDS(ph_com))	\
+	    croak("panic: DBI active kids (%d) > kids (%d)",		\
+		DBIc_ACTIVE_KIDS(ph_com), DBIc_KIDS(ph_com));		\
+	DBIc_FLAGS(imp) |=  DBIcf_ACTIVE;				\
+    } while(0)
+#define DBIc_ACTIVE_off(imp)	/* adjust parent's active kid count */	\
+    do {								\
+	imp_xxh_t *ph_com = DBIc_PARENT_COM(imp);			\
+	if (DBIc_ACTIVE(imp) && ph_com && !dirty			\
+		&& (--DBIc_ACTIVE_KIDS(ph_com) > DBIc_KIDS(ph_com)	\
+		   || DBIc_ACTIVE_KIDS(ph_com) < 0) )			\
+	    croak("panic: DBI active kids (%d) < 0 or > kids (%d)",	\
+		DBIc_ACTIVE_KIDS(ph_com), DBIc_KIDS(ph_com));		\
+	DBIc_FLAGS(imp) &= ~DBIcf_ACTIVE;				\
+    } while(0)
+
+#define DBIc_IADESTROY(imp)	(DBIc_FLAGS(imp) &   DBIcf_IADESTROY)
+#define DBIc_IADESTROY_on(imp)	(DBIc_FLAGS(imp) |=  DBIcf_IADESTROY)
+#define DBIc_IADESTROY_off(imp)	(DBIc_FLAGS(imp) &= ~DBIcf_IADESTROY)
+
+#define DBIc_WARN(imp)   	(DBIc_FLAGS(imp) &   DBIcf_WARN)
+#define DBIc_WARN_on(imp)	(DBIc_FLAGS(imp) |=  DBIcf_WARN)
+#define DBIc_WARN_off(imp)	(DBIc_FLAGS(imp) &= ~DBIcf_WARN)
+
+#define DBIc_COMPAT(imp)   	(DBIc_FLAGS(imp) &   DBIcf_COMPAT)
+#define DBIc_COMPAT_on(imp)	(DBIc_FLAGS(imp) |=  DBIcf_COMPAT)
+#define DBIc_COMPAT_off(imp)	(DBIc_FLAGS(imp) &= ~DBIcf_COMPAT)
+
+
+#ifdef IN_DBI_XS		/* get Handle Common Data Structure	*/
+#define DBIh_COM(h)         	(dbih_getcom2(h, 0))
+#else
+#define DBIh_COM(h)         	(DBIS->getcom(h))
+#define neatsvpv(sv,len)       	(DBIS->neat_svpv(sv,len))
+#endif
+
+
+/* --- Implementors Private Data Support --- */
+
+#define D_impdata(name,type,h)	type *name = (type*)(DBIh_COM(h))
+#define D_imp_drh(h) D_impdata(imp_drh, imp_drh_t, h)
+#define D_imp_dbh(h) D_impdata(imp_dbh, imp_dbh_t, h)
+#define D_imp_sth(h) D_impdata(imp_sth, imp_sth_t, h)
+#define D_imp_xxh(h) D_impdata(imp_xxh, imp_xxh_t, h)
+
+#define D_imp_from_child(name,type,child)	\
+				type *name = (type*)(DBIc_PARENT_COM(child))
+#define D_imp_drh_from_dbh D_imp_from_child(imp_drh, imp_drh_t, imp_dbh)
+#define D_imp_dbh_from_sth D_imp_from_child(imp_dbh, imp_dbh_t, imp_sth)
+
+#define DBI_IMP_SIZE(n,s) sv_setiv(perl_get_sv((n), GV_ADDMULTI), (s)) /* XXX */
+
+
+
+/* --- Event Support (VERY LIABLE TO CHANGE) --- */
+
+#define DBIh_EVENTx(h,t,a1,a2)	/* deprecated XXX */ &PL_sv_no
+#define DBIh_EVENT0(h,t)	DBIh_EVENTx((h), (t), &PL_sv_undef, &PL_sv_undef)
+#define DBIh_EVENT1(h,t, a1)	DBIh_EVENTx((h), (t), (a1),         &PL_sv_undef)
+#define DBIh_EVENT2(h,t, a1,a2)	DBIh_EVENTx((h), (t), (a1),         (a2))
+
+#define ERROR_event	"ERROR"
+#define WARN_event	"WARN"
+#define MSG_event	"MESSAGE"
+#define DBEVENT_event	"DBEVENT"
+#define UNKNOWN_event	"UNKNOWN"
+
+#define DBIh_SET_ERR_SV(h,i, err, errstr, state, method) \
+	(DBIc_DBISTATE(i)->set_err_sv(h,i, err, errstr, state, method))
+#define DBIh_SET_ERR_CHAR(h,i, err_c, err_i, errstr, state, method) \
+	(DBIc_DBISTATE(i)->set_err_char(h,i, err_c, err_i, errstr, state, method))
+
+
+/* --- Handy Macros --- */
+
+#define DBIh_CLEAR_ERROR(imp_xxh) (void)( \
+	(void)SvOK_off(DBIc_ERR(imp_xxh)),    	\
+	(void)SvOK_off(DBIc_ERRSTR(imp_xxh)),	\
+	(void)SvOK_off(DBIc_STATE(imp_xxh))	\
+    )
+
+
+/* --- DBI State Structure --- */
+
+struct dbistate_st {
+
+#define DBISTATE_VERSION  94	/* Must change whenever dbistate_t does	*/
+
+    /* this must be the first member in structure			*/
+    void (*check_version) _((char *name,
+		int dbis_cv, int dbis_cs, int need_dbixs_cv,
+		int drc_s, int dbc_s, int stc_s, int fdc_s));
+
+    /* version and size are used to check for DBI/DBD version mis-match	*/
+    U16 version;	/* version of this structure			*/
+    U16 size;
+    U16 xs_version;	/* version of the overall DBIXS / DBD interface	*/
+    U16 spare_pad;
+
+    I32 debug;
+    PerlIO *logfp;
+
+    /* pointers to DBI functions which the DBD's will want to use	*/
+    char      * (*neat_svpv)	_((SV *sv, STRLEN maxlen));
+    imp_xxh_t * (*getcom)	_((SV *h));	/* see DBIh_COM macro	*/
+    void        (*clearcom)	_((imp_xxh_t *imp_xxh));
+    SV        * (*event)	_((SV *h, char *name, SV*, SV*));
+    int         (*set_attr_k)	_((SV *h, SV *keysv, int dbikey, SV *valuesv));
+    SV        * (*get_attr_k)	_((SV *h, SV *keysv, int dbikey));
+    AV        * (*get_fbav)	_((imp_sth_t *imp_sth));
+    SV        * (*make_fdsv)	_((SV *sth, char *imp_class, STRLEN imp_size, char *col_name));
+    int         (*bind_as_num)	_((int sql_type, int p, int s, int *t, void *v));
+    int         (*hash)		_((char *string, long i));
+    SV        * (*preparse)	_((SV *sth, char *statement, IV ps_return, IV ps_accept, void *foo));
+
+    SV *neatsvpvlen;		/* only show dbgpvlen chars when debugging pv's	*/
+
+    PerlInterpreter * thr_owner;	/* thread that owns this dbistate	*/
+
+    int         (*logmsg)	_((imp_xxh_t *imp_xxh, char *fmt, ...));
+    int         (*set_err_sv)	_((SV *h, imp_xxh_t *imp_xxh, SV   *err, SV   *errstr, SV   *state, SV   *method));
+    int         (*set_err_char) _((SV *h, imp_xxh_t *imp_xxh, char *err, IV err_i, char *errstr, char *state, char *method));
+    int         (*bind_col)     _((SV *sth, SV *col, SV *ref, SV *attribs));
+
+    void *pad2[5];
+};
+
+/* macros for backwards compatibility */
+#define set_attr(h, k, v)	set_attr_k(h, k, 0, v)
+#define get_attr(h, k)		get_attr_k(h, k, 0)
+
+#define DBISTATE_PERLNAME "DBI::_dbistate"
+#define DBISTATE_ADDRSV   (perl_get_sv(DBISTATE_PERLNAME, 0x05))
+#define DBILOGFP	(DBIS->logfp)
+#ifdef IN_DBI_XS
+#define DBILOGMSG	(dbih_logmsg)
+#else
+#define DBILOGMSG	(DBIS->logmsg)
+#endif
+
+
+/* --- perl object (ActiveState) / multiplicity hooks and hoops --- */
+/* note that USE_ITHREADS implies MULTIPLICITY                      */
+#if defined(MULTIPLICITY) || defined(PERL_OBJECT) || defined(PERL_CAPI)
+
+# define DBISTATE_DECLARE typedef int dummy_dbistate /* keep semicolon from feeling lonely */
+# define DBISTATE_ASSIGN(st)
+# define DBISTATE_INIT
+# undef DBIS
+# define DBIS (*(INT2PTR(dbistate_t**, &SvIVX(DBISTATE_ADDRSV))))
+/* 'dbis' is temp for bad drivers using 'dbis' instead of 'DBIS' */
+# define dbis (*(INT2PTR(dbistate_t**, &SvIVX(DBISTATE_ADDRSV))))
+
+#else	/* plain and simple non perl object / multiplicity case */
+
+# define DBISTATE_DECLARE	static dbistate_t *DBIS
+# define DBISTATE_ASSIGN(st)	(DBIS = (st))
+# define DBISTATE_INIT_DBIS	DBISTATE_ASSIGN(INT2PTR(dbistate_t*, SvIV(DBISTATE_ADDRSV)))
+# define DBISTATE_INIT {	/* typically use in BOOT: of XS file	*/    \
+    DBISTATE_INIT_DBIS;	\
+    if (DBIS == NULL)	\
+	croak("Unable to get DBI state from %s at %p. DBI not loaded.", DBISTATE_PERLNAME, DBISTATE_ADDRSV); \
+    DBIS->check_version(__FILE__, DBISTATE_VERSION, sizeof(*DBIS), NEED_DBIXS_VERSION, \
+		sizeof(dbih_drc_t), sizeof(dbih_dbc_t), sizeof(dbih_stc_t), sizeof(dbih_fdc_t) \
+    ); \
+}
+#endif
+
+
+/* --- Assorted Utility Macros	--- */
+
+#define DBD_ATTRIB_OK(attribs)	/* is this a usable attrib value */	\
+	(attribs && SvROK(attribs) && SvTYPE(SvRV(attribs))==SVt_PVHV)
+
+/* If attribs value supplied then croak if it's not a hash ref.		*/
+/* Also map undef to Null. Should always be called to pre-process the	*/
+/* attribs value. One day we may add some extra magic in here.		*/
+#define DBD_ATTRIBS_CHECK(func, h, attribs)	\
+    if ((attribs) && SvOK(attribs)) {		\
+	STRLEN lna1=0, lna2=0;			\
+	if (!SvROK(attribs) || SvTYPE(SvRV(attribs))!=SVt_PVHV)		\
+	    croak("%s->%s(...): attribute parameter '%s' is not a hash ref",	\
+		    SvPV(h,lna1), func, SvPV(attribs,lna2));		\
+    } else (attribs) = Nullsv
+
+#define DBD_ATTRIB_GET_SVP(attribs, key,klen)			\
+	(DBD_ATTRIB_OK(attribs)					\
+	    ? hv_fetch((HV*)SvRV(attribs), key,klen, 0)		\
+	    : (SV **)Nullsv)
+	
+#define DBD_ATTRIB_GET_IV(attribs, key,klen, svp, var)			\
+	if ((svp=DBD_ATTRIB_GET_SVP(attribs, key,klen)) != NULL)	\
+	    var = SvIV(*svp)
+
+#define DBD_ATTRIB_GET_BOOL(attribs, key,klen, svp, var)		\
+	if ((svp=DBD_ATTRIB_GET_SVP(attribs, key,klen)) != NULL)	\
+	    var = SvTRUE(*svp)
+
+#define DBD_ATTRIB_TRUE(attribs, key,klen, svp)				\
+	(  ((svp=DBD_ATTRIB_GET_SVP(attribs, key,klen)) != NULL)	\
+	    ? SvTRUE(*svp) : 0 )
+
+#define DBD_ATTRIB_GET_PV(attribs, key,klen, svp, dflt)			\
+	(((svp=DBD_ATTRIB_GET_SVP(attribs, key,klen)) != NULL)		\
+	    ? SvPV_nolen(*svp) : (dflt))
+
+#define DBD_ATTRIB_DELETE(attribs, key, klen)			\
+	hv_delete((HV*)attribs, key, klen, G_DISCARD)
+
+#endif /* DBIXS_VERSION */
+/* end of DBIXS.h */
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/DBI/Driver.xst
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/DBI/Driver.xst	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/DBI/Driver.xst	(revision 14139)
@@ -0,0 +1,729 @@
+#  $Id$
+#  Copyright (c) 1997-2002  Tim Bunce  Ireland
+#  Copyright (c) 2002       Jonathan Leffler
+#
+#  You may distribute under the terms of either the GNU General Public
+#  License or the Artistic License, as specified in the Perl README file.
+
+
+#include "Driver_xst.h"
+
+
+MODULE = DBD::~DRIVER~	PACKAGE = DBD::~DRIVER~
+
+REQUIRE:    1.929
+PROTOTYPES: DISABLE
+
+BOOT:
+    items = 0;  /* avoid 'unused variable' warning */
+    DBISTATE_INIT;
+    /* XXX this interface will change: */
+    DBI_IMP_SIZE("DBD::~DRIVER~::dr::imp_data_size", sizeof(imp_drh_t));
+    DBI_IMP_SIZE("DBD::~DRIVER~::db::imp_data_size", sizeof(imp_dbh_t));
+    DBI_IMP_SIZE("DBD::~DRIVER~::st::imp_data_size", sizeof(imp_sth_t));
+    dbd_init(DBIS);
+
+
+# ------------------------------------------------------------
+# driver level interface
+# ------------------------------------------------------------
+MODULE = DBD::~DRIVER~	PACKAGE = DBD::~DRIVER~::dr
+
+
+#ifdef dbd_discon_all
+
+# disconnect_all renamed and ALIAS'd to avoid length clash on VMS :-(
+void
+discon_all_(drh)
+    SV *	drh
+    ALIAS:
+	disconnect_all = 1
+    CODE:
+    D_imp_drh(drh);
+    if (0) ix = ix;	/* avoid unused variable warning */
+    ST(0) = dbd_discon_all(drh, imp_drh) ? &sv_yes : &sv_no;
+
+#endif /* dbd_discon_all */
+
+
+#ifdef dbd_dr_data_sources
+
+void
+data_sources(drh, attr = Nullsv)
+    SV *drh
+    SV *attr
+    PPCODE:
+    {
+	D_imp_drh(drh);
+	AV *av = dbd_dr_data_sources(drh, imp_drh, attr);
+	if (av) {
+	    int i;
+	    int n = AvFILL(av)+1;
+	    EXTEND(sp, n);
+	    for (i = 0; i < n; ++i) {
+		PUSHs(AvARRAY(av)[i]);
+	    }
+	}
+    }
+
+#endif
+
+
+# ------------------------------------------------------------
+# database level interface
+# ------------------------------------------------------------
+MODULE = DBD::~DRIVER~    PACKAGE = DBD::~DRIVER~::db
+
+
+void
+_login(dbh, dbname, username, password, attribs=Nullsv)
+    SV *	dbh
+    char *	dbname
+    SV *	username
+    SV *	password
+    SV *	attribs
+    CODE:
+    {
+    STRLEN lna;
+    D_imp_dbh(dbh);
+    char *u = (SvOK(username)) ? SvPV(username,lna) : "";
+    char *p = (SvOK(password)) ? SvPV(password,lna) : "";
+#ifdef dbd_db_login6
+    ST(0) = dbd_db_login6(dbh, imp_dbh, dbname, u, p, attribs) ? &sv_yes : &sv_no;
+#else
+    ST(0) = dbd_db_login( dbh, imp_dbh, dbname, u, p) ? &sv_yes : &sv_no;
+#endif
+    }
+
+
+void
+selectall_arrayref(...)
+    PREINIT:
+    SV *sth;
+    SV **maxrows_svp;
+    SV **tmp_svp;
+    SV *attr = &PL_sv_undef;
+    imp_sth_t *imp_sth;
+    CODE:
+    if (items > 2) {
+	attr = ST(2);
+	if (SvROK(attr) &&
+		(DBD_ATTRIB_TRUE(attr,"Slice",5,tmp_svp) || DBD_ATTRIB_TRUE(attr,"Columns",7,tmp_svp))
+	) {
+	    /* fallback to perl implementation */
+	    ST(0) = dbixst_bounce_method("DBD::~DRIVER~::db::SUPER::selectall_arrayref", items);
+	    XSRETURN(1);
+	}
+    }
+    /* --- prepare --- */
+    if (SvROK(ST(1))) {
+	sth = ST(1);
+    }
+    else {
+	sth = dbixst_bounce_method("prepare", 3);
+	if (!SvROK(sth))
+	    XSRETURN_UNDEF;
+    }
+    imp_sth = (imp_sth_t*)(DBIh_COM(sth));
+    /* --- bind_param --- */
+    if (items > 3) {    /* need to bind params before execute */
+        if (!dbdxst_bind_params(sth, imp_sth, items-2, ax+2) ) {
+            XSRETURN_UNDEF;
+        }
+    }
+    /* --- execute --- */
+    DBIc_ROW_COUNT(imp_sth) = 0;
+    if ( dbd_st_execute(sth, imp_sth) <= -2 ) { /* -2 == error */
+        XSRETURN_UNDEF;
+    }
+    /* --- fetchall --- */
+    maxrows_svp = DBD_ATTRIB_GET_SVP(attr, "MaxRows", 7);
+    ST(0) = dbdxst_fetchall_arrayref(sth, &PL_sv_undef, (maxrows_svp) ? *maxrows_svp : &PL_sv_undef);
+
+
+void
+selectrow_arrayref(...)
+    ALIAS:
+	selectrow_array = 1
+    PREINIT:
+    imp_sth_t *imp_sth;
+    SV *sth;
+    AV *row_av;
+    PPCODE:
+    if (SvROK(ST(1))) {
+	sth = ST(1);
+    }
+    else {
+	/* --- prepare --- */
+	sth = dbixst_bounce_method("prepare", 3);
+	if (!SvROK(sth))
+	    XSRETURN_UNDEF;
+    }
+    imp_sth = (imp_sth_t*)(DBIh_COM(sth));
+    /* --- bind_param --- */
+    if (items > 3) {	/* need to bind params before execute */
+	if (!dbdxst_bind_params(sth, imp_sth, items-2, ax+2) ) {
+	    XSRETURN_UNDEF;
+	}
+    }
+    /* --- execute --- */
+    DBIc_ROW_COUNT(imp_sth) = 0;
+    if ( dbd_st_execute(sth, imp_sth) <= -2 ) {	/* -2 == error */
+        XSRETURN_UNDEF;
+    }
+    /* --- fetchrow_arrayref --- */
+    row_av = dbd_st_fetch(sth, imp_sth);
+    if (!row_av) {
+	if (GIMME == G_SCALAR)
+	    PUSHs(&PL_sv_undef);
+    }
+    else if (ix == 1) { /* selectrow_array */
+	int i;
+	int num_fields = AvFILL(row_av)+1;
+	if (GIMME == G_SCALAR)
+	    num_fields = 1; /* return just first field */
+	EXTEND(sp, num_fields);
+	for(i=0; i < num_fields; ++i) {
+	    PUSHs(AvARRAY(row_av)[i]);
+	}
+    }
+    else {
+	PUSHs( sv_2mortal(newRV((SV *)row_av)) );
+    }
+    /* --- finish --- */
+#ifdef dbd_st_finish3
+    dbd_st_finish3(sth, imp_sth, 0);
+#else
+    dbd_st_finish(sth, imp_sth);
+#endif
+
+
+#ifdef dbd_db_do4 /* deebeedee-deebee-doo, deebee-doobee-dah? */
+
+void
+do(dbh, statement, params = Nullsv)
+    SV *	dbh
+    char *	statement
+    SV *	params
+    CODE:
+    {
+    D_imp_dbh(dbh);
+    IV retval;
+    retval = dbd_db_do4(dbh, imp_dbh, statement, params);
+    /* remember that dbd_db_do4 must return <= -2 for error	*/
+    if (retval == 0)		/* ok with no rows affected	*/
+	XST_mPV(0, "0E0");	/* (true but zero)		*/
+    else if (retval < -1)	/* -1 == unknown number of rows	*/
+	XST_mUNDEF(0);		/* <= -2 means error   		*/
+    else
+	XST_mIV(0, retval);	/* typically 1, rowcount or -1	*/
+    }
+
+#endif
+
+
+#ifdef dbd_db_last_insert_id
+
+void
+last_insert_id(dbh, catalog, schema, table, field, attr=Nullsv)
+    SV *	dbh
+    SV *	catalog
+    SV *	schema
+    SV *	table
+    SV *	field
+    SV *	attr
+    CODE:
+    {
+    D_imp_dbh(dbh);
+    ST(0) = dbd_db_last_insert_id(dbh, imp_dbh, catalog, schema, table, field, attr);
+    }
+
+#endif
+
+
+void
+commit(dbh)
+    SV *	dbh
+    CODE:
+    D_imp_dbh(dbh);
+    if (DBIc_has(imp_dbh,DBIcf_AutoCommit) && DBIc_WARN(imp_dbh))
+	warn("commit ineffective with AutoCommit enabled");
+    ST(0) = dbd_db_commit(dbh, imp_dbh) ? &sv_yes : &sv_no;
+
+
+void
+rollback(dbh)
+    SV *	dbh
+    CODE:
+    D_imp_dbh(dbh);
+    if (DBIc_has(imp_dbh,DBIcf_AutoCommit) && DBIc_WARN(imp_dbh))
+	warn("rollback ineffective with AutoCommit enabled");
+    ST(0) = dbd_db_rollback(dbh, imp_dbh) ? &sv_yes : &sv_no;
+
+
+void
+disconnect(dbh)
+    SV *	dbh
+    CODE:
+    D_imp_dbh(dbh);
+    if ( !DBIc_ACTIVE(imp_dbh) ) {
+	XSRETURN_YES;
+    }
+    /* pre-disconnect checks and tidy-ups */
+    if (DBIc_CACHED_KIDS(imp_dbh)) {
+	SvREFCNT_dec(DBIc_CACHED_KIDS(imp_dbh));      /* cast them to the winds	*/
+	DBIc_CACHED_KIDS(imp_dbh) = Nullhv;
+    }
+    /* Check for disconnect() being called whilst refs to cursors	*/
+    /* still exists. This possibly needs some more thought.		*/
+    if (DBIc_ACTIVE_KIDS(imp_dbh) && DBIc_WARN(imp_dbh) && !dirty) {
+	STRLEN lna;
+	char *plural = (DBIc_ACTIVE_KIDS(imp_dbh)==1) ? "" : "s";
+	warn("%s->disconnect invalidates %d active statement handle%s %s",
+	    SvPV(dbh,lna), (int)DBIc_ACTIVE_KIDS(imp_dbh), plural,
+	    "(either destroy statement handles or call finish on them before disconnecting)");
+    }
+    ST(0) = dbd_db_disconnect(dbh, imp_dbh) ? &sv_yes : &sv_no;
+    DBIc_ACTIVE_off(imp_dbh);	/* ensure it's off, regardless */
+
+
+void
+STORE(dbh, keysv, valuesv)
+    SV *	dbh
+    SV *	keysv
+    SV *	valuesv
+    CODE:
+    D_imp_dbh(dbh);
+    if (SvGMAGICAL(valuesv))
+	mg_get(valuesv);
+    ST(0) = &sv_yes;
+    if (!dbd_db_STORE_attrib(dbh, imp_dbh, keysv, valuesv))
+	if (!DBIc_DBISTATE(imp_dbh)->set_attr(dbh, keysv, valuesv))
+	    ST(0) = &sv_no;
+
+
+void
+FETCH(dbh, keysv)
+    SV *	dbh
+    SV *	keysv
+    CODE:
+    D_imp_dbh(dbh);
+    SV *valuesv = dbd_db_FETCH_attrib(dbh, imp_dbh, keysv);
+    if (!valuesv)
+	valuesv = DBIc_DBISTATE(imp_dbh)->get_attr(dbh, keysv);
+    ST(0) = valuesv;	/* dbd_db_FETCH_attrib did sv_2mortal	*/
+
+
+void
+DESTROY(dbh)
+    SV *	dbh
+    PPCODE:
+    D_imp_dbh(dbh);
+    ST(0) = &sv_yes;
+    if (!DBIc_IMPSET(imp_dbh)) {	/* was never fully set up	*/
+	STRLEN lna;
+	if (DBIc_WARN(imp_dbh) && !dirty && DBIc_DBISTATE(imp_dbh)->debug >= 2)
+	     PerlIO_printf(DBIc_LOGPIO(imp_dbh),
+		"         DESTROY for %s ignored - handle not initialised\n",
+		    SvPV(dbh,lna));
+    }
+    else {
+	/* pre-disconnect checks and tidy-ups */
+	if (DBIc_CACHED_KIDS(imp_dbh)) {
+	    SvREFCNT_dec(DBIc_CACHED_KIDS(imp_dbh));  /* cast them to the winds	*/
+	    DBIc_CACHED_KIDS(imp_dbh) = Nullhv;
+	}
+        if (DBIc_IADESTROY(imp_dbh)) {		  /* want's ineffective destroy	*/
+            DBIc_ACTIVE_off(imp_dbh);
+        }
+	if (DBIc_ACTIVE(imp_dbh)) {
+	    /* The application has not explicitly disconnected. That's bad.	*/
+	    /* To ensure integrity we *must* issue a rollback. This will be	*/
+	    /* harmless	if the application has issued a commit. If it hasn't	*/
+	    /* then it'll ensure integrity. Consider a Ctrl-C killing perl	*/
+	    /* between two statements that must be executed as a transaction.	*/
+	    /* Perl will call DESTROY on the dbh and, if we don't rollback,	*/
+	    /* the server may automatically commit! Bham! Corrupt database!	*/
+	    if (!DBIc_has(imp_dbh,DBIcf_AutoCommit)) {
+		if (DBIc_WARN(imp_dbh)
+		&&  DBIc_is(imp_dbh, DBIcf_Executed)
+		&& (!dirty || DBIc_DBISTATE(imp_dbh)->debug >= 3)
+		)
+		     warn("Issuing rollback() for database handle being DESTROY'd without explicit disconnect()");
+		dbd_db_rollback(dbh, imp_dbh);			/* ROLLBACK! */
+	    }
+	    dbd_db_disconnect(dbh, imp_dbh);
+	    DBIc_ACTIVE_off(imp_dbh);	/* ensure it's off, regardless */
+	}
+	dbd_db_destroy(dbh, imp_dbh);
+    }
+
+
+#ifdef dbd_take_imp_data
+
+void
+take_imp_data(h)
+    SV * h
+    CODE:
+    D_imp_xxh(h);
+    ST(0) = (dbd_take_imp_data(h, imp_xxh, NULL))
+	? dbixst_bounce_method("DBD::~DRIVER~::db::SUPER::take_imp_data", items)
+	: &sv_undef;
+
+#endif
+
+#ifdef dbd_db_data_sources
+
+void
+data_sources(dbh, attr = Nullsv)
+    SV *dbh
+    SV *attr
+    PPCODE:
+    {
+	D_imp_dbh(dbh);
+	AV *av = dbd_db_data_sources(dbh, imp_dbh, attr);
+	if (av) {
+	    int i;
+	    int n = AvFILL(av)+1;
+	    EXTEND(sp, n);
+	    for (i = 0; i < n; ++i) {
+		PUSHs(AvARRAY(av)[i]);
+	    }
+	}
+    }
+
+#endif
+
+# -- end of DBD::~DRIVER~::db
+
+# ------------------------------------------------------------
+# statement interface
+# ------------------------------------------------------------
+MODULE = DBD::~DRIVER~    PACKAGE = DBD::~DRIVER~::st
+
+
+void
+_prepare(sth, statement, attribs=Nullsv)
+    SV *	sth
+    char *	statement
+    SV *	attribs
+    CODE:
+    {
+    D_imp_sth(sth);
+    DBD_ATTRIBS_CHECK("_prepare", sth, attribs);
+    ST(0) = dbd_st_prepare(sth, imp_sth, statement, attribs) ? &sv_yes : &sv_no;
+    }
+
+
+#ifdef dbd_st_rows
+
+void
+rows(sth)
+    SV *	sth
+    CODE:
+    D_imp_sth(sth);
+    XST_mIV(0, dbd_st_rows(sth, imp_sth));
+
+#endif /* dbd_st_rows */
+
+
+#ifdef dbd_st_bind_col
+
+void
+bind_col(sth, col, ref, attribs=Nullsv)
+    SV *	sth
+    SV *	col
+    SV *	ref
+    SV *	attribs
+    CODE:
+    {
+    IV sql_type = 0;
+    D_imp_sth(sth);
+    if (SvGMAGICAL(ref))
+	mg_get(ref);
+    if (attribs) {
+	if (SvNIOK(attribs)) {
+	    sql_type = SvIV(attribs);
+	    attribs = Nullsv;
+	}
+	else {
+	    SV **svp;
+	    DBD_ATTRIBS_CHECK("bind_col", sth, attribs);
+	    /* XXX we should perhaps complain if TYPE is not SvNIOK */
+	    DBD_ATTRIB_GET_IV(attribs, "TYPE",4, svp, sql_type);
+	}
+    }
+    switch(dbd_st_bind_col(sth, imp_sth, col, ref, sql_type, attribs)) {
+    case 2:	ST(0) = &sv_yes;	/* job done completely */
+		break;
+    case 1:	/* fallback to DBI default */
+		ST(0) = (DBIc_DBISTATE(imp_sth)->bind_col(sth, col, ref, attribs))
+		    ? &sv_yes : &sv_no;
+		break;
+    default:	ST(0) = &sv_no;		/* dbd_st_bind_col has called set_err */
+		break;
+    }
+    }
+
+#endif /* dbd_st_bind_col */
+
+void
+bind_param(sth, param, value, attribs=Nullsv)
+    SV *	sth
+    SV *	param
+    SV *	value
+    SV *	attribs
+    CODE:
+    {
+    IV sql_type = 0;
+    D_imp_sth(sth);
+    if (SvGMAGICAL(value))
+	mg_get(value);
+    if (attribs) {
+	if (SvNIOK(attribs)) {
+	    sql_type = SvIV(attribs);
+	    attribs = Nullsv;
+	}
+	else {
+	    SV **svp;
+	    DBD_ATTRIBS_CHECK("bind_param", sth, attribs);
+	    /* XXX we should perhaps complain if TYPE is not SvNIOK */
+	    DBD_ATTRIB_GET_IV(attribs, "TYPE",4, svp, sql_type);
+	}
+    }
+    ST(0) = dbd_bind_ph(sth, imp_sth, param, value, sql_type, attribs, FALSE, 0)
+		? &sv_yes : &sv_no;
+    }
+
+
+void
+bind_param_inout(sth, param, value_ref, maxlen, attribs=Nullsv)
+    SV *	sth
+    SV *	param
+    SV *	value_ref
+    IV 		maxlen
+    SV *	attribs
+    CODE:
+    {
+    IV sql_type = 0;
+    D_imp_sth(sth);
+    SV *value;
+    if (!SvROK(value_ref) || SvTYPE(SvRV(value_ref)) > SVt_PVMG)
+	croak("bind_param_inout needs a reference to a scalar value");
+    value = SvRV(value_ref);
+    if (SvREADONLY(value))
+	croak("Modification of a read-only value attempted");
+    if (SvGMAGICAL(value))
+	mg_get(value);
+    if (attribs) {
+	if (SvNIOK(attribs)) {
+	    sql_type = SvIV(attribs);
+	    attribs = Nullsv;
+	}
+	else {
+	    SV **svp;
+	    DBD_ATTRIBS_CHECK("bind_param", sth, attribs);
+	    DBD_ATTRIB_GET_IV(attribs, "TYPE",4, svp, sql_type);
+	}
+    }
+    ST(0) = dbd_bind_ph(sth, imp_sth, param, value, sql_type, attribs, TRUE, maxlen)
+		? &sv_yes : &sv_no;
+    }
+
+
+void
+execute(sth, ...)
+    SV *	sth
+    CODE:
+    D_imp_sth(sth);
+    int retval;
+    if (items > 1) {	/* need to bind params */
+	if (!dbdxst_bind_params(sth, imp_sth, items, ax) ) {
+	    XSRETURN_UNDEF;
+	}
+    }
+    /* XXX this code is duplicated in selectrow_arrayref above	*/
+    if (DBIc_ROW_COUNT(imp_sth) > 0) /* reset for re-execute */
+	DBIc_ROW_COUNT(imp_sth) = 0;
+    retval = dbd_st_execute(sth, imp_sth);
+    /* remember that dbd_st_execute must return <= -2 for error	*/
+    if (retval == 0)		/* ok with no rows affected	*/
+	XST_mPV(0, "0E0");	/* (true but zero)		*/
+    else if (retval < -1)	/* -1 == unknown number of rows	*/
+	XST_mUNDEF(0);		/* <= -2 means error   		*/
+    else
+	XST_mIV(0, retval);	/* typically 1, rowcount or -1	*/
+
+
+#ifdef dbd_st_execute_for_fetch
+
+void
+execute_for_fetch(sth, fetch_tuple_sub, tuple_status = Nullsv)
+    SV *	sth
+    SV *	fetch_tuple_sub
+    SV *	tuple_status
+    CODE:
+    {
+    D_imp_sth(sth);
+    ST(0) = dbd_st_execute_for_fetch(sth, imp_sth, fetch_tuple_sub, tuple_status);
+    }
+
+#endif
+
+
+
+void
+fetchrow_arrayref(sth)
+    SV *	sth
+    ALIAS:
+	fetch = 1
+    CODE:
+    D_imp_sth(sth);
+    AV *av;
+    if (0) ix = ix;	/* avoid unused variable warning */
+    av = dbd_st_fetch(sth, imp_sth);
+    ST(0) = (av) ? sv_2mortal(newRV((SV *)av)) : &PL_sv_undef;
+
+
+void
+fetchrow_array(sth)
+    SV *	sth
+    ALIAS:
+	fetchrow = 1
+    PPCODE:
+    D_imp_sth(sth);
+    AV *av;
+    av = dbd_st_fetch(sth, imp_sth);
+    if (av) {
+	int i;
+	int num_fields = AvFILL(av)+1;
+	EXTEND(sp, num_fields);
+	for(i=0; i < num_fields; ++i) {
+	    PUSHs(AvARRAY(av)[i]);
+	}
+	if (0) ix = ix;	/* avoid unused variable warning */
+    }
+
+
+void
+fetchall_arrayref(sth, slice=&PL_sv_undef, batch_row_count=&PL_sv_undef)
+    SV *	sth
+    SV *	slice
+    SV *	batch_row_count
+    CODE:
+    if (SvOK(slice)) {  /* fallback to perl implementation */
+        ST(0) = dbixst_bounce_method("DBD::~DRIVER~::st::SUPER::fetchall_arrayref", 3);
+    }
+    else {
+	ST(0) = dbdxst_fetchall_arrayref(sth, slice, batch_row_count);
+    }
+
+
+void
+finish(sth)
+    SV *	sth
+    CODE:
+    D_imp_sth(sth);
+    D_imp_dbh_from_sth;
+    if (!DBIc_ACTIVE(imp_sth)) {
+	/* No active statement to finish	*/
+	XSRETURN_YES;
+    }
+    if (!DBIc_ACTIVE(imp_dbh)) {
+	/* Either an explicit disconnect() or global destruction	*/
+	/* has disconnected us from the database. Finish is meaningless	*/
+	DBIc_ACTIVE_off(imp_sth);
+	XSRETURN_YES;
+    }
+#ifdef dbd_st_finish3
+    ST(0) = dbd_st_finish3(sth, imp_sth, 0) ? &sv_yes : &sv_no;
+#else
+    ST(0) = dbd_st_finish(sth, imp_sth) ? &sv_yes : &sv_no;
+#endif
+
+
+void
+blob_read(sth, field, offset, len, destrv=Nullsv, destoffset=0)
+    SV *        sth
+    int field
+    long        offset
+    long        len
+    SV *        destrv
+    long        destoffset
+    CODE:
+    {
+    D_imp_sth(sth);
+    if (!destrv)
+        destrv = sv_2mortal(newRV(sv_2mortal(newSV(0))));
+    if (dbd_st_blob_read(sth, imp_sth, field, offset, len, destrv, destoffset))
+         ST(0) = SvRV(destrv);
+    else ST(0) = &PL_sv_undef;
+    }
+
+
+void
+STORE(sth, keysv, valuesv)
+    SV *	sth
+    SV *	keysv
+    SV *	valuesv
+    CODE:
+    D_imp_sth(sth);
+    if (SvGMAGICAL(valuesv))
+	mg_get(valuesv);
+    ST(0) = &sv_yes;
+    if (!dbd_st_STORE_attrib(sth, imp_sth, keysv, valuesv))
+	if (!DBIc_DBISTATE(imp_sth)->set_attr(sth, keysv, valuesv))
+	    ST(0) = &sv_no;
+
+
+# FETCH renamed and ALIAS'd to avoid case clash on VMS :-(
+void
+FETCH_attrib(sth, keysv)
+    SV *	sth
+    SV *	keysv
+    ALIAS:
+    FETCH = 1
+    CODE:
+    D_imp_sth(sth);
+    SV *valuesv;
+    if (0) ix = ix;	/* avoid unused variable warning */
+    valuesv = dbd_st_FETCH_attrib(sth, imp_sth, keysv);
+    if (!valuesv)
+	valuesv = DBIc_DBISTATE(imp_sth)->get_attr(sth, keysv);
+    ST(0) = valuesv;	/* dbd_st_FETCH_attrib did sv_2mortal	*/
+
+
+void
+DESTROY(sth)
+    SV *	sth
+    PPCODE:
+    D_imp_sth(sth);
+    ST(0) = &sv_yes;
+    if (!DBIc_IMPSET(imp_sth)) {	/* was never fully set up	*/
+	STRLEN lna;
+	if (DBIc_WARN(imp_sth) && !dirty && DBIc_DBISTATE(imp_sth)->debug >= 2)
+	     PerlIO_printf(DBIc_LOGPIO(imp_sth),
+		"         DESTROY for %s ignored - handle not initialised\n",
+		    SvPV(sth,lna));
+    }
+    else {
+        if (DBIc_IADESTROY(imp_sth)) { /* want's ineffective destroy    */
+            DBIc_ACTIVE_off(imp_sth);
+        }
+	if (DBIc_ACTIVE(imp_sth)) {
+	    D_imp_dbh_from_sth;
+	    if (!dirty && DBIc_ACTIVE(imp_dbh)) {
+#ifdef dbd_st_finish3
+		dbd_st_finish3(sth, imp_sth, 1);
+#else
+		dbd_st_finish(sth, imp_sth);
+#endif
+	    }
+	    else {
+		DBIc_ACTIVE_off(imp_sth);
+	    }
+	}
+	dbd_st_destroy(sth, imp_sth);
+    }
+
+# end of ~DRIVER~.xst
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/DBI/Driver_xst.h
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/DBI/Driver_xst.h	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/DBI/Driver_xst.h	(revision 14139)
@@ -0,0 +1,108 @@
+/*
+#  $Id$
+#  Copyright (c) 2002  Tim Bunce  Ireland
+#
+#  You may distribute under the terms of either the GNU General Public
+#  License or the Artistic License, as specified in the Perl README file.
+*/
+
+static SV *
+dbixst_bounce_method(char *methname, int params)
+{
+    /* XXX this 'magic' undoes the dMARK embedded in the dXSARGS of our caller	*/
+    /* so that the dXSARGS below can set things up as they were for our caller	*/
+    void *xxx = PL_markstack_ptr++;
+    dXSARGS; /* declares sp, ax, mark, items */
+    int i;
+    SV *sv;
+    int debug = 0;
+    D_imp_xxh(ST(0));
+    if (debug >= 3) {
+	PerlIO_printf(DBIc_LOGPIO(imp_xxh),
+	    "    -> %s (trampoline call with %d (%ld) params)\n", methname, params, (long)items);
+	xxx = xxx; /* avoid unused var warning */
+    }
+    EXTEND(SP, params);
+    PUSHMARK(SP);
+    for (i=0; i < params; ++i) {
+	sv = (i >= items) ? &sv_undef : ST(i);
+        PUSHs(sv);
+    }
+    PUTBACK;
+    i = perl_call_method(methname, G_SCALAR);
+    SPAGAIN;
+    sv = (i) ? POPs : &sv_undef;
+    PUTBACK;
+    if (debug >= 3)
+	PerlIO_printf(DBIc_LOGPIO(imp_xxh),
+	    "    <- %s= %s (trampoline call return)\n", methname, neatsvpv(sv,0));
+    return sv;
+}
+
+
+static int
+dbdxst_bind_params(SV *sth, imp_sth_t *imp_sth, I32 items, I32 ax)
+{
+    /* Handle binding supplied values to placeholders.		*/
+    /* items = one greater than the number of params		*/
+    /* ax = ax from calling sub, maybe adjusted to match items	*/
+    int i;
+    SV *idx;
+    if (items-1 != DBIc_NUM_PARAMS(imp_sth)
+	&& DBIc_NUM_PARAMS(imp_sth) != DBIc_NUM_PARAMS_AT_EXECUTE
+    ) {
+	char errmsg[99];
+	sprintf(errmsg,"called with %d bind variables when %d are needed",
+		(int)items-1, DBIc_NUM_PARAMS(imp_sth));
+	sv_setpv(DBIc_ERRSTR(imp_sth), errmsg);
+	sv_setiv(DBIc_ERR(imp_sth), (IV)-1);
+	return 0;
+    }
+    idx = sv_2mortal(newSViv(0));
+    for(i=1; i < items ; ++i) {
+	SV* value = ST(i);
+	if (SvGMAGICAL(value))
+	    mg_get(value);	/* trigger magic to FETCH the value     */
+	sv_setiv(idx, i);
+	if (!dbd_bind_ph(sth, imp_sth, idx, value, 0, Nullsv, FALSE, 0)) {
+	    return 0;	/* dbd_bind_ph already registered error	*/
+	}
+    }
+    return 1;
+}
+
+#ifndef dbd_fetchall_arrayref
+static SV *
+dbdxst_fetchall_arrayref(SV *sth, SV *slice, SV *batch_row_count)
+{
+    D_imp_sth(sth);
+    SV *rows_rvav;
+    if (SvOK(slice)) {  /* should never get here */
+	char errmsg[99];
+	sprintf(errmsg,"slice param not supported by XS version of fetchall_arrayref");
+	sv_setpv(DBIc_ERRSTR(imp_sth), errmsg);
+	sv_setiv(DBIc_ERR(imp_sth), (IV)-1);
+	return &sv_undef;
+    }
+    else {
+	IV maxrows = SvOK(batch_row_count) ? SvIV(batch_row_count) : -1;
+	AV *fetched_av;
+	AV *rows_av = newAV();
+	if ( !DBIc_ACTIVE(imp_sth) && maxrows>0 ) {
+	    /* to simplify application logic we return undef without an error	*/
+	    /* if we've fetched all the rows and called with a batch_row_count	*/
+	    return &sv_undef;
+	}
+	av_extend(rows_av, (maxrows>0) ? maxrows : 31);
+	while ( (maxrows < 0 || maxrows-- > 0)
+	    && (fetched_av = dbd_st_fetch(sth, imp_sth))
+	) {
+	    AV *copy_row_av = av_make(AvFILL(fetched_av)+1, AvARRAY(fetched_av));
+	    av_push(rows_av, newRV_noinc((SV*)copy_row_av));
+	}
+	rows_rvav = sv_2mortal(newRV_noinc((SV *)rows_av));
+    }
+    return rows_rvav;
+}
+#endif
+
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/DBI/dbd_xsh.h
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/DBI/dbd_xsh.h	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/DBI/dbd_xsh.h	(revision 14139)
@@ -0,0 +1,56 @@
+/* @(#)$Id$
+ *
+ * Copyright 2000-2002 Tim Bunce
+ * Copyright 2002      Jonathan Leffler
+ *
+ * These prototypes are for dbdimp.c funcs used in the XS file.
+ * These names are #defined to driver specific names by the
+ * dbdimp.h file in the driver source.
+ */
+
+#ifndef DBI_DBD_XSH_H
+#define DBI_DBD_XSH_H
+
+void     dbd_init _((dbistate_t *dbistate));
+
+int      dbd_discon_all _((SV *drh, imp_drh_t *imp_drh));
+SV      *dbd_take_imp_data _((SV *h, imp_xxh_t *imp_xxh, void *foo));
+
+/* Support for dbd_dr_data_sources and dbd_db_do added to Driver.xst in DBI v1.33 */
+/* dbd_dr_data_sources: optional: defined by a driver that calls a C */
+/* function to get the list of data sources */
+AV	*dbd_dr_data_sources(SV *drh, imp_drh_t *imp_drh, SV *attrs);
+
+int      dbd_db_login6 _((SV *dbh, imp_dbh_t *imp_dbh, char *dbname, char *uid, char *pwd, SV*attribs));
+int      dbd_db_login  _((SV *dbh, imp_dbh_t *imp_dbh, char *dbname, char *uid, char *pwd)); /* deprecated */
+/* Note: interface of dbd_db_do changed in v1.33 */
+/* Old prototype: dbd_db_do _((SV *sv, char *statement)); */
+/* dbd_db_do: optional: defined by a driver if the DBI default version is too slow */
+int      dbd_db_do4 _((SV *dbh, imp_dbh_t *imp_dbh, char *statement, SV *params));
+int      dbd_db_commit     _((SV *dbh, imp_dbh_t *imp_dbh));
+int      dbd_db_rollback   _((SV *dbh, imp_dbh_t *imp_dbh));
+int      dbd_db_disconnect _((SV *dbh, imp_dbh_t *imp_dbh));
+void     dbd_db_destroy    _((SV *dbh, imp_dbh_t *imp_dbh));
+int      dbd_db_STORE_attrib _((SV *dbh, imp_dbh_t *imp_dbh, SV *keysv, SV *valuesv));
+SV      *dbd_db_FETCH_attrib _((SV *dbh, imp_dbh_t *imp_dbh, SV *keysv));
+SV	*dbd_db_last_insert_id _((SV *dbh, imp_dbh_t *imp_dbh, SV *catalog, SV *schema, SV *table, SV *field, SV *attr));
+AV      *dbd_db_data_sources _((SV *dbh, imp_dbh_t *imp_dbh, SV *attr));
+
+int      dbd_st_prepare _((SV *sth, imp_sth_t *imp_sth, char *statement, SV *attribs));
+int      dbd_st_rows    _((SV *sth, imp_sth_t *imp_sth));
+int      dbd_st_execute _((SV *sth, imp_sth_t *imp_sth));
+AV      *dbd_st_fetch   _((SV *sth, imp_sth_t *imp_sth));
+int      dbd_st_finish3 _((SV *sth, imp_sth_t *imp_sth, int from_destroy));
+int      dbd_st_finish  _((SV *sth, imp_sth_t *imp_sth)); /* deprecated */
+void     dbd_st_destroy _((SV *sth, imp_sth_t *imp_sth));
+int      dbd_st_blob_read _((SV *sth, imp_sth_t *imp_sth,
+                int field, long offset, long len, SV *destrv, long destoffset));
+int      dbd_st_STORE_attrib _((SV *sth, imp_sth_t *imp_sth, SV *keysv, SV *valuesv));
+SV      *dbd_st_FETCH_attrib _((SV *sth, imp_sth_t *imp_sth, SV *keysv));
+SV      *dbd_st_execute_for_fetch _((SV *sth, imp_sth_t *imp_sth, SV *fetch_tuple_sub, SV *tuple_status));
+
+int      dbd_bind_ph  _((SV *sth, imp_sth_t *imp_sth,
+                SV *param, SV *value, IV sql_type, SV *attribs,
+				int is_inout, IV maxlen));
+
+#endif /* end of dbd_xsh.h */
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/DBI/dbi_sql.h
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/DBI/dbi_sql.h	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/DBI/dbi_sql.h	(revision 14139)
@@ -0,0 +1,96 @@
+/* $Id$
+ *
+ * Copyright (c) 1997,1998,1999  Tim Bunce  England
+ *
+ * See COPYRIGHT section in DBI.pm for usage and distribution rights.
+ */
+
+
+/* Some core SQL CLI standard (ODBC) declarations		*/
+#ifndef SQL_SUCCESS	/* don't clash with ODBC based drivers	*/
+
+/* SQL datatype codes */
+#define SQL_GUID                         (-11)
+#define SQL_WLONGVARCHAR                 (-10)
+#define SQL_WVARCHAR                      (-9)
+#define SQL_WCHAR                         (-8)
+#define SQL_BIT                           (-7)
+#define SQL_TINYINT                       (-6)
+#define SQL_BIGINT                        (-5)
+#define SQL_LONGVARBINARY                 (-4)
+#define SQL_VARBINARY                     (-3)
+#define SQL_BINARY                        (-2)
+#define SQL_LONGVARCHAR                   (-1)
+#define SQL_UNKNOWN_TYPE                    0
+#define SQL_ALL_TYPES                       0
+#define SQL_CHAR                            1
+#define SQL_NUMERIC                         2
+#define SQL_DECIMAL                         3
+#define SQL_INTEGER                         4
+#define SQL_SMALLINT                        5
+#define SQL_FLOAT                           6
+#define SQL_REAL                            7
+#define SQL_DOUBLE                          8
+#define SQL_DATETIME                        9
+#define SQL_DATE                            9
+#define SQL_INTERVAL                       10
+#define SQL_TIME                           10
+#define SQL_TIMESTAMP                      11
+#define SQL_VARCHAR                        12
+#define SQL_BOOLEAN                        16
+#define SQL_UDT                            17
+#define SQL_UDT_LOCATOR                    18
+#define SQL_ROW                            19
+#define SQL_REF                            20
+#define SQL_BLOB                           30
+#define SQL_BLOB_LOCATOR                   31
+#define SQL_CLOB                           40
+#define SQL_CLOB_LOCATOR                   41
+#define SQL_ARRAY                          50
+#define SQL_ARRAY_LOCATOR                  51
+#define SQL_MULTISET                       55
+#define SQL_MULTISET_LOCATOR               56
+#define SQL_TYPE_DATE                      91
+#define SQL_TYPE_TIME                      92
+#define SQL_TYPE_TIMESTAMP                 93
+#define SQL_TYPE_TIME_WITH_TIMEZONE        94
+#define SQL_TYPE_TIMESTAMP_WITH_TIMEZONE   95
+#define SQL_INTERVAL_YEAR                 101
+#define SQL_INTERVAL_MONTH                102
+#define SQL_INTERVAL_DAY                  103
+#define SQL_INTERVAL_HOUR                 104
+#define SQL_INTERVAL_MINUTE               105
+#define SQL_INTERVAL_SECOND               106
+#define SQL_INTERVAL_YEAR_TO_MONTH        107
+#define SQL_INTERVAL_DAY_TO_HOUR          108
+#define SQL_INTERVAL_DAY_TO_MINUTE        109
+#define SQL_INTERVAL_DAY_TO_SECOND        110
+#define SQL_INTERVAL_HOUR_TO_MINUTE       111
+#define SQL_INTERVAL_HOUR_TO_SECOND       112
+#define SQL_INTERVAL_MINUTE_TO_SECOND     113
+
+
+/* Main return codes						*/
+#define	SQL_ERROR			(-1)
+#define	SQL_SUCCESS			0
+#define	SQL_SUCCESS_WITH_INFO		1
+#define	SQL_NO_DATA_FOUND		100
+
+/*
+ * for ODBC SQL Cursor Types
+ */
+#define SQL_CURSOR_FORWARD_ONLY         0UL
+#define SQL_CURSOR_KEYSET_DRIVEN        1UL
+#define SQL_CURSOR_DYNAMIC              2UL
+#define SQL_CURSOR_STATIC               3UL
+#define SQL_CURSOR_TYPE_DEFAULT         SQL_CURSOR_FORWARD_ONLY
+
+#endif	/*	SQL_SUCCESS	*/
+
+/* Handy macro for testing for success and success with info.		*/
+/* BEWARE that this macro can have side effects since rc appears twice!	*/
+/* So DONT use it as if(SQL_ok(func(...))) { ... }			*/
+#define SQL_ok(rc)	((rc)==SQL_SUCCESS || (rc)==SQL_SUCCESS_WITH_INFO)
+
+
+/* end of dbi_sql.h */
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/DBI/dbipport.h
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/DBI/dbipport.h	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/DBI/dbipport.h	(revision 14139)
@@ -0,0 +1,540 @@
+
+/* ppport.h -- Perl/Pollution/Portability Version 2.0002 
+ *
+ * Automatically Created by Devel::PPPort on Fri Jul 12 11:55:34 2002 
+ *
+ * Do NOT edit this file directly! -- Edit PPPort.pm instead.
+ *
+ * Version 2.x, Copyright (C) 2001, Paul Marquess.
+ * Version 1.x, Copyright (C) 1999, Kenneth Albanowski.
+ * This code may be used and distributed under the same license as any
+ * version of Perl.
+ * 
+ * This version of ppport.h is designed to support operation with Perl
+ * installations back to 5.004, and has been tested up to 5.8.0.
+ *
+ * If this version of ppport.h is failing during the compilation of this
+ * module, please check if a newer version of Devel::PPPort is available
+ * on CPAN before sending a bug report.
+ *
+ * If you are using the latest version of Devel::PPPort and it is failing
+ * during compilation of this module, please send a report to perlbug@perl.com
+ *
+ * Include all following information:
+ *
+ *  1. The complete output from running "perl -V"
+ *
+ *  2. This file.
+ *
+ *  3. The name & version of the module you were trying to build.
+ *
+ *  4. A full log of the build that failed.
+ *
+ *  5. Any other information that you think could be relevant.
+ *
+ *
+ * For the latest version of this code, please retreive the Devel::PPPort
+ * module from CPAN.
+ * 
+ */
+
+/*
+ * In order for a Perl extension module to be as portable as possible
+ * across differing versions of Perl itself, certain steps need to be taken.
+ * Including this header is the first major one, then using dTHR is all the
+ * appropriate places and using a PL_ prefix to refer to global Perl
+ * variables is the second.
+ *
+ */
+
+
+/* If you use one of a few functions that were not present in earlier
+ * versions of Perl, please add a define before the inclusion of ppport.h
+ * for a static include, or use the GLOBAL request in a single module to
+ * produce a global definition that can be referenced from the other
+ * modules.
+ * 
+ * Function:            Static define:           Extern define:
+ * newCONSTSUB()        NEED_newCONSTSUB         NEED_newCONSTSUB_GLOBAL
+ *
+ */
+ 
+
+/* To verify whether ppport.h is needed for your module, and whether any
+ * special defines should be used, ppport.h can be run through Perl to check
+ * your source code. Simply say:
+ * 
+ * 	perl -x ppport.h *.c *.h *.xs foo/bar*.c [etc]
+ * 
+ * The result will be a list of patches suggesting changes that should at
+ * least be acceptable, if not necessarily the most efficient solution, or a
+ * fix for all possible problems. It won't catch where dTHR is needed, and
+ * doesn't attempt to account for global macro or function definitions,
+ * nested includes, typemaps, etc.
+ * 
+ * In order to test for the need of dTHR, please try your module under a
+ * recent version of Perl that has threading compiled-in.
+ *
+ */ 
+
+
+/*
+#!/usr/bin/perl
+@ARGV = ("*.xs") if !@ARGV;
+%badmacros = %funcs = %macros = (); $replace = 0;
+foreach (<DATA>) {
+	$funcs{$1} = 1 if /Provide:\s+(\S+)/;
+	$macros{$1} = 1 if /^#\s*define\s+([a-zA-Z0-9_]+)/;
+	$replace = $1 if /Replace:\s+(\d+)/;
+	$badmacros{$2}=$1 if $replace and /^#\s*define\s+([a-zA-Z0-9_]+).*?\s+([a-zA-Z0-9_]+)/;
+	$badmacros{$1}=$2 if /Replace (\S+) with (\S+)/;
+}
+foreach $filename (map(glob($_),@ARGV)) {
+	unless (open(IN, "<$filename")) {
+		warn "Unable to read from $file: $!\n";
+		next;
+	}
+	print "Scanning $filename...\n";
+	$c = ""; while (<IN>) { $c .= $_; } close(IN);
+	$need_include = 0; %add_func = (); $changes = 0;
+	$has_include = ($c =~ /#.*include.*ppport/m);
+
+	foreach $func (keys %funcs) {
+		if ($c =~ /#.*define.*\bNEED_$func(_GLOBAL)?\b/m) {
+			if ($c !~ /\b$func\b/m) {
+				print "If $func isn't needed, you don't need to request it.\n" if
+				$changes += ($c =~ s/^.*#.*define.*\bNEED_$func\b.*\n//m);
+			} else {
+				print "Uses $func\n";
+				$need_include = 1;
+			}
+		} else {
+			if ($c =~ /\b$func\b/m) {
+				$add_func{$func} =1 ;
+				print "Uses $func\n";
+				$need_include = 1;
+			}
+		}
+	}
+
+	if (not $need_include) {
+		foreach $macro (keys %macros) {
+			if ($c =~ /\b$macro\b/m) {
+				print "Uses $macro\n";
+				$need_include = 1;
+			}
+		}
+	}
+
+	foreach $badmacro (keys %badmacros) {
+		if ($c =~ /\b$badmacro\b/m) {
+			$changes += ($c =~ s/\b$badmacro\b/$badmacros{$badmacro}/gm);
+			print "Uses $badmacros{$badmacro} (instead of $badmacro)\n";
+			$need_include = 1;
+		}
+	}
+	
+	if (scalar(keys %add_func) or $need_include != $has_include) {
+		if (!$has_include) {
+			$inc = join('',map("#define NEED_$_\n", sort keys %add_func)).
+			       "#include \"ppport.h\"\n";
+			$c = "$inc$c" unless $c =~ s/#.*include.*XSUB.*\n/$&$inc/m;
+		} elsif (keys %add_func) {
+			$inc = join('',map("#define NEED_$_\n", sort keys %add_func));
+			$c = "$inc$c" unless $c =~ s/^.*#.*include.*ppport.*$/$inc$&/m;
+		}
+		if (!$need_include) {
+			print "Doesn't seem to need ppport.h.\n";
+			$c =~ s/^.*#.*include.*ppport.*\n//m;
+		}
+		$changes++;
+	}
+	
+	if ($changes) {
+		open(OUT,">/tmp/ppport.h.$$");
+		print OUT $c;
+		close(OUT);
+		open(DIFF, "diff -u $filename /tmp/ppport.h.$$|");
+		while (<DIFF>) { s!/tmp/ppport\.h\.$$!$filename.patched!; print STDOUT; }
+		close(DIFF);
+		unlink("/tmp/ppport.h.$$");
+	} else {
+		print "Looks OK\n";
+	}
+}
+__DATA__
+*/
+
+#ifndef _P_P_PORTABILITY_H_
+#define _P_P_PORTABILITY_H_
+
+#ifndef PERL_REVISION
+#   ifndef __PATCHLEVEL_H_INCLUDED__
+#       include "patchlevel.h"
+#   endif
+#   ifndef PERL_REVISION
+#	define PERL_REVISION	(5)
+        /* Replace: 1 */
+#       define PERL_VERSION	PATCHLEVEL
+#       define PERL_SUBVERSION	SUBVERSION
+        /* Replace PERL_PATCHLEVEL with PERL_VERSION */
+        /* Replace: 0 */
+#   endif
+#endif
+
+#define PERL_BCDVERSION ((PERL_REVISION * 0x1000000L) + (PERL_VERSION * 0x1000L) + PERL_SUBVERSION)
+
+/* It is very unlikely that anyone will try to use this with Perl 6 
+   (or greater), but who knows.
+ */
+#if PERL_REVISION != 5
+#	error ppport.h only works with Perl version 5
+#endif /* PERL_REVISION != 5 */
+
+#ifndef ERRSV
+#	define ERRSV perl_get_sv("@",FALSE)
+#endif
+
+#if (PERL_VERSION < 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION <= 5))
+/* Replace: 1 */
+#	define PL_Sv		Sv
+#	define PL_compiling	compiling
+#	define PL_copline	copline
+#	define PL_curcop	curcop
+#	define PL_curstash	curstash
+#	define PL_defgv		defgv
+#	define PL_dirty		dirty
+#	define PL_dowarn	dowarn
+#	define PL_hints		hints
+#	define PL_na		na
+#	define PL_perldb	perldb
+#	define PL_rsfp_filters	rsfp_filters
+#	define PL_rsfpv		rsfp
+#	define PL_stdingv	stdingv
+#	define PL_sv_no		sv_no
+#	define PL_sv_undef	sv_undef
+#	define PL_sv_yes	sv_yes
+/* Replace: 0 */
+#endif
+
+#ifdef HASATTRIBUTE
+#  if defined(__GNUC__) && defined(__cplusplus)
+#    define PERL_UNUSED_DECL
+#  else
+#    define PERL_UNUSED_DECL __attribute__((unused))
+#  endif
+#else
+#  define PERL_UNUSED_DECL
+#endif
+
+#ifndef dNOOP
+#  define NOOP (void)0
+#  define dNOOP extern int Perl___notused PERL_UNUSED_DECL
+#endif
+
+#ifndef dTHR
+#  define dTHR          dNOOP
+#endif
+
+#ifndef dTHX
+#  define dTHX          dNOOP
+#  define dTHXa(x)      dNOOP
+#  define dTHXoa(x)     dNOOP
+#endif
+
+#ifndef pTHX
+#    define pTHX	void
+#    define pTHX_
+#    define aTHX
+#    define aTHX_
+#endif         
+
+#ifndef UVSIZE
+#   define UVSIZE IVSIZE
+#endif
+
+#ifndef NVTYPE
+#   if defined(USE_LONG_DOUBLE) && defined(HAS_LONG_DOUBLE)
+#       define NVTYPE long double
+#   else
+#       define NVTYPE double
+#   endif
+typedef NVTYPE NV;
+#endif
+
+#ifndef INT2PTR
+
+#if (IVSIZE == PTRSIZE) && (UVSIZE == PTRSIZE)
+#  define PTRV                  UV
+#  define INT2PTR(any,d)        (any)(d)
+#else
+#  if PTRSIZE == LONGSIZE
+#    define PTRV                unsigned long
+#  else
+#    define PTRV                unsigned
+#  endif
+#  define INT2PTR(any,d)        (any)(PTRV)(d)
+#endif
+#define NUM2PTR(any,d)  (any)(PTRV)(d)
+#define PTR2IV(p)       INT2PTR(IV,p)
+#define PTR2UV(p)       INT2PTR(UV,p)
+#define PTR2NV(p)       NUM2PTR(NV,p)
+#if PTRSIZE == LONGSIZE
+#  define PTR2ul(p)     (unsigned long)(p)
+#else
+#  define PTR2ul(p)     INT2PTR(unsigned long,p)        
+#endif
+
+#endif /* !INT2PTR */
+
+#ifndef boolSV
+#	define boolSV(b) ((b) ? &PL_sv_yes : &PL_sv_no)
+#endif
+
+#ifndef gv_stashpvn
+#	define gv_stashpvn(str,len,flags) gv_stashpv(str,flags)
+#endif
+
+#ifndef newSVpvn
+#	define newSVpvn(data,len) ((len) ? newSVpv ((data), (len)) : newSVpv ("", 0))
+#endif
+
+#ifndef newRV_inc
+/* Replace: 1 */
+#	define newRV_inc(sv) newRV(sv)
+/* Replace: 0 */
+#endif
+
+/* DEFSV appears first in 5.004_56 */
+#ifndef DEFSV
+#  define DEFSV	GvSV(PL_defgv)
+#endif
+
+#ifndef SAVE_DEFSV
+#    define SAVE_DEFSV SAVESPTR(GvSV(PL_defgv))
+#endif
+
+#ifndef newRV_noinc
+#  ifdef __GNUC__
+#    define newRV_noinc(sv)               \
+      ({                                  \
+          SV *nsv = (SV*)newRV(sv);       \
+          SvREFCNT_dec(sv);               \
+          nsv;                            \
+      })
+#  else
+#    if defined(USE_THREADS)
+static SV * newRV_noinc (SV * sv)
+{
+          SV *nsv = (SV*)newRV(sv);       
+          SvREFCNT_dec(sv);               
+          return nsv;                     
+}
+#    else
+#      define newRV_noinc(sv)    \
+        (PL_Sv=(SV*)newRV(sv), SvREFCNT_dec(sv), (SV*)PL_Sv)
+#    endif
+#  endif
+#endif
+
+/* Provide: newCONSTSUB */
+
+/* newCONSTSUB from IO.xs is in the core starting with 5.004_63 */
+#if (PERL_VERSION < 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION < 63))
+
+#if defined(NEED_newCONSTSUB)
+static
+#else
+extern void newCONSTSUB(HV * stash, char * name, SV *sv);
+#endif
+
+#if defined(NEED_newCONSTSUB) || defined(NEED_newCONSTSUB_GLOBAL)
+void
+newCONSTSUB(stash,name,sv)
+HV *stash;
+char *name;
+SV *sv;
+{
+	U32 oldhints = PL_hints;
+	HV *old_cop_stash = PL_curcop->cop_stash;
+	HV *old_curstash = PL_curstash;
+	line_t oldline = PL_curcop->cop_line;
+	PL_curcop->cop_line = PL_copline;
+
+	PL_hints &= ~HINT_BLOCK_SCOPE;
+	if (stash)
+		PL_curstash = PL_curcop->cop_stash = stash;
+
+	newSUB(
+
+#if (PERL_VERSION < 3) || ((PERL_VERSION == 3) && (PERL_SUBVERSION < 22))
+     /* before 5.003_22 */
+		start_subparse(),
+#else
+#  if (PERL_VERSION == 3) && (PERL_SUBVERSION == 22)
+     /* 5.003_22 */
+     		start_subparse(0),
+#  else
+     /* 5.003_23  onwards */
+     		start_subparse(FALSE, 0),
+#  endif
+#endif
+
+		newSVOP(OP_CONST, 0, newSVpv(name,0)),
+		newSVOP(OP_CONST, 0, &PL_sv_no),   /* SvPV(&PL_sv_no) == "" -- GMB */
+		newSTATEOP(0, Nullch, newSVOP(OP_CONST, 0, sv))
+	);
+
+	PL_hints = oldhints;
+	PL_curcop->cop_stash = old_cop_stash;
+	PL_curstash = old_curstash;
+	PL_curcop->cop_line = oldline;
+}
+#endif
+
+#endif /* newCONSTSUB */
+
+#ifndef START_MY_CXT
+
+/*
+ * Boilerplate macros for initializing and accessing interpreter-local
+ * data from C.  All statics in extensions should be reworked to use
+ * this, if you want to make the extension thread-safe.  See ext/re/re.xs
+ * for an example of the use of these macros.
+ *
+ * Code that uses these macros is responsible for the following:
+ * 1. #define MY_CXT_KEY to a unique string, e.g. "DynaLoader_guts"
+ * 2. Declare a typedef named my_cxt_t that is a structure that contains
+ *    all the data that needs to be interpreter-local.
+ * 3. Use the START_MY_CXT macro after the declaration of my_cxt_t.
+ * 4. Use the MY_CXT_INIT macro such that it is called exactly once
+ *    (typically put in the BOOT: section).
+ * 5. Use the members of the my_cxt_t structure everywhere as
+ *    MY_CXT.member.
+ * 6. Use the dMY_CXT macro (a declaration) in all the functions that
+ *    access MY_CXT.
+ */
+
+#if defined(MULTIPLICITY) || defined(PERL_OBJECT) || \
+    defined(PERL_CAPI)    || defined(PERL_IMPLICIT_CONTEXT)
+
+/* This must appear in all extensions that define a my_cxt_t structure,
+ * right after the definition (i.e. at file scope).  The non-threads
+ * case below uses it to declare the data as static. */
+#define START_MY_CXT
+
+#if (PERL_VERSION < 4 || (PERL_VERSION == 4 && PERL_SUBVERSION < 68 ))
+/* Fetches the SV that keeps the per-interpreter data. */
+#define dMY_CXT_SV \
+	SV *my_cxt_sv = perl_get_sv(MY_CXT_KEY, FALSE)
+#else /* >= perl5.004_68 */
+#define dMY_CXT_SV \
+	SV *my_cxt_sv = *hv_fetch(PL_modglobal, MY_CXT_KEY,		\
+				  sizeof(MY_CXT_KEY)-1, TRUE)
+#endif /* < perl5.004_68 */
+
+/* This declaration should be used within all functions that use the
+ * interpreter-local data. */
+#define dMY_CXT	\
+	dMY_CXT_SV;							\
+	my_cxt_t *my_cxtp = INT2PTR(my_cxt_t*,SvUV(my_cxt_sv))
+
+/* Creates and zeroes the per-interpreter data.
+ * (We allocate my_cxtp in a Perl SV so that it will be released when
+ * the interpreter goes away.) */
+#define MY_CXT_INIT \
+	dMY_CXT_SV;							\
+	/* newSV() allocates one more than needed */			\
+	my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1));\
+	Zero(my_cxtp, 1, my_cxt_t);					\
+	sv_setuv(my_cxt_sv, PTR2UV(my_cxtp))
+
+/* This macro must be used to access members of the my_cxt_t structure.
+ * e.g. MYCXT.some_data */
+#define MY_CXT		(*my_cxtp)
+
+/* Judicious use of these macros can reduce the number of times dMY_CXT
+ * is used.  Use is similar to pTHX, aTHX etc. */
+#define pMY_CXT		my_cxt_t *my_cxtp
+#define pMY_CXT_	pMY_CXT,
+#define _pMY_CXT	,pMY_CXT
+#define aMY_CXT		my_cxtp
+#define aMY_CXT_	aMY_CXT,
+#define _aMY_CXT	,aMY_CXT
+
+#else /* single interpreter */
+
+
+#define START_MY_CXT	static my_cxt_t my_cxt;
+#define dMY_CXT_SV	dNOOP
+#define dMY_CXT		dNOOP
+#define MY_CXT_INIT	NOOP
+#define MY_CXT		my_cxt
+
+#define pMY_CXT		void
+#define pMY_CXT_
+#define _pMY_CXT
+#define aMY_CXT
+#define aMY_CXT_
+#define _aMY_CXT
+
+#endif 
+
+#endif /* START_MY_CXT */
+
+#ifndef IVdf
+#  if IVSIZE == LONGSIZE
+#       define	IVdf		"ld"
+#       define	UVuf		"lu"
+#       define	UVof		"lo"
+#       define	UVxf		"lx"
+#       define	UVXf		"lX"
+#   else
+#       if IVSIZE == INTSIZE
+#           define	IVdf	"d"
+#           define	UVuf	"u"
+#           define	UVof	"o"
+#           define	UVxf	"x"
+#           define	UVXf	"X"
+#       endif
+#   endif
+#endif
+
+#ifndef NVef
+#   if defined(USE_LONG_DOUBLE) && defined(HAS_LONG_DOUBLE) && \
+	defined(PERL_PRIfldbl) /* Not very likely, but let's try anyway. */ 
+#       define NVef		PERL_PRIeldbl
+#       define NVff		PERL_PRIfldbl
+#       define NVgf		PERL_PRIgldbl
+#   else
+#       define NVef		"e"
+#       define NVff		"f"
+#       define NVgf		"g"
+#   endif
+#endif
+
+#ifndef AvFILLp			/* Older perls (<=5.003) lack AvFILLp */
+#   define AvFILLp AvFILL
+#endif
+
+#ifdef SvPVbyte
+#   if PERL_REVISION == 5 && PERL_VERSION < 7
+       /* SvPVbyte does not work in perl-5.6.1, borrowed version for 5.7.3 */
+#       undef SvPVbyte
+#       define SvPVbyte(sv, lp) \
+          ((SvFLAGS(sv) & (SVf_POK|SVf_UTF8)) == (SVf_POK) \
+           ? ((lp = SvCUR(sv)), SvPVX(sv)) : my_sv_2pvbyte(aTHX_ sv, &lp))
+       static char *
+       my_sv_2pvbyte(pTHX_ register SV *sv, STRLEN *lp)
+       {   
+           sv_utf8_downgrade(sv,0);
+           return SvPV(sv,*lp);
+       }
+#   endif
+#else
+#   define SvPVbyte SvPV
+#endif
+
+#endif /* _P_P_PORTABILITY_H_ */
+
+/* End of File ppport.h */
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/DBI/dbivport.h
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/DBI/dbivport.h	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/DBI/dbivport.h	(revision 14139)
@@ -0,0 +1,52 @@
+/* dbivport.h
+
+	Provides macros that enable greater portability between DBI versions.
+
+	This file should be *copied* and included in driver distributions
+	and #included into the source, after #include DBIXS.h
+
+	New driver releases should include an updated copy of dbivport.h
+	from the most recent DBI release.
+*/
+
+#ifndef DBI_VPORT_H
+#define DBI_VPORT_H
+
+#ifndef DBIh_SET_ERR_CHAR
+/* Emulate DBIh_SET_ERR_CHAR
+	Only uses the err_i, errstr and state parameters.
+*/
+#define DBIh_SET_ERR_CHAR(h, imp_xxh, err_c, err_i, errstr, state, method) \
+        sv_setiv(DBIc_ERR(imp_xxh), err_i); \
+        (state) ? (void)sv_setpv(DBIc_STATE(imp_xxh), state) : (void)SvOK_off(DBIc_STATE(imp_xxh)); \
+        sv_setpv(DBIc_ERRSTR(imp_xxh), errstr)
+#endif
+
+#ifndef DBIcf_Executed
+#define DBIcf_Executed    0x080000
+#endif
+
+#ifndef DBIc_TRACE_LEVEL_MASK
+#define DBIc_TRACE_LEVEL_MASK   0x0000000F
+#define DBIc_TRACE_FLAGS_MASK   0xFFFFFF00
+#define DBIc_TRACE_SETTINGS(imp) (DBIc_DBISTATE(imp)->debug)
+#define DBIc_TRACE_LEVEL(imp)   (DBIc_TRACE_SETTINGS(imp) & DBIc_TRACE_LEVEL_MASK)
+#define DBIc_TRACE_FLAGS(imp)   (DBIc_TRACE_SETTINGS(imp) & DBIc_TRACE_FLAGS_MASK)
+/* DBIc_TRACE_MATCHES - true if s1 'matches' s2  (c.f. trace_msg())
+   DBIc_TRACE_MATCHES(foo, DBIc_TRACE_SETTINGS(imp))
+*/
+#define DBIc_TRACE_MATCHES(s1, s2)      \
+        (  ((s1 & DBIc_TRACE_LEVEL_MASK) >= (s2 & DBIc_TRACE_LEVEL_MASK)) \
+        || ((s1 & DBIc_TRACE_FLAGS_MASK)  & (s2 & DBIc_TRACE_FLAGS_MASK)) )
+/* DBIc_TRACE - true if flags match & DBI level>=flaglevel, or if DBI level>level
+   DBIc_TRACE(imp,         0, 0, 4) = if level >= 4
+   DBIc_TRACE(imp, DBDtf_FOO, 2, 4) = if tracing DBDtf_FOO & level>=2 or level>=4
+   DBIc_TRACE(imp, DBDtf_FOO, 2, 0) = as above but never trace just due to level
+*/
+#define DBIc_TRACE(imp, flags, flaglevel, level)        \
+        (  (flags && (DBIc_TRACE_FLAGS(imp) & flags) && (DBIc_TRACE_LEVEL(imp) >= flaglevel)) \
+        || (level && DBIc_TRACE_LEVEL(imp) >= level) )
+#endif
+
+
+#endif /* !DBI_VPORT_H */
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Data/Dump/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Data/Dump/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Data/Dump/.packlist	(revision 14139)
@@ -0,0 +1,1 @@
+C:\mdewsnip\perl-5.6.1\site\lib\Data\Dump.pm
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Digest/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Digest/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Digest/.packlist	(revision 14139)
@@ -0,0 +1,2 @@
+C:\mdewsnip\perl-5.6.1\site\lib\Digest.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Digest\base.pm
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Digest/HMAC/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Digest/HMAC/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Digest/HMAC/.packlist	(revision 14139)
@@ -0,0 +1,3 @@
+C:\mdewsnip\perl-5.6.1\site\lib\Digest\HMAC.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Digest\HMAC_MD5.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Digest\HMAC_SHA1.pm
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Digest/MD2/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Digest/MD2/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Digest/MD2/.packlist	(revision 14139)
@@ -0,0 +1,5 @@
+C:\mdewsnip\perl-5.6.1\site\lib\Digest\MD2.pm
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Digest\MD2\MD2.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Digest\MD2\MD2.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Digest\MD2\MD2.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Digest\MD2\MD2.lib
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Digest/MD4/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Digest/MD4/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Digest/MD4/.packlist	(revision 14139)
@@ -0,0 +1,6 @@
+C:\mdewsnip\perl-5.6.1\site\lib\Digest\MD4.pm
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Digest\MD4\MD4.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Digest\MD4\MD4.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Digest\MD4\MD4.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Digest\MD4\MD4.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Digest\MD4\autosplit.ix
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Digest/MD4/autosplit.ix
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Digest/MD4/autosplit.ix	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Digest/MD4/autosplit.ix	(revision 14139)
@@ -0,0 +1,3 @@
+# Index created by AutoSplit for blib\lib\Digest\MD4.pm
+#    (file acts as timestamp)
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Digest/MD5/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Digest/MD5/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Digest/MD5/.packlist	(revision 14139)
@@ -0,0 +1,5 @@
+C:\mdewsnip\perl-5.6.1\site\lib\Digest\MD5.pm
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Digest\MD5\MD5.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Digest\MD5\MD5.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Digest\MD5\MD5.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Digest\MD5\MD5.lib
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Digest/SHA1/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Digest/SHA1/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Digest/SHA1/.packlist	(revision 14139)
@@ -0,0 +1,5 @@
+C:\mdewsnip\perl-5.6.1\site\lib\Digest\SHA1.pm
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Digest\SHA1\SHA1.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Digest\SHA1\SHA1.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Digest\SHA1\SHA1.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Digest\SHA1\SHA1.lib
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/File/CounterFile/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/File/CounterFile/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/File/CounterFile/.packlist	(revision 14139)
@@ -0,0 +1,1 @@
+C:\mdewsnip\perl-5.6.1\site\lib\File\CounterFile.pm
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Font/AFM/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Font/AFM/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Font/AFM/.packlist	(revision 14139)
@@ -0,0 +1,13 @@
+C:\mdewsnip\perl-5.6.1\site\lib\Font\AFM.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Font\Metrics\Courier.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Font\Metrics\CourierBold.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Font\Metrics\CourierBoldOblique.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Font\Metrics\CourierOblique.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Font\Metrics\Helvetica.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Font\Metrics\HelveticaBold.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Font\Metrics\HelveticaBoldOblique.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Font\Metrics\HelveticaOblique.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Font\Metrics\TimesBold.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Font\Metrics\TimesBoldItalic.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Font\Metrics\TimesItalic.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Font\Metrics\TimesRoman.pm
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/HTML-Tree/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/HTML-Tree/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/HTML-Tree/.packlist	(revision 14139)
@@ -0,0 +1,9 @@
+C:\mdewsnip\perl-5.6.1\site\lib\HTML\AsSubs.pm
+C:\mdewsnip\perl-5.6.1\site\lib\HTML\Element.pm
+C:\mdewsnip\perl-5.6.1\site\lib\HTML\Element\traverse.pm
+C:\mdewsnip\perl-5.6.1\site\lib\HTML\Parse.pm
+C:\mdewsnip\perl-5.6.1\site\lib\HTML\Tree.pm
+C:\mdewsnip\perl-5.6.1\site\lib\HTML\TreeBuilder.pm
+C:\mdewsnip\perl-5.6.1\site\lib\HTML\Tree\AboutObjects.pod
+C:\mdewsnip\perl-5.6.1\site\lib\HTML\Tree\AboutTrees.pod
+C:\mdewsnip\perl-5.6.1\site\lib\HTML\Tree\Scanning.pod
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/HTML/Parser/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/HTML/Parser/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/HTML/Parser/.packlist	(revision 14139)
@@ -0,0 +1,11 @@
+C:\mdewsnip\perl-5.6.1\site\lib\HTML\Entities.pm
+C:\mdewsnip\perl-5.6.1\site\lib\HTML\Filter.pm
+C:\mdewsnip\perl-5.6.1\site\lib\HTML\HeadParser.pm
+C:\mdewsnip\perl-5.6.1\site\lib\HTML\LinkExtor.pm
+C:\mdewsnip\perl-5.6.1\site\lib\HTML\Parser.pm
+C:\mdewsnip\perl-5.6.1\site\lib\HTML\PullParser.pm
+C:\mdewsnip\perl-5.6.1\site\lib\HTML\TokeParser.pm
+C:\mdewsnip\perl-5.6.1\site\lib\auto\HTML\Parser\Parser.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\HTML\Parser\Parser.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\HTML\Parser\Parser.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\HTML\Parser\Parser.lib
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/HTML/Tagset/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/HTML/Tagset/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/HTML/Tagset/.packlist	(revision 14139)
@@ -0,0 +1,1 @@
+C:\mdewsnip\perl-5.6.1\site\lib\HTML\Tagset.pm
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/IO/Zlib/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/IO/Zlib/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/IO/Zlib/.packlist	(revision 14139)
@@ -0,0 +1,1 @@
+C:\mdewsnip\perl-5.6.1\site\lib\IO\Zlib.pm
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/MD5/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/MD5/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/MD5/.packlist	(revision 14139)
@@ -0,0 +1,1 @@
+C:\mdewsnip\perl-5.6.1\site\lib\MD5.pm
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/MIME/Base64/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/MIME/Base64/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/MIME/Base64/.packlist	(revision 14139)
@@ -0,0 +1,14 @@
+C:\mdewsnip\perl-5.6.1\bin\decode-base64
+C:\mdewsnip\perl-5.6.1\bin\decode-base64.bat
+C:\mdewsnip\perl-5.6.1\bin\decode-qp
+C:\mdewsnip\perl-5.6.1\bin\decode-qp.bat
+C:\mdewsnip\perl-5.6.1\bin\encode-base64
+C:\mdewsnip\perl-5.6.1\bin\encode-base64.bat
+C:\mdewsnip\perl-5.6.1\bin\encode-qp
+C:\mdewsnip\perl-5.6.1\bin\encode-qp.bat
+C:\mdewsnip\perl-5.6.1\site\lib\MIME\Base64.pm
+C:\mdewsnip\perl-5.6.1\site\lib\MIME\QuotedPrint.pm
+C:\mdewsnip\perl-5.6.1\site\lib\auto\MIME\Base64\Base64.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\MIME\Base64\Base64.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\MIME\Base64\Base64.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\MIME\Base64\Base64.lib
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Net/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Net/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Net/.packlist	(revision 14139)
@@ -0,0 +1,18 @@
+C:\mdewsnip\perl-5.6.1\bin\libnetcfg.bat
+C:\mdewsnip\perl-5.6.1\bin\libnetcfg.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Net\Cmd.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Net\Config.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Net\Domain.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Net\FTP.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Net\FTP\A.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Net\FTP\E.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Net\FTP\I.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Net\FTP\L.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Net\FTP\dataconn.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Net\NNTP.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Net\Netrc.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Net\POP3.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Net\SMTP.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Net\Time.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Net\libnet.cfg
+C:\mdewsnip\perl-5.6.1\site\lib\Net\libnetFAQ.pod
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/PPM-Agent-Perl/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/PPM-Agent-Perl/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/PPM-Agent-Perl/.packlist	(revision 14139)
@@ -0,0 +1,67 @@
+C:\mdewsnip\perl-5.6.1\bin\ppm3-bin.cfg
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\Compat.pm
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\Config.pm
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\InstallerClient.pm
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\PPD.pm
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\Search.pm
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\YAML.pm
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\Archive-Tar.pkg
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\Archive-Tar.ppd
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\Compress-Zlib.pkg
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\Compress-Zlib.ppd
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\Data-Dump.pkg
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\Data-Dump.ppd
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\Digest-HMAC.pkg
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\Digest-HMAC.ppd
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\Digest-MD2.pkg
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\Digest-MD2.ppd
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\Digest-MD4.pkg
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\Digest-MD4.ppd
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\Digest-MD5.pkg
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\Digest-MD5.ppd
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\Digest-SHA1.pkg
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\Digest-SHA1.ppd
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\Digest.pkg
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\Digest.ppd
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\File-CounterFile.pkg
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\File-CounterFile.ppd
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\Font-AFM.pkg
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\Font-AFM.ppd
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\HTML-Parser.pkg
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\HTML-Parser.ppd
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\HTML-Tagset.pkg
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\HTML-Tagset.ppd
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\HTML-Tree.pkg
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\HTML-Tree.ppd
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\IO-Zlib.pkg
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\IO-Zlib.ppd
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\MD5.pkg
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\MD5.ppd
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\MIME-Base64.pkg
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\MIME-Base64.ppd
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\PPM-Agent-Perl.pkg
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\PPM-Agent-Perl.ppd
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\PPM.pkg
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\PPM.ppd
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\SOAP-Lite.pkg
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\SOAP-Lite.ppd
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\Storable.pkg
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\Storable.ppd
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\Test-Simple.pkg
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\Test-Simple.ppd
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\Tk.pkg
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\Tk.ppd
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\URI.pkg
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\URI.ppd
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\XML-Parser.pkg
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\XML-Parser.ppd
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\XML-Simple.pkg
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\XML-Simple.ppd
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\libnet.pkg
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\libnet.ppd
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\libwin32.pkg
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\libwin32.ppd
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\libwww-perl.pkg
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\libwww-perl.ppd
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\ppm.cfg
+C:\mdewsnip\perl-5.6.1\site\lib\ppm-conf\ppminst.bat
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/PPM/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/PPM/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/PPM/.packlist	(revision 14139)
@@ -0,0 +1,9 @@
+C:\mdewsnip\perl-5.6.1\bin\ppm2.bat
+C:\mdewsnip\perl-5.6.1\site\lib\PPM.pm
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\RelocPerl.pm
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\XML\Element.pm
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\XML\PPD.pm
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\XML\PPMConfig.pm
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\XML\RepositorySummary.pm
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\XML\ValidatingElement.pm
+C:\mdewsnip\perl-5.6.1\site\lib\ppm.xml
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/PPM/Shell/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/PPM/Shell/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/PPM/Shell/.packlist	(revision 14139)
@@ -0,0 +1,24 @@
+C:\mdewsnip\perl-5.6.1\bin\ppm3-bin
+C:\mdewsnip\perl-5.6.1\bin\ppm3-bin.bat
+C:\mdewsnip\perl-5.6.1\bin\ppm3.bat
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\Archive.pm
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\Archive\Tar.pm
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\Archive\Zip.pm
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\Compat.pm
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\Config.pm
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\Installer.pm
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\Installer\Local.pm
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\Installer\Remote.pm
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\PPD.pm
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\Repository.pm
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\Repository\Local.pm
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\Repository\PPM3Server.pm
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\Repository\PPMServer.pm
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\Repository\WWW.pm
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\Result.pm
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\Search.pm
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\Sysinfo.pm
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\Term\Shell.pm
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\Trace.pm
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\UI.pm
+C:\mdewsnip\perl-5.6.1\site\lib\PPM\YAML.pm
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/SOAP/Lite/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/SOAP/Lite/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/SOAP/Lite/.packlist	(revision 14139)
@@ -0,0 +1,28 @@
+C:\mdewsnip\perl-5.6.1\bin\SOAPsh.bat
+C:\mdewsnip\perl-5.6.1\bin\SOAPsh.pl
+C:\mdewsnip\perl-5.6.1\bin\XMLRPCsh.bat
+C:\mdewsnip\perl-5.6.1\bin\XMLRPCsh.pl
+C:\mdewsnip\perl-5.6.1\bin\stubmaker.bat
+C:\mdewsnip\perl-5.6.1\bin\stubmaker.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Apache\SOAP.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Apache\XMLRPC\Lite.pm
+C:\mdewsnip\perl-5.6.1\site\lib\IO\SessionData.pm
+C:\mdewsnip\perl-5.6.1\site\lib\IO\SessionSet.pm
+C:\mdewsnip\perl-5.6.1\site\lib\SOAP\Lite.pm
+C:\mdewsnip\perl-5.6.1\site\lib\SOAP\Test.pm
+C:\mdewsnip\perl-5.6.1\site\lib\SOAP\Transport\FTP.pm
+C:\mdewsnip\perl-5.6.1\site\lib\SOAP\Transport\HTTP.pm
+C:\mdewsnip\perl-5.6.1\site\lib\SOAP\Transport\IO.pm
+C:\mdewsnip\perl-5.6.1\site\lib\SOAP\Transport\JABBER.pm
+C:\mdewsnip\perl-5.6.1\site\lib\SOAP\Transport\LOCAL.pm
+C:\mdewsnip\perl-5.6.1\site\lib\SOAP\Transport\MAILTO.pm
+C:\mdewsnip\perl-5.6.1\site\lib\SOAP\Transport\MQ.pm
+C:\mdewsnip\perl-5.6.1\site\lib\SOAP\Transport\POP3.pm
+C:\mdewsnip\perl-5.6.1\site\lib\SOAP\Transport\TCP.pm
+C:\mdewsnip\perl-5.6.1\site\lib\UDDI\Lite.pm
+C:\mdewsnip\perl-5.6.1\site\lib\XMLRPC\Lite.pm
+C:\mdewsnip\perl-5.6.1\site\lib\XMLRPC\Test.pm
+C:\mdewsnip\perl-5.6.1\site\lib\XMLRPC\Transport\HTTP.pm
+C:\mdewsnip\perl-5.6.1\site\lib\XMLRPC\Transport\POP3.pm
+C:\mdewsnip\perl-5.6.1\site\lib\XMLRPC\Transport\TCP.pm
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Lite.pm
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/.packlist	(revision 14139)
@@ -0,0 +1,22 @@
+C:\mdewsnip\perl-5.6.1\site\lib\Storable.pm
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Storable\Storable.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Storable\Storable.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Storable\Storable.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Storable\Storable.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Storable\_freeze.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Storable\_retrieve.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Storable\_store.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Storable\_store_fd.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Storable\autosplit.ix
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Storable\fd_retrieve.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Storable\freeze.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Storable\lock_nstore.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Storable\lock_retrieve.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Storable\lock_store.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Storable\nfreeze.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Storable\nstore.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Storable\nstore_fd.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Storable\retrieve.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Storable\store.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Storable\store_fd.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Storable\thaw.al
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/_freeze.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/_freeze.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/_freeze.al	(revision 14139)
@@ -0,0 +1,23 @@
+# NOTE: Derived from blib\lib\Storable.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Storable;
+
+#line 255 "blib\lib\Storable.pm (autosplit into blib\lib\auto\Storable\_freeze.al)"
+# Internal freeze routine
+sub _freeze {
+	my $xsptr = shift;
+	my $self = shift;
+	logcroak "not a reference" unless ref($self);
+	logcroak "too many arguments" unless @_ == 0;	# No @foo in arglist
+	my $da = $@;				# Don't mess if called from exception handler
+	my $ret;
+	# Call C routine mstore or net_mstore, depending on network order
+	eval { $ret = &$xsptr($self) };
+	logcroak $@ if $@ =~ s/\.?\n$/,/;
+	$@ = $da;
+	return $ret ? $ret : undef;
+}
+
+# end of Storable::_freeze
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/_retrieve.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/_retrieve.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/_retrieve.al	(revision 14139)
@@ -0,0 +1,31 @@
+# NOTE: Derived from blib\lib\Storable.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Storable;
+
+#line 289 "blib\lib\Storable.pm (autosplit into blib\lib\auto\Storable\_retrieve.al)"
+# Internal retrieve routine
+sub _retrieve {
+	my ($file, $use_locking) = @_;
+	local *FILE;
+	open(FILE, $file) || logcroak "can't open $file: $!";
+	binmode FILE;							# Archaic systems...
+	my $self;
+	my $da = $@;							# Could be from exception handler
+	if ($use_locking) {
+		unless (&CAN_FLOCK) {
+			logcarp "Storable::lock_store: fcntl/flock emulation broken on $^O";
+			return undef;
+		}
+		flock(FILE, LOCK_SH) || logcroak "can't get shared lock on $file: $!";
+		# Unlocking will happen when FILE is closed
+	}
+	eval { $self = pretrieve(*FILE) };		# Call C routine
+	close(FILE);
+	logcroak $@ if $@ =~ s/\.?\n$/,/;
+	$@ = $da;
+	return $self;
+}
+
+# end of Storable::_retrieve
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/_store.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/_store.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/_store.al	(revision 14139)
@@ -0,0 +1,39 @@
+# NOTE: Derived from blib\lib\Storable.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Storable;
+
+#line 167 "blib\lib\Storable.pm (autosplit into blib\lib\auto\Storable\_store.al)"
+# Internal store to file routine
+sub _store {
+	my $xsptr = shift;
+	my $self = shift;
+	my ($file, $use_locking) = @_;
+	logcroak "not a reference" unless ref($self);
+	logcroak "wrong argument number" unless @_ == 2;	# No @foo in arglist
+	local *FILE;
+	open(FILE, ">$file") || logcroak "can't create $file: $!";
+	binmode FILE;				# Archaic systems...
+	if ($use_locking) {
+		unless (&CAN_FLOCK) {
+			logcarp "Storable::lock_store: fcntl/flock emulation broken on $^O";
+			return undef;
+		}
+		flock(FILE, LOCK_EX) ||
+			logcroak "can't get exclusive lock on $file: $!";
+		truncate FILE, 0;
+		# Unlocking will happen when FILE is closed
+	}
+	my $da = $@;				# Don't mess if called from exception handler
+	my $ret;
+	# Call C routine nstore or pstore, depending on network order
+	eval { $ret = &$xsptr(*FILE, $self) };
+	close(FILE) or $ret = undef;
+	unlink($file) or warn "Can't unlink $file: $!\n" if $@ || !defined $ret;
+	logcroak $@ if $@ =~ s/\.?\n$/,/;
+	$@ = $da;
+	return $ret ? $ret : undef;
+}
+
+# end of Storable::_store
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/_store_fd.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/_store_fd.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/_store_fd.al	(revision 14139)
@@ -0,0 +1,26 @@
+# NOTE: Derived from blib\lib\Storable.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Storable;
+
+#line 218 "blib\lib\Storable.pm (autosplit into blib\lib\auto\Storable\_store_fd.al)"
+# Internal store routine on opened file descriptor
+sub _store_fd {
+	my $xsptr = shift;
+	my $self = shift;
+	my ($file) = @_;
+	logcroak "not a reference" unless ref($self);
+	logcroak "too many arguments" unless @_ == 1;	# No @foo in arglist
+	my $fd = fileno($file);
+	logcroak "not a valid file descriptor" unless defined $fd;
+	my $da = $@;				# Don't mess if called from exception handler
+	my $ret;
+	# Call C routine nstore or pstore, depending on network order
+	eval { $ret = &$xsptr($file, $self) };
+	logcroak $@ if $@ =~ s/\.?\n$/,/;
+	$@ = $da;
+	return $ret ? $ret : undef;
+}
+
+# end of Storable::_store_fd
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/autosplit.ix
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/autosplit.ix	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/autosplit.ix	(revision 14139)
@@ -0,0 +1,20 @@
+# Index created by AutoSplit for blib\lib\Storable.pm
+#    (file acts as timestamp)
+package Storable;
+sub store  ;
+sub nstore  ;
+sub lock_store  ;
+sub lock_nstore  ;
+sub _store  ;
+sub store_fd  ;
+sub nstore_fd  ;
+sub _store_fd  ;
+sub freeze  ;
+sub nfreeze  ;
+sub _freeze  ;
+sub retrieve  ;
+sub lock_retrieve  ;
+sub _retrieve  ;
+sub fd_retrieve  ;
+sub thaw  ;
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/fd_retrieve.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/fd_retrieve.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/fd_retrieve.al	(revision 14139)
@@ -0,0 +1,25 @@
+# NOTE: Derived from blib\lib\Storable.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Storable;
+
+#line 312 "blib\lib\Storable.pm (autosplit into blib\lib\auto\Storable\fd_retrieve.al)"
+#
+# fd_retrieve
+#
+# Same as retrieve, but perform from an already opened file descriptor instead.
+#
+sub fd_retrieve {
+	my ($file) = @_;
+	my $fd = fileno($file);
+	logcroak "not a valid file descriptor" unless defined $fd;
+	my $self;
+	my $da = $@;							# Could be from exception handler
+	eval { $self = pretrieve($file) };		# Call C routine
+	logcroak $@ if $@ =~ s/\.?\n$/,/;
+	$@ = $da;
+	return $self;
+}
+
+# end of Storable::fd_retrieve
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/freeze.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/freeze.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/freeze.al	(revision 14139)
@@ -0,0 +1,18 @@
+# NOTE: Derived from blib\lib\Storable.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Storable;
+
+#line 236 "blib\lib\Storable.pm (autosplit into blib\lib\auto\Storable\freeze.al)"
+#
+# freeze
+#
+# Store oject and its hierarchy in memory and return a scalar
+# containing the result.
+#
+sub freeze {
+	_freeze(\&mstore, @_);
+}
+
+# end of Storable::freeze
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/lock_nstore.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/lock_nstore.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/lock_nstore.al	(revision 14139)
@@ -0,0 +1,17 @@
+# NOTE: Derived from blib\lib\Storable.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Storable;
+
+#line 158 "blib\lib\Storable.pm (autosplit into blib\lib\auto\Storable\lock_nstore.al)"
+#
+# lock_nstore
+#
+# Same as nstore, but flock the file first (advisory locking).
+#
+sub lock_nstore {
+	return _store(\&net_pstore, @_, 1);
+}
+
+# end of Storable::lock_nstore
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/lock_retrieve.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/lock_retrieve.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/lock_retrieve.al	(revision 14139)
@@ -0,0 +1,17 @@
+# NOTE: Derived from blib\lib\Storable.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Storable;
+
+#line 280 "blib\lib\Storable.pm (autosplit into blib\lib\auto\Storable\lock_retrieve.al)"
+#
+# lock_retrieve
+#
+# Same as retrieve, but with advisory locking.
+#
+sub lock_retrieve {
+	_retrieve($_[0], 1);
+}
+
+# end of Storable::lock_retrieve
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/lock_store.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/lock_store.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/lock_store.al	(revision 14139)
@@ -0,0 +1,17 @@
+# NOTE: Derived from blib\lib\Storable.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Storable;
+
+#line 149 "blib\lib\Storable.pm (autosplit into blib\lib\auto\Storable\lock_store.al)"
+#
+# lock_store
+#
+# Same as store, but flock the file first (advisory locking).
+#
+sub lock_store {
+	return _store(\&pstore, @_, 1);
+}
+
+# end of Storable::lock_store
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/nfreeze.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/nfreeze.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/nfreeze.al	(revision 14139)
@@ -0,0 +1,17 @@
+# NOTE: Derived from blib\lib\Storable.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Storable;
+
+#line 246 "blib\lib\Storable.pm (autosplit into blib\lib\auto\Storable\nfreeze.al)"
+#
+# nfreeze
+#
+# Same as freeze but in network order.
+#
+sub nfreeze {
+	_freeze(\&net_mstore, @_);
+}
+
+# end of Storable::nfreeze
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/nstore.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/nstore.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/nstore.al	(revision 14139)
@@ -0,0 +1,17 @@
+# NOTE: Derived from blib\lib\Storable.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Storable;
+
+#line 140 "blib\lib\Storable.pm (autosplit into blib\lib\auto\Storable\nstore.al)"
+#
+# nstore
+#
+# Same as store, but in network order.
+#
+sub nstore {
+	return _store(\&net_pstore, @_, 0);
+}
+
+# end of Storable::nstore
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/nstore_fd.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/nstore_fd.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/nstore_fd.al	(revision 14139)
@@ -0,0 +1,18 @@
+# NOTE: Derived from blib\lib\Storable.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Storable;
+
+#line 208 "blib\lib\Storable.pm (autosplit into blib\lib\auto\Storable\nstore_fd.al)"
+#
+# nstore_fd
+#
+# Same as store_fd, but in network order.
+#
+sub nstore_fd {
+	my ($self, $file) = @_;
+	return _store_fd(\&net_pstore, @_);
+}
+
+# end of Storable::nstore_fd
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/retrieve.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/retrieve.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/retrieve.al	(revision 14139)
@@ -0,0 +1,18 @@
+# NOTE: Derived from blib\lib\Storable.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Storable;
+
+#line 270 "blib\lib\Storable.pm (autosplit into blib\lib\auto\Storable\retrieve.al)"
+#
+# retrieve
+#
+# Retrieve object hierarchy from disk, returning a reference to the root
+# object of that tree.
+#
+sub retrieve {
+	_retrieve($_[0], 0);
+}
+
+# end of Storable::retrieve
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/store.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/store.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/store.al	(revision 14139)
@@ -0,0 +1,20 @@
+# NOTE: Derived from blib\lib\Storable.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Storable;
+
+#line 128 "blib\lib\Storable.pm (autosplit into blib\lib\auto\Storable\store.al)"
+#
+# store
+#
+# Store target object hierarchy, identified by a reference to its root.
+# The stored object tree may later be retrieved to memory via retrieve.
+# Returns undef if an I/O error occurred, in which case the file is
+# removed.
+#
+sub store {
+	return _store(\&pstore, @_, 0);
+}
+
+# end of Storable::store
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/store_fd.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/store_fd.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/store_fd.al	(revision 14139)
@@ -0,0 +1,18 @@
+# NOTE: Derived from blib\lib\Storable.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Storable;
+
+#line 198 "blib\lib\Storable.pm (autosplit into blib\lib\auto\Storable\store_fd.al)"
+#
+# store_fd
+#
+# Same as store, but perform on an already opened file descriptor instead.
+# Returns undef if an I/O error occurred.
+#
+sub store_fd {
+	return _store_fd(\&pstore, @_);
+}
+
+# end of Storable::store_fd
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/thaw.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/thaw.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Storable/thaw.al	(revision 14139)
@@ -0,0 +1,25 @@
+# NOTE: Derived from blib\lib\Storable.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Storable;
+
+#line 329 "blib\lib\Storable.pm (autosplit into blib\lib\auto\Storable\thaw.al)"
+#
+# thaw
+#
+# Recreate objects in memory from an existing frozen image created
+# by freeze.  If the frozen image passed is undef, return undef.
+#
+sub thaw {
+	my ($frozen) = @_;
+	return undef unless defined $frozen;
+	my $self;
+	my $da = $@;							# Could be from exception handler
+	eval { $self = mretrieve($frozen) };	# Call C routine
+	logcroak $@ if $@ =~ s/\.?\n$/,/;
+	$@ = $da;
+	return $self;
+}
+
+1;
+# end of Storable::thaw
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Test/Simple/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Test/Simple/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Test/Simple/.packlist	(revision 14139)
@@ -0,0 +1,4 @@
+C:\mdewsnip\perl-5.6.1\site\lib\Test\Builder.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Test\More.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Test\Simple.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Test\Tutorial.pod
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Text/Autoformat/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Text/Autoformat/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Text/Autoformat/.packlist	(revision 14139)
@@ -0,0 +1,2 @@
+C:\mdewsnip\perl-5.6.1\site\lib\Text\Autoformat.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Text\demo.pl
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/.packlist	(revision 14139)
@@ -0,0 +1,645 @@
+C:\mdewsnip\perl-5.6.1\bin\ptked
+C:\mdewsnip\perl-5.6.1\bin\ptked.bat
+C:\mdewsnip\perl-5.6.1\bin\ptksh
+C:\mdewsnip\perl-5.6.1\bin\ptksh.bat
+C:\mdewsnip\perl-5.6.1\bin\widget
+C:\mdewsnip\perl-5.6.1\bin\widget.bat
+C:\mdewsnip\perl-5.6.1\site\lib\Tie\Watch.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Adjuster.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Adjuster.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\After.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Animation.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Animation.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Balloon.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Balloon.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Bitmap.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Bitmap.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\BrowseEntry.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\BrowseEntry.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Button.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Button.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Camel.xpm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Canvas.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Canvas.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Checkbutton.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Checkbutton.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Clipboard.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Clipboard.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\CmdLine.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\CmdLine.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\ColorEdit.xpm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\ColorEditor.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\ColorEditor.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Common.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Compound.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Compound.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Config.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\ConfigSpecs.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Configure.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Credits
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\DItem.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Derived.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Derived.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Dialog.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Dialog.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\DialogBox.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\DialogBox.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\DirTree.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\DirTree.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Dirlist.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\DragDrop.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\DragDrop\Common.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\DragDrop\KDEDrop.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\DragDrop\KDESite.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\DragDrop\LocalDrop.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\DragDrop\Rect.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\DragDrop\SunConst.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\DragDrop\SunDrop.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\DragDrop\SunSite.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\DragDrop\Win32Drop.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\DragDrop\Win32Site.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\DragDrop\XDNDDrop.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\DragDrop\XDNDSite.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\DropSite.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\DropSite.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\English.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Entry.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Entry.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Error.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\ErrorDialog.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Event.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Event\IO.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Eventloop.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\FBox.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\FileSelect.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\FileSelect.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\FloatEntry.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Font.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Font.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Frame.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Frame.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\HList.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\HList.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\IO.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\IO.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\IconList.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Image.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Image.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\InputO.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Internals.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Item.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\ItemStyle.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\LabEntry.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\LabFrame.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\LabFrame.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\LabRadio.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Label.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Label.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Listbox.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Listbox.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\MMtry.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\MMutil.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\MainWindow.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\MainWindow.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\MakeDepend.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Menu.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Menu.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Menu\Item.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Menubar.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Menubutton.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Menubutton.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Message.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Message.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Mwm.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\NBFrame.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\NoteBook.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\NoteBook.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Optionmenu.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Optionmenu.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Pane.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Photo.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Photo.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Pixmap.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Pixmap.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Pretty.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\ProgressBar.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\README.Adjust
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\ROText.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\ROText.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Radiobutton.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Radiobutton.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Region.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Reindex.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\ReindexedROText.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\ReindexedText.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Scale.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Scale.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Scrollbar.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Scrollbar.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Scrolled.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Stats.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Submethods.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Submethods.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\SunConst.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\TList.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\TList.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Table.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Table.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Tcl-perl.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Text.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Text.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\TextEdit.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\TextList.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\TextUndo.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\TextUndo.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Text\Tag.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Tiler.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Tiler.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\TixGrid.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\TixGrid.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Tk.xbm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Tk.xpm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\TkXSUB.def
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Toplevel.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Toplevel.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Trace.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Tree.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Tree.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\UserGuide.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Widget.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Widget.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\WidgetDemo.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Wm.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Wm.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\X.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\X.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\X11Font.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\X11Font.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\X11\X.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\X11\Xatom.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\X11\Xfuncproto.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\X11\Xlib.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\X11\Xutil.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\X11\cursorfont.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\X11\keysym.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\X11\keysymdef.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\X11\license.terms
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Xcamel.gif
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Xlib.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Xrm.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\Xrm.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\act_folder.xbm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\act_folder.xpm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\after.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\anim.gif
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\balArrow.xbm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\bind.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\bindtags.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\callbacks.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\cbxarrow.xbm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\chooseColor.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\composite.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\LabEnLabRad.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\images\QuitPB.xpm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\images\QuitPBa.xpm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\images\c.icon
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\images\cursor.mask
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\images\cursor.xbm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\images\dir.icon
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\images\dir.mask
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\images\earth.gif
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\images\earthris.gif
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\images\face
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\images\flagdown
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\images\flagup
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\images\grey.25
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\images\grey.5
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\images\letters
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\images\mickey.gif
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\images\ned.xpm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\images\noletters
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\images\page.icon
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\images\page.mask
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\images\pattern
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\images\teapot.ppm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\Ball.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\Plot.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\WidgetDemo.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\arrows.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\bind.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\bitmaps.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\bounce.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\button.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\check.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\clrpick.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\colors.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\cscroll.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\ctext.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\dialog1.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\dialog2.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\entry1.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\entry2.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\filebox.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\floor.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\form.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\hscale.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\icon.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\image1.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\image2.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\items.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\labels.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\menbut.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\menus.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\menus2.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\mkArrow.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\mkBasic.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\mkBitmaps.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\mkButton.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\mkCanvText.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\mkCheck.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\mkEntry.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\mkEntry2.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\mkFloor.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\mkForm.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\mkHScale.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\mkIcon.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\mkItems.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\mkLabel.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\mkListbox.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\mkListbox2.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\mkListbox3.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\mkPlot.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\mkPuzzle.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\mkRadio.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\mkRuler.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\mkScroll.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\mkStyles.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\mkTextBind.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\mkTextWind.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\mkTxtSearch.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\mkVScale.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\msgBox.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\plot.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\puzzle.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\radio.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\ruler.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\sayings.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\search.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\showVars.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\states.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\style.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\texts.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\transtile.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\twind.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widget_lib\vscale.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widtrib\Gedi.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widtrib\HList.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widtrib\HList2.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widtrib\TEMPLATE.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widtrib\Tiler.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widtrib\balloon.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widtrib\browseentry.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widtrib\browseentry2.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widtrib\dirtree.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widtrib\form_mgr.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widtrib\labframe.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widtrib\lib\npuz\Xcamel.npuz
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widtrib\notebook.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widtrib\npuz.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widtrib\plop.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\demos\widtrib\progress.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\event.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\exit.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\file.xbm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\file.xpm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\fileevent.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\focus.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\folder.xbm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\folder.xpm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\form.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\getOpenFile.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\grab.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\grid.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\icon.gif
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\install.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\license.terms
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\mega.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\messageBox.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\openfile.xbm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\openfolder.xbm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\openfolder.xpm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\option.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\options.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\overview.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\Lang.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\Lang.m
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\Lang.t
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\LangIO.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\Lang_f.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\Tcl-pTk
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\Xlib.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\Xlib.m
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\Xlib.t
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\Xlib_f.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\compat\limits.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\compat\stdlib.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\compat\unistd.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\default.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\img.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\imgInt.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\imgInt.m
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\imgInt.t
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\imgInt_f.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\ks_names.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\mkVFunc
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\patchlevel.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\port.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tclMath.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tix.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tix.m
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tix.t
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tixBitmaps.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tixDef.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tixForm.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tixGrData.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tixGrid.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tixHList.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tixImgXpm.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tixImgXpm.m
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tixImgXpm.t
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tixImgXpm_f.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tixInt.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tixInt.m
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tixInt.t
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tixInt_f.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tixPort.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tixTList.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tixWinInt.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tixWinPort.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tix_f.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tk.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tk.m
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tk.t
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tk3d.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkButton.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkCanvas.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkCanvases.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkColor.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkConfig.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkEvent.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkEvent.m
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkEvent.t
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkEvent_f.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkFileFilter.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkFont.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkImgPhoto.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkImgPhoto.m
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkImgPhoto.t
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkImgPhoto_f.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkInitScript.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkInt.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkInt.m
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkInt.t
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkInt_f.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkMenu.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkMenubutton.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkOption.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkOption.m
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkOption.t
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkOption_f.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkPort.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkScale.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkScrollbar.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkSelect.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkText.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkVMacro.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkWin.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkWin.m
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkWin.t
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkWinDefault.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkWinInt.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkWinInt.m
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkWinInt.t
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkWinInt_f.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkWinPort.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkWin_f.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tkXrm.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\tk_f.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pTk\xbytes.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\pack.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\palette.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\place.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\prolog.ps
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\reindex.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\selection.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\send.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\srcfile.xpm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\textfile.xpm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\tixWm.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\tkGlue.def
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\tkGlue.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\tkGlue.m
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\tkGlue.t
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\tkGlue_f.h
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\tkvars.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\tranicon.gif
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\typemap
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\widgets.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\widgets.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\win.xbm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\winfolder.xpm
+C:\mdewsnip\perl-5.6.1\site\lib\Tk\wintext.xpm
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Bitmap\Bitmap.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Bitmap\Bitmap.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Bitmap\Bitmap.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Bitmap\Bitmap.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\CancelRepeat.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Canvas\Canvas.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Canvas\Canvas.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Canvas\Canvas.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Canvas\Canvas.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Clipboard\autosplit.ix
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Clipboard\getSelected.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Compound\Compound.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Compound\Compound.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Compound\Compound.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Compound\Compound.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\DragDrop\Win32Site\Win32Site.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\DragDrop\Win32Site\Win32Site.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\DragDrop\Win32Site\Win32Site.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\DragDrop\Win32Site\Win32Site.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\EnterFocus.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Entry\Entry.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Entry\Entry.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Entry\Entry.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Entry\Entry.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Error.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Event\Event.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Event\Event.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Event\Event.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Event\Event.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\FirstMenu.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\FocusChildren.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\FocusOK.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Frame\AddScrollbars.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Frame\FindMenu.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Frame\autosplit.ix
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Frame\freeze_on_map.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Frame\label.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Frame\labelPack.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Frame\labelVariable.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Frame\packscrollbars.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Frame\queuePack.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Frame\sbset.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Frame\scrollbars.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\HList\HList.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\HList\HList.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\HList\HList.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\HList\HList.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\IO\IO.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\IO\IO.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\IO\IO.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\IO\IO.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\ImageNames.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\ImageTypes.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Listbox\AutoScan.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Listbox\BeginExtend.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Listbox\BeginSelect.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Listbox\BeginToggle.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Listbox\ButtonRelease_1.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Listbox\Cancel.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Listbox\Cntrl_End.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Listbox\Cntrl_Home.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Listbox\Cntrl_backslash.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Listbox\DataExtend.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Listbox\ExtendUpDown.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Listbox\Listbox.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Listbox\Listbox.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Listbox\Listbox.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Listbox\Listbox.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Listbox\Motion.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Listbox\SelectAll.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Listbox\SetList.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Listbox\UpDown.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Listbox\autosplit.ix
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Listbox\clipboardPaste.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Listbox\deleteSelected.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Listbox\getSelected.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Listbox\xyIndex.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Menubutton\Menubutton.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Menubutton\Menubutton.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Menubutton\Menubutton.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Menubutton\Menubutton.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\NBFrame\NBFrame.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\NBFrame\NBFrame.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\NBFrame\NBFrame.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\NBFrame\NBFrame.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Photo\Photo.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Photo\Photo.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Photo\Photo.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Photo\Photo.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Pixmap\Pixmap.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Pixmap\Pixmap.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Pixmap\Pixmap.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Pixmap\Pixmap.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Receive.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\RepeatId.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Scale\Activate.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Scale\ButtonDown.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Scale\ButtonUp.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Scale\ControlPress.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Scale\Drag.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Scale\EndDrag.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Scale\Enter.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Scale\Increment.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Scale\Leave.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Scale\Scale.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Scale\Scale.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Scale\Scale.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Scale\Scale.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Scale\autosplit.ix
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Scrollbar\ButtonDown.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Scrollbar\ButtonUp.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Scrollbar\Drag.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Scrollbar\EndDrag.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Scrollbar\Enter.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Scrollbar\Leave.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Scrollbar\Motion.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Scrollbar\ScrlByPages.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Scrollbar\ScrlByUnits.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Scrollbar\ScrlToPos.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Scrollbar\ScrlTopBottom.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Scrollbar\Scrollbar.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Scrollbar\Scrollbar.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Scrollbar\Scrollbar.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Scrollbar\Scrollbar.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Scrollbar\Select.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Scrollbar\StartDrag.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Scrollbar\autosplit.ix
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Selection.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\TList\TList.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\TList\TList.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\TList\TList.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\TList\TList.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Table\Create.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Table\Posn.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Table\autosplit.ix
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Table\see.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Table\totalColumns.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Table\totalRows.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\TextEdit\autosplit.ix
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\TextUndo\autosplit.ix
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Text\Text.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Text\Text.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Text\Text.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Text\Text.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Text\autosplit.ix
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\TixGrid\TixGrid.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\TixGrid\TixGrid.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\TixGrid\TixGrid.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\TixGrid\TixGrid.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Tk.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Tk.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Tk.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Tk.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Toplevel\FG_BindIn.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Toplevel\FG_BindOut.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Toplevel\FG_Create.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Toplevel\FG_Destroy.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Toplevel\FG_In.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Toplevel\FG_Out.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Toplevel\autosplit.ix
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\TraverseToMenu.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Widget\ASkludge.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Widget\autosplit.ix
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Widget\clipboardKeysyms.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Widget\pathname.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Wm\AnchorAdjust.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Wm\FullScreen.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Wm\Popup.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Wm\Post.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Wm\autosplit.ix
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Wm\iconposition.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\X\X.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\X\X.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\X\X.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\X\X.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\X\autosplit.ix
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Xlib\Xlib.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Xlib\Xlib.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Xlib\Xlib.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\Xlib\Xlib.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\autosplit.ix
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\break.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\focusFollowsMouse.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\focusNext.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\focusPrev.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\interps.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\lsearch.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\pTk\extralibs.ld
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\tabFocus.al
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Tk\updateWidgets.al
+C:\mdewsnip\perl-5.6.1\site\lib\fix_4_os2.pl
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/CancelRepeat.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/CancelRepeat.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/CancelRepeat.al	(revision 14139)
@@ -0,0 +1,15 @@
+# NOTE: Derived from blib\lib\Tk.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk;
+
+#line 405 "blib\lib\Tk.pm (autosplit into blib\lib\auto\Tk\CancelRepeat.al)"
+sub CancelRepeat
+{
+ my $w = shift->MainWindow;
+ my $id = delete $w->{_afterId_};
+ $w->after('cancel',$id) if (defined $id);
+}
+
+# end of Tk::CancelRepeat
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Clipboard/autosplit.ix
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Clipboard/autosplit.ix	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Clipboard/autosplit.ix	(revision 14139)
@@ -0,0 +1,6 @@
+# Index created by AutoSplit for blib\lib\Tk\Clipboard.pm
+#    (file acts as timestamp)
+package Tk::Clipboard;
+sub getSelected 
+;
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Clipboard/getSelected.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Clipboard/getSelected.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Clipboard/getSelected.al	(revision 14139)
@@ -0,0 +1,15 @@
+# NOTE: Derived from blib\lib\Tk\Clipboard.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Clipboard;
+
+#line 103 "blib\lib\Tk\Clipboard.pm (autosplit into blib\lib\auto\Tk\Clipboard\getSelected.al)"
+sub getSelected
+{
+ my $w   = shift;
+ my $val = Tk::catch { $w->get('sel.first','sel.last') };
+ return $val;
+}
+
+1;
+# end of Tk::Clipboard::getSelected
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/EnterFocus.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/EnterFocus.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/EnterFocus.al	(revision 14139)
@@ -0,0 +1,26 @@
+# NOTE: Derived from blib\lib\Tk.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk;
+
+#line 568 "blib\lib\Tk.pm (autosplit into blib\lib\auto\Tk\EnterFocus.al)"
+# focusFollowsMouse
+#
+# If this procedure is invoked, Tk will enter "focus-follows-mouse"
+# mode, where the focus is always on whatever window contains the
+# mouse. If this procedure isn't invoked, then the user typically
+# has to click on a window to give it the focus.
+#
+# Arguments:
+# None.
+
+sub EnterFocus
+{
+ my $w  = shift;
+ my $Ev = $w->XEvent;
+ my $d  = $Ev->d;
+ $w->Tk::focus() if ($d eq 'NotifyAncestor' ||  $d eq 'NotifyNonlinear' ||  $d eq 'NotifyInferior');
+}
+
+# end of Tk::EnterFocus
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Error.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Error.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Error.al	(revision 14139)
@@ -0,0 +1,20 @@
+# NOTE: Derived from blib\lib\Tk.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk;
+
+#line 393 "blib\lib\Tk.pm (autosplit into blib\lib\auto\Tk\Error.al)"
+sub Error
+{my $w = shift;
+ my $error = shift;
+ if (Exists($w))
+  {
+   my $grab = $w->grab('current');
+   $grab->Unbusy if (defined $grab);
+  }
+ chomp($error);
+ warn "Tk::Error: $error\n " . join("\n ",@_)."\n";
+}
+
+# end of Tk::Error
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/FirstMenu.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/FirstMenu.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/FirstMenu.al	(revision 14139)
@@ -0,0 +1,21 @@
+# NOTE: Derived from blib\lib\Tk.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk;
+
+#line 615 "blib\lib\Tk.pm (autosplit into blib\lib\auto\Tk\FirstMenu.al)"
+# tkFirstMenu --
+# This procedure traverses to the first menubutton in the toplevel
+# for a given window, and posts that menubutton's menu.
+#
+# Arguments:
+# w - Name of a window. Selects which toplevel
+# to search for menubuttons.
+sub FirstMenu
+{
+ my $w = shift;
+ $w = $w->toplevel->FindMenu('');
+}
+
+# end of Tk::FirstMenu
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/FocusChildren.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/FocusChildren.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/FocusChildren.al	(revision 14139)
@@ -0,0 +1,35 @@
+# NOTE: Derived from blib\lib\Tk.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk;
+
+#line 422 "blib\lib\Tk.pm (autosplit into blib\lib\auto\Tk\FocusChildren.al)"
+#----------------------------------------------------------------------------
+# focus.tcl --
+#
+# This file defines several procedures for managing the input
+# focus.
+#
+# @(#) focus.tcl 1.6 94/12/19 17:06:46
+#
+# Copyright (c) 1994 Sun Microsystems, Inc.
+#
+# See the file "license.terms" for information on usage and redistribution
+# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+
+sub FocusChildren { shift->children }
+
+#
+# focusNext --
+# This procedure is invoked to move the input focus to the next window
+# after a given one. "Next" is defined in terms of the window
+# stacking order, with all the windows underneath a given top-level
+# (no matter how deeply nested in the hierarchy) considered except
+# for frames and toplevels.
+#
+# Arguments:
+# w - Name of a window: the procedure will set the focus
+# to the next window after this one in the traversal
+# order.
+# end of Tk::FocusChildren
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/FocusOK.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/FocusOK.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/FocusOK.al	(revision 14139)
@@ -0,0 +1,33 @@
+# NOTE: Derived from blib\lib\Tk.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk;
+
+#line 542 "blib\lib\Tk.pm (autosplit into blib\lib\auto\Tk\FocusOK.al)"
+sub FocusOK
+{
+ my $w = shift;
+ my $value;
+ catch { $value = $w->cget('-takefocus') };
+ if (!$@ && defined($value))
+  {
+   return 0 if ($value eq '0');
+   return $w->viewable if ($value eq '1');
+   $value = $w->$value();
+   return $value if (defined $value);
+  }
+ if (!$w->viewable)
+  {
+   return 0;
+  }
+ catch { $value = $w->cget('-state') } ;
+ if (!$@ && defined($value) && $value eq 'disabled')
+  {
+   return 0;
+  }
+ $value = grep(/Key|Focus/,$w->Tk::bind(),$w->Tk::bind(ref($w)));
+ return $value;
+}
+
+# end of Tk::FocusOK
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/AddScrollbars.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/AddScrollbars.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/AddScrollbars.al	(revision 14139)
@@ -0,0 +1,52 @@
+# NOTE: Derived from blib\lib\Tk\Frame.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Frame;
+
+#line 221 "blib\lib\Tk\Frame.pm (autosplit into blib\lib\auto\Tk\Frame\AddScrollbars.al)"
+sub AddScrollbars
+{
+ require Tk::Scrollbar;
+ my ($cw,$w) = @_;
+ my $def = '';
+ my ($x,$y) = ('','');
+ my $s = 0;
+ my $c;
+ $cw->freeze_on_map;
+ foreach $c ($w->configure)
+  {
+   my $opt = $c->[0];
+   if ($opt eq '-yscrollcommand')
+    {
+     my $slice  = Tk::Frame->new($cw,Name => 'ysbslice');
+     my $ysb    = Tk::Scrollbar->new($slice,-orient => 'vertical', -command => [ 'yview', $w ]);
+     my $size   = $ysb->cget('-width');
+     my $corner = Tk::Frame->new($slice,Name=>'corner','-relief' => 'raised',
+                  '-width' => $size, '-height' => $size);
+     $ysb->pack(-side => 'left', -fill => 'y');
+     $cw->Advertise('yscrollbar' => $ysb);
+     $cw->Advertise('corner' => $corner);
+     $cw->Advertise('ysbslice' => $slice);
+     $corner->{'before'} = $ysb->PathName;
+     $slice->{'before'} = $w->PathName;
+     $y = 'w';
+     $s = 1;
+    }
+   elsif ($opt eq '-xscrollcommand')
+    {
+     my $xsb = Tk::Scrollbar->new($cw,-orient => 'horizontal', -command => [ 'xview', $w ]);
+     $cw->Advertise('xscrollbar' => $xsb);
+     $xsb->{'before'} = $w->PathName;
+     $x = 's';
+     $s = 1;
+    }
+  }
+ if ($s)
+  {
+   $cw->Advertise('scrolled' => $w);
+   $cw->ConfigSpecs('-scrollbars' => ['METHOD','scrollbars','Scrollbars',$x.$y]);
+  }
+}
+
+# end of Tk::Frame::AddScrollbars
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/FindMenu.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/FindMenu.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/FindMenu.al	(revision 14139)
@@ -0,0 +1,22 @@
+# NOTE: Derived from blib\lib\Tk\Frame.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Frame;
+
+#line 359 "blib\lib\Tk\Frame.pm (autosplit into blib\lib\auto\Tk\Frame\FindMenu.al)"
+sub FindMenu
+{
+ my ($w,$char) = @_;
+ my $child;
+ my $match;
+ foreach $child ($w->children)
+  {
+   next unless (ref $child);
+   $match = $child->FindMenu($char);
+   return $match if (defined $match);
+  }
+ return undef;
+}
+
+1;
+# end of Tk::Frame::FindMenu
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/autosplit.ix
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/autosplit.ix	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/autosplit.ix	(revision 14139)
@@ -0,0 +1,24 @@
+# Index created by AutoSplit for blib\lib\Tk\Frame.pm
+#    (file acts as timestamp)
+package Tk::Frame;
+sub labelPack 
+;
+sub labelVariable 
+;
+sub label 
+;
+sub queuePack 
+;
+sub sbset 
+;
+sub freeze_on_map 
+;
+sub AddScrollbars 
+;
+sub packscrollbars 
+;
+sub scrollbars 
+;
+sub FindMenu 
+;
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/freeze_on_map.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/freeze_on_map.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/freeze_on_map.al	(revision 14139)
@@ -0,0 +1,18 @@
+# NOTE: Derived from blib\lib\Tk\Frame.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Frame;
+
+#line 211 "blib\lib\Tk\Frame.pm (autosplit into blib\lib\auto\Tk\Frame\freeze_on_map.al)"
+sub freeze_on_map
+{
+ my ($w) = @_;
+ unless ($w->Tk::bind('Freeze','<Map>'))
+  {
+   $w->Tk::bind('Freeze','<Map>',['packPropagate' => 0])
+  }
+ $w->AddBindTag('Freeze');
+}
+
+# end of Tk::Frame::freeze_on_map
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/label.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/label.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/label.al	(revision 14139)
@@ -0,0 +1,24 @@
+# NOTE: Derived from blib\lib\Tk\Frame.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Frame;
+
+#line 178 "blib\lib\Tk\Frame.pm (autosplit into blib\lib\auto\Tk\Frame\label.al)"
+sub label
+{
+ my ($cw,$val) = @_;
+ my $var = $cw->cget('-labelVariable');
+ if (@_ > 1 && defined $val)
+  {
+   if (!defined $var)
+    {
+     $var = \$cw->{Configure}{'-label'};
+     $cw->labelVariable($var);
+    }
+   $$var = $val;
+  }
+ return (defined $var) ? $$var : undef;;
+}
+
+# end of Tk::Frame::label
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/labelPack.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/labelPack.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/labelPack.al	(revision 14139)
@@ -0,0 +1,50 @@
+# NOTE: Derived from blib\lib\Tk\Frame.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Frame;
+
+#line 117 "blib\lib\Tk\Frame.pm (autosplit into blib\lib\auto\Tk\Frame\labelPack.al)"
+sub labelPack
+{
+ my ($cw,$val) = @_;
+ my $w = $cw->Subwidget('label');
+ my @result = ();
+ if (@_ > 1)
+  {
+   if (defined($w) && !defined($val))
+    {
+     $w->packForget;
+    }
+   elsif (defined($val) && !defined ($w))
+    {
+     require Tk::Label;
+     $w = Tk::Label->new($cw,-textvariable => $cw->labelVariable);
+     $cw->Advertise('label' => $w);
+     $cw->ConfigDelegate('label',qw(-text -textvariable));
+    }
+   if (defined($val) && defined($w))
+    {
+     my %pack = @$val;
+     unless (exists $pack{-side})
+      {
+       $pack{-side} = 'top' unless (exists $pack{-side});
+      }
+     unless (exists $pack{-fill})
+      {
+       $pack{-fill} = 'x' if ($pack{-side} =~ /(top|bottom)/);
+       $pack{-fill} = 'y' if ($pack{-side} =~ /(left|right)/);
+      }
+     unless (exists($pack{'-before'}) || exists($pack{'-after'}))
+      {
+       my $before = ($cw->packSlaves)[0];
+       $pack{'-before'} = $before if (defined $before);
+      }
+     $w->pack(%pack);
+    }
+  }
+ @result = $w->packInfo if (defined $w);
+ return (wantarray) ? @result : \@result;
+}
+
+# end of Tk::Frame::labelPack
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/labelVariable.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/labelVariable.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/labelVariable.al	(revision 14139)
@@ -0,0 +1,27 @@
+# NOTE: Derived from blib\lib\Tk\Frame.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Frame;
+
+#line 159 "blib\lib\Tk\Frame.pm (autosplit into blib\lib\auto\Tk\Frame\labelVariable.al)"
+sub labelVariable
+{
+ my ($cw,$val) = @_;
+ my $var = \$cw->{Configure}{'-labelVariable'};
+ if (@_ > 1 && defined $val)
+  {
+   $$var = $val;
+   $$val = '' unless (defined $$val);
+   my $w = $cw->Subwidget('label');
+   unless (defined $w)
+    {
+     $cw->labelPack([]);
+     $w = $cw->Subwidget('label');
+    }
+   $w->configure(-textvariable => $val);
+  }
+ return $$var;
+}
+
+# end of Tk::Frame::labelVariable
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/packscrollbars.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/packscrollbars.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/packscrollbars.al	(revision 14139)
@@ -0,0 +1,86 @@
+# NOTE: Derived from blib\lib\Tk\Frame.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Frame;
+
+#line 265 "blib\lib\Tk\Frame.pm (autosplit into blib\lib\auto\Tk\Frame\packscrollbars.al)"
+sub packscrollbars
+{
+ my ($cw) = @_;
+ my $opt    = $cw->cget('-scrollbars');
+ my $slice  = $cw->Subwidget('ysbslice');
+ my $xsb    = $cw->Subwidget('xscrollbar');
+ my $corner = $cw->Subwidget('corner');
+ my $w      = $cw->Subwidget('scrolled');
+ my $xside  = (($opt =~ /n/) ? 'top' : 'bottom');
+ my $havex  = 0;
+ my $havey  = 0;
+ $opt =~ s/r//;
+ $cw->{'pack_pending'} = 0;
+ if (defined $slice)
+  {
+   my $reqy;
+   my $ysb    = $cw->Subwidget('yscrollbar');
+   if ($opt =~ /(o)?[we]/ && (($reqy = !defined($1)) || $ysb->Needed))
+    {
+     my $yside = (($opt =~ /w/) ? 'left' : 'right');
+     $slice->pack(-side => $yside, -fill => 'y',-before => $slice->{'before'});
+     $havey = 1;
+     if ($reqy)
+      {
+       $w->configure(-yscrollcommand => ['set', $ysb]);
+      }
+     else
+      {
+       $w->configure(-yscrollcommand => ['sbset', $cw, $ysb, \$cw->{'packysb'}]);
+      }
+    }
+   else
+    {
+     $w->configure(-yscrollcommand => undef) unless $opt =~ s/[we]//;
+     $slice->packForget;
+    }
+   $cw->{'packysb'} = $havey;
+  }
+ if (defined $xsb)
+  {
+   my $reqx;
+   if ($opt =~ /(o)?[ns]/ && (($reqx = !defined($1)) || $xsb->Needed))
+    {
+     $xsb->pack(-side => $xside, -fill => 'x',-before => $xsb->{'before'});
+     $havex = 1;
+     if ($reqx)
+      {
+       $w->configure(-xscrollcommand => ['set', $xsb]);
+      }
+     else
+      {
+       $w->configure(-xscrollcommand => ['sbset', $cw, $xsb, \$cw->{'packxsb'}]);
+      }
+    }
+   else
+    {
+     $w->configure(-xscrollcommand => undef) unless $opt =~ s/[ns]//;
+     $xsb->packForget;
+    }
+   $cw->{'packxsb'} = $havex;
+  }
+ if (defined $corner)
+  {
+   if ($havex && $havey && defined $corner->{'before'})
+    {
+     my $anchor = $opt;
+     $anchor =~ s/o//g;
+     $corner->configure(-height => $xsb->ReqHeight);
+     $corner->pack(-before => $corner->{'before'}, -side => $xside,
+                   -anchor => $anchor, -fill => 'x');
+    }
+   else
+    {
+     $corner->packForget;
+    }
+  }
+}
+
+# end of Tk::Frame::packscrollbars
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/queuePack.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/queuePack.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/queuePack.al	(revision 14139)
@@ -0,0 +1,18 @@
+# NOTE: Derived from blib\lib\Tk\Frame.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Frame;
+
+#line 194 "blib\lib\Tk\Frame.pm (autosplit into blib\lib\auto\Tk\Frame\queuePack.al)"
+sub queuePack
+{
+ my ($cw) = @_;
+ unless ($cw->{'pack_pending'})
+  {
+   $cw->{'pack_pending'} = 1;
+   $cw->afterIdle([$cw,'packscrollbars']);
+  }
+}
+
+# end of Tk::Frame::queuePack
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/sbset.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/sbset.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/sbset.al	(revision 14139)
@@ -0,0 +1,15 @@
+# NOTE: Derived from blib\lib\Tk\Frame.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Frame;
+
+#line 204 "blib\lib\Tk\Frame.pm (autosplit into blib\lib\auto\Tk\Frame\sbset.al)"
+sub sbset
+{
+ my ($cw,$sb,$ref,@args) = @_;
+ $sb->set(@args);
+ $cw->queuePack if (@args == 2 && $sb->Needed != $$ref);
+}
+
+# end of Tk::Frame::sbset
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/scrollbars.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/scrollbars.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Frame/scrollbars.al	(revision 14139)
@@ -0,0 +1,24 @@
+# NOTE: Derived from blib\lib\Tk\Frame.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Frame;
+
+#line 343 "blib\lib\Tk\Frame.pm (autosplit into blib\lib\auto\Tk\Frame\scrollbars.al)"
+sub scrollbars
+{
+ my ($cw,$opt) = @_;
+ my $var = \$cw->{'-scrollbars'};
+ if (@_ > 1)
+  {
+   my $old = $$var;
+   if (!defined $old || $old ne $opt)
+    {
+     $$var = $opt;
+     $cw->queuePack;
+    }
+  }
+ return $$var;
+}
+
+# end of Tk::Frame::scrollbars
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/ImageNames.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/ImageNames.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/ImageNames.al	(revision 14139)
@@ -0,0 +1,13 @@
+# NOTE: Derived from blib\lib\Tk.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk;
+
+#line 667 "blib\lib\Tk.pm (autosplit into blib\lib\auto\Tk\ImageNames.al)"
+sub ImageNames
+{
+ image('names');
+}
+
+# end of Tk::ImageNames
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/ImageTypes.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/ImageTypes.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/ImageTypes.al	(revision 14139)
@@ -0,0 +1,13 @@
+# NOTE: Derived from blib\lib\Tk.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk;
+
+#line 672 "blib\lib\Tk.pm (autosplit into blib\lib\auto\Tk\ImageTypes.al)"
+sub ImageTypes
+{
+ image('types');
+}
+
+# end of Tk::ImageTypes
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/AutoScan.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/AutoScan.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/AutoScan.al	(revision 14139)
@@ -0,0 +1,48 @@
+# NOTE: Derived from ..\blib\lib\Tk\Listbox.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Listbox;
+
+#line 634 "..\blib\lib\Tk\Listbox.pm (autosplit into ..\blib\lib\auto\Tk\Listbox\AutoScan.al)"
+# AutoScan --
+# This procedure is invoked when the mouse leaves an entry window
+# with button 1 down. It scrolls the window up, down, left, or
+# right, depending on where the mouse left the window, and reschedules
+# itself as an "after" command so that the window continues to scroll until
+# the mouse moves back into the window or the mouse button is released.
+#
+# Arguments:
+# w - The entry window.
+# x - The x-coordinate of the mouse when it left the window.
+# y - The y-coordinate of the mouse when it left the window.
+sub AutoScan
+{
+ my $w = shift;
+ my $x = shift;
+ my $y = shift;
+ if ($y >= $w->height)
+  {
+   $w->yview('scroll',1,'units')
+  }
+ elsif ($y < 0)
+  {
+   $w->yview('scroll',-1,'units')
+  }
+ elsif ($x >= $w->width)
+  {
+   $w->xview('scroll',2,'units')
+  }
+ elsif ($x < 0)
+  {
+   $w->xview('scroll',-2,'units')
+  }
+ else
+  {
+   return;
+  }
+ $w->Motion($w->index("@" . $x . ',' . $y));
+ $w->RepeatId($w->after(50,'AutoScan',$w,$x,$y));
+}
+
+# end of Tk::Listbox::AutoScan
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/BeginExtend.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/BeginExtend.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/BeginExtend.al	(revision 14139)
@@ -0,0 +1,29 @@
+# NOTE: Derived from ..\blib\lib\Tk\Listbox.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Listbox;
+
+#line 584 "..\blib\lib\Tk\Listbox.pm (autosplit into ..\blib\lib\auto\Tk\Listbox\BeginExtend.al)"
+# BeginExtend --
+#
+# This procedure is typically invoked on shift-button-1 presses. It
+# begins the process of extending a selection in the listbox. Its
+# exact behavior depends on the selection mode currently in effect
+# for the listbox; see the Motif documentation for details.
+#
+# Arguments:
+# w - The listbox widget.
+# el - The element for the selection operation (typically the
+# one under the pointer). Must be in numerical form.
+sub BeginExtend
+{
+ my $w = shift;
+ my $el = shift;
+ if ($w->cget('-selectmode') eq 'extended' && $w->selectionIncludes('anchor'))
+  {
+   $w->Motion($el)
+  }
+}
+
+# end of Tk::Listbox::BeginExtend
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/BeginSelect.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/BeginSelect.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/BeginSelect.al	(revision 14139)
@@ -0,0 +1,45 @@
+# NOTE: Derived from ..\blib\lib\Tk\Listbox.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Listbox;
+
+#line 491 "..\blib\lib\Tk\Listbox.pm (autosplit into ..\blib\lib\auto\Tk\Listbox\BeginSelect.al)"
+# BeginSelect --
+#
+# This procedure is typically invoked on button-1 presses. It begins
+# the process of making a selection in the listbox. Its exact behavior
+# depends on the selection mode currently in effect for the listbox;
+# see the Motif documentation for details.
+#
+# Arguments:
+# w - The listbox widget.
+# el - The element for the selection operation (typically the
+# one under the pointer). Must be in numerical form.
+sub BeginSelect
+{
+ my $w = shift;
+ my $el = shift;
+ if ($w->cget('-selectmode') eq 'multiple')
+  {
+   if ($w->selectionIncludes($el))
+    {
+     $w->selectionClear($el)
+    }
+   else
+    {
+     $w->selectionSet($el)
+    }
+  }
+ else
+  {
+   $w->selectionClear(0,'end');
+   $w->selectionSet($el);
+   $w->selectionAnchor($el);
+   @Selection = ();
+   $Prev = $el
+  }
+ $w->focus if ($w->cget('-takefocus'));
+}
+
+# end of Tk::Listbox::BeginSelect
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/BeginToggle.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/BeginToggle.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/BeginToggle.al	(revision 14139)
@@ -0,0 +1,39 @@
+# NOTE: Derived from ..\blib\lib\Tk\Listbox.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Listbox;
+
+#line 604 "..\blib\lib\Tk\Listbox.pm (autosplit into ..\blib\lib\auto\Tk\Listbox\BeginToggle.al)"
+# BeginToggle --
+#
+# This procedure is typically invoked on control-button-1 presses. It
+# begins the process of toggling a selection in the listbox. Its
+# exact behavior depends on the selection mode currently in effect
+# for the listbox; see the Motif documentation for details.
+#
+# Arguments:
+# w - The listbox widget.
+# el - The element for the selection operation (typically the
+# one under the pointer). Must be in numerical form.
+sub BeginToggle
+{
+ my $w = shift;
+ my $el = shift;
+ if ($w->cget('-selectmode') eq 'extended')
+  {
+   @Selection = $w->curselection();
+   $Prev = $el;
+   $w->selectionAnchor($el);
+   if ($w->selectionIncludes($el))
+    {
+     $w->selectionClear($el)
+    }
+   else
+    {
+     $w->selectionSet($el)
+    }
+  }
+}
+
+# end of Tk::Listbox::BeginToggle
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/ButtonRelease_1.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/ButtonRelease_1.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/ButtonRelease_1.al	(revision 14139)
@@ -0,0 +1,16 @@
+# NOTE: Derived from ..\blib\lib\Tk\Listbox.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Listbox;
+
+#line 450 "..\blib\lib\Tk\Listbox.pm (autosplit into ..\blib\lib\auto\Tk\Listbox\ButtonRelease_1.al)"
+sub ButtonRelease_1
+{
+ my $w = shift;
+ my $Ev = $w->XEvent;
+ $w->CancelRepeat;
+ $w->activate($Ev->xy);
+}
+
+# end of Tk::Listbox::ButtonRelease_1
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/Cancel.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/Cancel.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/Cancel.al	(revision 14139)
@@ -0,0 +1,43 @@
+# NOTE: Derived from ..\blib\lib\Tk\Listbox.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Listbox;
+
+#line 754 "..\blib\lib\Tk\Listbox.pm (autosplit into ..\blib\lib\auto\Tk\Listbox\Cancel.al)"
+# Cancel
+#
+# This procedure is invoked to cancel an extended selection in
+# progress. If there is an extended selection in progress, it
+# restores all of the items between the active one and the anchor
+# to their previous selection state.
+#
+# Arguments:
+# w - The listbox widget.
+sub Cancel
+{
+ my $w = shift;
+ if ($w->cget('-selectmode') ne 'extended' || !defined $Prev)
+  {
+   return;
+  }
+ $first = $w->index('anchor');
+ $last = $Prev;
+ if ($first > $last)
+  {
+   $tmp = $first;
+   $first = $last;
+   $last = $tmp
+  }
+ $w->selectionClear($first,$last);
+ while ($first <= $last)
+  {
+   if (Tk::lsearch(\@Selection,$first) >= 0)
+    {
+     $w->selectionSet($first)
+    }
+   $first += 1
+  }
+}
+
+# end of Tk::Listbox::Cancel
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/Cntrl_End.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/Cntrl_End.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/Cntrl_End.al	(revision 14139)
@@ -0,0 +1,18 @@
+# NOTE: Derived from ..\blib\lib\Tk\Listbox.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Listbox;
+
+#line 470 "..\blib\lib\Tk\Listbox.pm (autosplit into ..\blib\lib\auto\Tk\Listbox\Cntrl_End.al)"
+sub Cntrl_End
+{
+ my $w = shift;
+ my $Ev = $w->XEvent;
+ $w->activate('end');
+ $w->see('end');
+ $w->selectionClear(0,'end');
+ $w->selectionSet('end')
+}
+
+# end of Tk::Listbox::Cntrl_End
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/Cntrl_Home.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/Cntrl_Home.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/Cntrl_Home.al	(revision 14139)
@@ -0,0 +1,18 @@
+# NOTE: Derived from ..\blib\lib\Tk\Listbox.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Listbox;
+
+#line 459 "..\blib\lib\Tk\Listbox.pm (autosplit into ..\blib\lib\auto\Tk\Listbox\Cntrl_Home.al)"
+sub Cntrl_Home
+{
+ my $w = shift;
+ my $Ev = $w->XEvent;
+ $w->activate(0);
+ $w->see(0);
+ $w->selectionClear(0,'end');
+ $w->selectionSet(0)
+}
+
+# end of Tk::Listbox::Cntrl_Home
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/Cntrl_backslash.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/Cntrl_backslash.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/Cntrl_backslash.al	(revision 14139)
@@ -0,0 +1,18 @@
+# NOTE: Derived from ..\blib\lib\Tk\Listbox.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Listbox;
+
+#line 481 "..\blib\lib\Tk\Listbox.pm (autosplit into ..\blib\lib\auto\Tk\Listbox\Cntrl_backslash.al)"
+sub Cntrl_backslash
+{
+ my $w = shift;
+ my $Ev = $w->XEvent;
+ if ($w->cget('-selectmode') ne 'browse')
+ {
+ $w->selectionClear(0,'end');
+ }
+}
+
+# end of Tk::Listbox::Cntrl_backslash
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/DataExtend.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/DataExtend.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/DataExtend.al	(revision 14139)
@@ -0,0 +1,39 @@
+# NOTE: Derived from ..\blib\lib\Tk\Listbox.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Listbox;
+
+#line 724 "..\blib\lib\Tk\Listbox.pm (autosplit into ..\blib\lib\auto\Tk\Listbox\DataExtend.al)"
+# DataExtend
+#
+# This procedure is called for key-presses such as Shift-KEndData.
+# If the selection mode isn't multiple or extend then it does nothing.
+# Otherwise it moves the active element to el and, if we're in
+# extended mode, extends the selection to that point.
+#
+# Arguments:
+# w - The listbox widget.
+# el - An integer element number.
+sub DataExtend
+{
+ my $w = shift;
+ my $el = shift;
+ $mode = $w->cget('-selectmode');
+ if ($mode eq 'extended')
+  {
+   $w->activate($el);
+   $w->see($el);
+   if ($w->selectionIncludes('anchor'))
+    {
+     $w->Motion($el)
+    }
+  }
+ elsif ($mode eq 'multiple')
+  {
+   $w->activate($el);
+   $w->see($el)
+  }
+}
+
+# end of Tk::Listbox::DataExtend
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/ExtendUpDown.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/ExtendUpDown.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/ExtendUpDown.al	(revision 14139)
@@ -0,0 +1,30 @@
+# NOTE: Derived from ..\blib\lib\Tk\Listbox.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Listbox;
+
+#line 703 "..\blib\lib\Tk\Listbox.pm (autosplit into ..\blib\lib\auto\Tk\Listbox\ExtendUpDown.al)"
+# ExtendUpDown --
+#
+# Does nothing unless we're in extended selection mode; in this
+# case it moves the location cursor (active element) up or down by
+# one element, and extends the selection to that point.
+#
+# Arguments:
+# w - The listbox widget.
+# amount - +1 to move down one item, -1 to move back one item.
+sub ExtendUpDown
+{
+ my $w = shift;
+ my $amount = shift;
+ if ($w->cget('-selectmode') ne 'extended')
+  {
+   return;
+  }
+ $w->activate($w->index('active')+$amount);
+ $w->see('active');
+ $w->Motion($w->index('active'))
+}
+
+# end of Tk::Listbox::ExtendUpDown
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/Motion.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/Motion.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/Motion.al	(revision 14139)
@@ -0,0 +1,66 @@
+# NOTE: Derived from ..\blib\lib\Tk\Listbox.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Listbox;
+
+#line 527 "..\blib\lib\Tk\Listbox.pm (autosplit into ..\blib\lib\auto\Tk\Listbox\Motion.al)"
+# Motion --
+#
+# This procedure is called to process mouse motion events while
+# button 1 is down. It may move or extend the selection, depending
+# on the listbox's selection mode.
+#
+# Arguments:
+# w - The listbox widget.
+# el - The element under the pointer (must be a number).
+sub Motion
+{
+ my $w = shift;
+ my $el = shift;
+ if (defined($Prev) && $el == $Prev)
+  {
+   return;
+  }
+ $anchor = $w->index('anchor');
+ my $mode = $w->cget('-selectmode');
+ if ($mode eq 'browse')
+  {
+   $w->selectionClear(0,'end');
+   $w->selectionSet($el);
+   $Prev = $el;
+  }
+ elsif ($mode eq 'extended')
+  {
+   $i = $Prev;
+   if ($w->selectionIncludes('anchor'))
+    {
+     $w->selectionClear($i,$el);
+     $w->selectionSet('anchor',$el)
+    }
+   else
+    {
+     $w->selectionClear($i,$el);
+     $w->selectionClear('anchor',$el)
+    }
+   while ($i < $el && $i < $anchor)
+    {
+     if (Tk::lsearch(\@Selection,$i) >= 0)
+      {
+       $w->selectionSet($i)
+      }
+     $i += 1
+    }
+   while ($i > $el && $i > $anchor)
+    {
+     if (Tk::lsearch(\@Selection,$i) >= 0)
+      {
+       $w->selectionSet($i)
+      }
+     $i += -1
+    }
+   $Prev = $el
+  }
+}
+
+# end of Tk::Listbox::Motion
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/SelectAll.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/SelectAll.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/SelectAll.al	(revision 14139)
@@ -0,0 +1,31 @@
+# NOTE: Derived from ..\blib\lib\Tk\Listbox.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Listbox;
+
+#line 788 "..\blib\lib\Tk\Listbox.pm (autosplit into ..\blib\lib\auto\Tk\Listbox\SelectAll.al)"
+# SelectAll
+#
+# This procedure is invoked to handle the "select all" operation.
+# For single and browse mode, it just selects the active element.
+# Otherwise it selects everything in the widget.
+#
+# Arguments:
+# w - The listbox widget.
+sub SelectAll
+{
+ my $w = shift;
+ my $mode = $w->cget('-selectmode');
+ if ($mode eq 'single' || $mode eq 'browse')
+  {
+   $w->selectionClear(0,'end');
+   $w->selectionSet('active')
+  }
+ else
+  {
+   $w->selectionSet(0,'end')
+  }
+}
+
+# end of Tk::Listbox::SelectAll
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/SetList.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/SetList.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/SetList.al	(revision 14139)
@@ -0,0 +1,15 @@
+# NOTE: Derived from ..\blib\lib\Tk\Listbox.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Listbox;
+
+#line 811 "..\blib\lib\Tk\Listbox.pm (autosplit into ..\blib\lib\auto\Tk\Listbox\SetList.al)"
+sub SetList
+{
+ my $w = shift;
+ $w->delete(0,'end');
+ $w->insert('end',@_);
+}
+
+# end of Tk::Listbox::SetList
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/UpDown.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/UpDown.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/UpDown.al	(revision 14139)
@@ -0,0 +1,39 @@
+# NOTE: Derived from ..\blib\lib\Tk\Listbox.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Listbox;
+
+#line 673 "..\blib\lib\Tk\Listbox.pm (autosplit into ..\blib\lib\auto\Tk\Listbox\UpDown.al)"
+# UpDown --
+#
+# Moves the location cursor (active element) up or down by one element,
+# and changes the selection if we're in browse or extended selection
+# mode.
+#
+# Arguments:
+# w - The listbox widget.
+# amount - +1 to move down one item, -1 to move back one item.
+sub UpDown
+{
+ my $w = shift;
+ my $amount = shift;
+ $w->activate($w->index('active')+$amount);
+ $w->see('active');
+ $LNet__0 = $w->cget('-selectmode');
+ if ($LNet__0 eq 'browse')
+  {
+   $w->selectionClear(0,'end');
+   $w->selectionSet('active')
+  }
+ elsif ($LNet__0 eq 'extended')
+  {
+   $w->selectionClear(0,'end');
+   $w->selectionSet('active');
+   $w->selectionAnchor('active');
+   $Prev = $w->index('active');
+   @Selection = ();
+  }
+}
+
+# end of Tk::Listbox::UpDown
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/autosplit.ix
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/autosplit.ix	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/autosplit.ix	(revision 14139)
@@ -0,0 +1,42 @@
+# Index created by AutoSplit for ..\blib\lib\Tk\Listbox.pm
+#    (file acts as timestamp)
+package Tk::Listbox;
+sub xyIndex 
+;
+sub ButtonRelease_1 
+;
+sub Cntrl_Home 
+;
+sub Cntrl_End 
+;
+sub Cntrl_backslash 
+;
+sub BeginSelect 
+;
+sub Motion 
+;
+sub BeginExtend 
+;
+sub BeginToggle 
+;
+sub AutoScan 
+;
+sub UpDown 
+;
+sub ExtendUpDown 
+;
+sub DataExtend 
+;
+sub Cancel 
+;
+sub SelectAll 
+;
+sub SetList 
+;
+sub deleteSelected 
+;
+sub clipboardPaste 
+;
+sub getSelected 
+;
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/clipboardPaste.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/clipboardPaste.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/clipboardPaste.al	(revision 14139)
@@ -0,0 +1,21 @@
+# NOTE: Derived from ..\blib\lib\Tk\Listbox.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Listbox;
+
+#line 828 "..\blib\lib\Tk\Listbox.pm (autosplit into ..\blib\lib\auto\Tk\Listbox\clipboardPaste.al)"
+sub clipboardPaste
+{
+ my $w = shift;
+ my $index = $w->index('active') || $w->index($w->XEvent->xy);
+ my $str;
+ eval {local $SIG{__DIE__}; $str = $w->clipboardGet };
+ return if $@;
+ foreach (split("\n",$str))
+  {
+   $w->insert($index++,$_);
+  }
+}
+
+# end of Tk::Listbox::clipboardPaste
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/deleteSelected.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/deleteSelected.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/deleteSelected.al	(revision 14139)
@@ -0,0 +1,18 @@
+# NOTE: Derived from ..\blib\lib\Tk\Listbox.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Listbox;
+
+#line 818 "..\blib\lib\Tk\Listbox.pm (autosplit into ..\blib\lib\auto\Tk\Listbox\deleteSelected.al)"
+sub deleteSelected
+{
+ my $w = shift;
+ my $i;
+ foreach $i (reverse $w->curselection)
+  {
+   $w->delete($i);
+  }
+}
+
+# end of Tk::Listbox::deleteSelected
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/getSelected.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/getSelected.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/getSelected.al	(revision 14139)
@@ -0,0 +1,22 @@
+# NOTE: Derived from ..\blib\lib\Tk\Listbox.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Listbox;
+
+#line 841 "..\blib\lib\Tk\Listbox.pm (autosplit into ..\blib\lib\auto\Tk\Listbox\getSelected.al)"
+sub getSelected
+{
+ my ($w) = @_;
+ my $i;
+ my (@result) = ();
+ foreach $i ($w->curselection)
+  {
+   push(@result,$w->get($i));
+  }
+ return (wantarray) ? @result : $result[0];
+}
+
+1;
+__END__
+1;
+# end of Tk::Listbox::getSelected
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/xyIndex.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/xyIndex.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Listbox/xyIndex.al	(revision 14139)
@@ -0,0 +1,27 @@
+# NOTE: Derived from ..\blib\lib\Tk\Listbox.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Listbox;
+
+#line 431 "..\blib\lib\Tk\Listbox.pm (autosplit into ..\blib\lib\auto\Tk\Listbox\xyIndex.al)"
+#
+# Bind --
+# This procedure is invoked the first time the mouse enters a listbox
+# widget or a listbox widget receives the input focus. It creates
+# all of the class bindings for listboxes.
+#
+# Arguments:
+# event - Indicates which event caused the procedure to be invoked
+# (Enter or FocusIn). It is used so that we can carry out
+# the functions of that event in addition to setting up
+# bindings.
+
+sub xyIndex
+{
+ my $w = shift;
+ my $Ev = $w->XEvent;
+ return $w->index($Ev->xy);
+}
+
+# end of Tk::Listbox::xyIndex
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Receive.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Receive.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Receive.al	(revision 14139)
@@ -0,0 +1,23 @@
+# NOTE: Derived from blib\lib\Tk.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk;
+
+#line 638 "blib\lib\Tk.pm (autosplit into blib\lib\auto\Tk\Receive.al)"
+# If we have sub Clipboard in Tk then use base qw(Tk::Clipboard ....)
+# calls it when it does its eval "require $base"
+#sub Clipboard
+#{my $w = shift;
+# my $cmd    = shift;
+# croak "Use clipboard\u$cmd()";
+#}
+
+sub Receive
+{
+ my $w = shift;
+ warn 'Receive(' . join(',',@_) .')';
+ die 'Tk rejects send(' . join(',',@_) .")\n";
+}
+
+# end of Tk::Receive
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/RepeatId.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/RepeatId.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/RepeatId.al	(revision 14139)
@@ -0,0 +1,16 @@
+# NOTE: Derived from blib\lib\Tk.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk;
+
+#line 412 "blib\lib\Tk.pm (autosplit into blib\lib\auto\Tk\RepeatId.al)"
+sub RepeatId
+{
+ my ($w,$id) = @_;
+ $w = $w->MainWindow;
+ $w->CancelRepeat;
+ $w->{_afterId_} = $id;
+}
+
+# end of Tk::RepeatId
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scale/Activate.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scale/Activate.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scale/Activate.al	(revision 14139)
@@ -0,0 +1,33 @@
+# NOTE: Derived from ..\blib\lib\Tk\Scale.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Scale;
+
+#line 86 "..\blib\lib\Tk\Scale.pm (autosplit into ..\blib\lib\auto\Tk\Scale\Activate.al)"
+# Activate --
+# This procedure is invoked to check a given x-y position in the
+# scale and activate the slider if the x-y position falls within
+# the slider.
+#
+# Arguments:
+# w - The scale widget.
+# x, y - Mouse coordinates.
+sub Activate
+{
+ my $w = shift;
+ my $x = shift;
+ my $y = shift;
+ return if ($w->cget('-state') eq 'disabled');
+ my $ident = $w->identify($x,$y);
+ if (defined($ident) && $ident eq 'slider')
+  {
+   $w->configure(-state => 'active')
+  }
+ else
+  {
+   $w->configure(-state => 'normal')
+  }
+}
+
+# end of Tk::Scale::Activate
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scale/ButtonDown.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scale/ButtonDown.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scale/ButtonDown.al	(revision 14139)
@@ -0,0 +1,40 @@
+# NOTE: Derived from ..\blib\lib\Tk\Scale.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Scale;
+
+#line 138 "..\blib\lib\Tk\Scale.pm (autosplit into ..\blib\lib\auto\Tk\Scale\ButtonDown.al)"
+# ButtonDown --
+# This procedure is invoked when a button is pressed in a scale. It
+# takes different actions depending on where the button was pressed.
+#
+# Arguments:
+# w - The scale widget.
+# x, y - Mouse coordinates of button press.
+sub ButtonDown
+{
+ my $w = shift;
+ my $x = shift;
+ my $y = shift;
+ $Tk::dragging = 0;
+ $el = $w->identify($x,$y);
+ return unless ($el);
+ if ($el eq 'trough1')
+  {
+   $w->Increment('up','little','initial')
+  }
+ elsif ($el eq 'trough2')
+  {
+   $w->Increment('down','little','initial')
+  }
+ elsif ($el eq 'slider')
+  {
+   $Tk::dragging = 1;
+   my @coords = $w->coords();
+   $Tk::deltaX = $x-$coords[0];
+   $Tk::deltaY = $y-$coords[1];
+  }
+}
+
+# end of Tk::Scale::ButtonDown
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scale/ButtonUp.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scale/ButtonUp.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scale/ButtonUp.al	(revision 14139)
@@ -0,0 +1,16 @@
+# NOTE: Derived from ..\blib\lib\Tk\Scale.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Scale;
+
+#line 129 "..\blib\lib\Tk\Scale.pm (autosplit into ..\blib\lib\auto\Tk\Scale\ButtonUp.al)"
+sub ButtonUp
+{
+ my ($w,$x,$y) = @_;
+ $w->CancelRepeat();
+ $w->EndDrag();
+ $w->Activate($x,$y)
+}
+
+# end of Tk::Scale::ButtonUp
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scale/ControlPress.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scale/ControlPress.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scale/ControlPress.al	(revision 14139)
@@ -0,0 +1,31 @@
+# NOTE: Derived from ..\blib\lib\Tk\Scale.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Scale;
+
+#line 255 "..\blib\lib\Tk\Scale.pm (autosplit into ..\blib\lib\auto\Tk\Scale\ControlPress.al)"
+# ControlPress --
+# This procedure handles button presses that are made with the Control
+# key down. Depending on the mouse position, it adjusts the scale
+# value to one end of the range or the other.
+#
+# Arguments:
+# w - The scale widget.
+# x, y - Mouse coordinates where the button was pressed.
+sub ControlPress
+{
+ my ($w,$x,$y) = @_;
+ my $el = $w->identify($x,$y);
+ return unless ($el);
+ if ($el eq 'trough1')
+  {
+   $w->set($w->cget('-from'))
+  }
+ elsif ($el eq 'trough2')
+  {
+   $w->set($w->cget('-to'))
+  }
+}
+
+1;
+# end of Tk::Scale::ControlPress
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scale/Drag.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scale/Drag.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scale/Drag.al	(revision 14139)
@@ -0,0 +1,29 @@
+# NOTE: Derived from ..\blib\lib\Tk\Scale.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Scale;
+
+#line 169 "..\blib\lib\Tk\Scale.pm (autosplit into ..\blib\lib\auto\Tk\Scale\Drag.al)"
+# Drag --
+# This procedure is called when the mouse is dragged with
+# mouse button 1 down. If the drag started inside the slider
+# (i.e. the scale is active) then the scale's value is adjusted
+# to reflect the mouse's position.
+#
+# Arguments:
+# w - The scale widget.
+# x, y - Mouse coordinates.
+sub Drag
+{
+ my $w = shift;
+ my $x = shift;
+ my $y = shift;
+ if (!$Tk::dragging)
+  {
+   return;
+  }
+ $w->set($w->get($x-$Tk::deltaX,$y-$Tk::deltaY))
+}
+
+# end of Tk::Scale::Drag
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scale/EndDrag.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scale/EndDrag.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scale/EndDrag.al	(revision 14139)
@@ -0,0 +1,23 @@
+# NOTE: Derived from ..\blib\lib\Tk\Scale.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Scale;
+
+#line 189 "..\blib\lib\Tk\Scale.pm (autosplit into ..\blib\lib\auto\Tk\Scale\EndDrag.al)"
+# EndDrag --
+# This procedure is called to end an interactive drag of the
+# slider.  It just marks the drag as over.
+# Arguments:
+# w - The scale widget.
+sub EndDrag
+{
+ my $w = shift;
+ if (!$Tk::dragging)
+  {
+   return;
+  }
+ $Tk::dragging = 0;
+}
+
+# end of Tk::Scale::EndDrag
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scale/Enter.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scale/Enter.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scale/Enter.al	(revision 14139)
@@ -0,0 +1,19 @@
+# NOTE: Derived from ..\blib\lib\Tk\Scale.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Scale;
+
+#line 118 "..\blib\lib\Tk\Scale.pm (autosplit into ..\blib\lib\auto\Tk\Scale\Enter.al)"
+sub Enter
+{
+ my ($w,$x,$y) = @_;
+ if ($Tk::strictMotif)
+  {
+   $w->{'activeBg'} = $w->cget('-activebackground');
+   $w->configure('-activebackground',$w->cget('-background'));
+  }
+ $w->Activate($x,$y);
+}
+
+# end of Tk::Scale::Enter
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scale/Increment.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scale/Increment.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scale/Increment.al	(revision 14139)
@@ -0,0 +1,61 @@
+# NOTE: Derived from ..\blib\lib\Tk\Scale.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Scale;
+
+#line 203 "..\blib\lib\Tk\Scale.pm (autosplit into ..\blib\lib\auto\Tk\Scale\Increment.al)"
+# Increment --
+# This procedure is invoked to increment the value of a scale and
+# to set up auto-repeating of the action if that is desired. The
+# way the value is incremented depends on the "dir" and "big"
+# arguments.
+#
+# Arguments:
+# w - The scale widget.
+# dir - "up" means move value towards -from, "down" means
+# move towards -to.
+# big - Size of increments: "big" or "little".
+# repeat - Whether and how to auto-repeat the action: "noRepeat"
+# means don't auto-repeat, "initial" means this is the
+# first action in an auto-repeat sequence, and "again"
+# means this is the second repetition or later.
+sub Increment
+{
+ my $w = shift;
+ my $dir = shift;
+ my $big = shift;
+ my $repeat = shift;
+ my $inc;
+ if ($big eq 'big')
+  {
+   $inc = $w->cget('-bigincrement');
+   if ($inc == 0)
+    {
+     $inc = abs(($w->cget('-to')-$w->cget('-from')))/10.0
+    }
+   if ($inc < $w->cget('-resolution'))
+    {
+     $inc = $w->cget('-resolution')
+    }
+  }
+ else
+  {
+   $inc = $w->cget('-resolution')
+  }
+ if (($w->cget('-from') > $w->cget('-to')) ^ ($dir eq 'up'))
+  {
+   $inc = -$inc
+  }
+ $w->set($w->get()+$inc);
+ if ($repeat eq 'again')
+  {
+   $w->RepeatId($w->after($w->cget('-repeatinterval'),'Increment',$w,$dir,$big,'again'));
+  }
+ elsif ($repeat eq 'initial')
+  {
+   $w->RepeatId($w->after($w->cget('-repeatdelay'),'Increment',$w,$dir,$big,'again'));
+  }
+}
+
+# end of Tk::Scale::Increment
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scale/Leave.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scale/Leave.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scale/Leave.al	(revision 14139)
@@ -0,0 +1,15 @@
+# NOTE: Derived from ..\blib\lib\Tk\Scale.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Scale;
+
+#line 111 "..\blib\lib\Tk\Scale.pm (autosplit into ..\blib\lib\auto\Tk\Scale\Leave.al)"
+sub Leave
+{
+ my ($w) = @_;
+ $w->configure('-activebackground',$w->{'activeBg'}) if ($Tk::strictMotif);
+ $w->configure('-state','normal')  if ($w->cget('-state') eq 'active');
+}
+
+# end of Tk::Scale::Leave
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scale/autosplit.ix
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scale/autosplit.ix	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scale/autosplit.ix	(revision 14139)
@@ -0,0 +1,22 @@
+# Index created by AutoSplit for ..\blib\lib\Tk\Scale.pm
+#    (file acts as timestamp)
+package Tk::Scale;
+sub Activate 
+;
+sub Leave 
+;
+sub Enter 
+;
+sub ButtonUp 
+;
+sub ButtonDown 
+;
+sub Drag 
+;
+sub EndDrag 
+;
+sub Increment 
+;
+sub ControlPress 
+;
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/ButtonDown.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/ButtonDown.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/ButtonDown.al	(revision 14139)
@@ -0,0 +1,55 @@
+# NOTE: Derived from ..\blib\lib\Tk\Scrollbar.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Scrollbar;
+
+#line 106 "..\blib\lib\Tk\Scrollbar.pm (autosplit into ..\blib\lib\auto\Tk\Scrollbar\ButtonDown.al)"
+# tkScrollButtonDown --
+# This procedure is invoked when a button is pressed in a scrollbar.
+# It changes the way the scrollbar is displayed and takes actions
+# depending on where the mouse is.
+#
+# Arguments:
+# w -		The scrollbar widget.
+# x, y -	Mouse coordinates.
+
+sub ButtonDown
+{my $w = shift;
+ my $e = $w->XEvent;
+ my $element = $w->identify($e->x,$e->y);
+ $w->configure('-activerelief' => 'sunken');
+ if ($e->b == 1 and
+     (defined($element) && $element eq 'slider'))
+  {
+   $w->StartDrag($e->x,$e->y);
+  }
+ elsif ($e->b == 2 and
+	(defined($element) && $element =~ /^(trough[12]|slider)$/o))
+  {
+	my $pos = $w->fraction($e->x, $e->y);
+	my($head, $tail) = $w->get;
+	my $len = $tail - $head;
+
+	$head = $pos - $len/2;
+	$tail = $pos + $len/2;
+	if ($head < 0) {
+		$head = 0;
+		$tail = $len;
+	}
+	elsif ($tail > 1) {
+		$head = 1 - $len;
+		$tail = 1;
+	}
+	$w->ScrlToPos($head);
+	$w->set($head, $tail);
+
+	$w->StartDrag($e->x,$e->y);
+   }
+ else
+  {
+   $w->Select($element,'initial');
+  }
+}
+
+# end of Tk::Scrollbar::ButtonDown
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/ButtonUp.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/ButtonUp.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/ButtonUp.al	(revision 14139)
@@ -0,0 +1,26 @@
+# NOTE: Derived from ..\blib\lib\Tk\Scrollbar.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Scrollbar;
+
+#line 153 "..\blib\lib\Tk\Scrollbar.pm (autosplit into ..\blib\lib\auto\Tk\Scrollbar\ButtonUp.al)"
+# tkScrollButtonUp --
+# This procedure is invoked when a button is released in a scrollbar.
+# It cancels scans and auto-repeats that were in progress, and restores
+# the way the active element is displayed.
+#
+# Arguments:
+# w -		The scrollbar widget.
+# x, y -	Mouse coordinates.
+
+sub ButtonUp
+{my $w = shift;
+ my $e = $w->XEvent;
+ $w->CancelRepeat;
+ $w->configure('-activerelief' => 'raised');
+ $w->EndDrag($e->x,$e->y);
+ $w->activate($w->identify($e->x,$e->y));
+}
+
+# end of Tk::Scrollbar::ButtonUp
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/Drag.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/Drag.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/Drag.al	(revision 14139)
@@ -0,0 +1,44 @@
+# NOTE: Derived from ..\blib\lib\Tk\Scrollbar.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Scrollbar;
+
+#line 247 "..\blib\lib\Tk\Scrollbar.pm (autosplit into ..\blib\lib\auto\Tk\Scrollbar\Drag.al)"
+# tkScrollDrag --
+# This procedure is called for each mouse motion even when the slider
+# is being dragged.  It notifies the associated widget if we're not
+# jump scrolling, and it just updates the scrollbar if we are jump
+# scrolling.
+#
+# Arguments:
+# w -		The scrollbar widget.
+# x, y -	The current mouse position.
+
+sub Drag
+{my $w = shift;
+ my $e = $w->XEvent;
+ return unless (defined $initMouse);
+ my $f = $w->fraction($e->x,$e->y);
+ my $delta = $f - $initMouse;
+ if ($w->cget('-jump'))
+  {
+   if (@initValues == 2)
+    {
+     $w->set($initValues[0]+$delta,$initValues[1]+$delta);
+    }
+   else
+    {
+     $delta = int($delta * $initValues[0]);
+     $initValues[2] += $delta;
+     $initValues[3] += $delta;
+     $w->set(@initValues);
+    }
+  }
+ else
+  {
+   $w->ScrlToPos($initPos+$delta);
+  }
+}
+
+# end of Tk::Scrollbar::Drag
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/EndDrag.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/EndDrag.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/EndDrag.al	(revision 14139)
@@ -0,0 +1,29 @@
+# NOTE: Derived from ..\blib\lib\Tk\Scrollbar.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Scrollbar;
+
+#line 283 "..\blib\lib\Tk\Scrollbar.pm (autosplit into ..\blib\lib\auto\Tk\Scrollbar\EndDrag.al)"
+# tkScrollEndDrag --
+# This procedure is called to end an interactive drag of the slider.
+# It scrolls the window if we're in jump mode, otherwise it does nothing.
+#
+# Arguments:
+# w -		The scrollbar widget.
+# x, y -	The mouse position at the end of the drag operation.
+
+sub EndDrag
+{
+ my $w = shift;
+ my $x = shift;
+ my $y = shift;
+ return unless defined($initMouse);
+ if ($w->cget('-jump'))
+  {
+   $w->ScrlToPos($initPos + $w->fraction($x,$y) - $initMouse);
+  }
+ undef $initMouse;
+}
+
+# end of Tk::Scrollbar::EndDrag
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/Enter.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/Enter.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/Enter.al	(revision 14139)
@@ -0,0 +1,21 @@
+# NOTE: Derived from ..\blib\lib\Tk\Scrollbar.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Scrollbar;
+
+#line 76 "..\blib\lib\Tk\Scrollbar.pm (autosplit into ..\blib\lib\auto\Tk\Scrollbar\Enter.al)"
+sub Enter
+{
+ my $w = shift;
+ my $e = $w->XEvent;
+ if ($Tk::strictMotif)
+  {
+   my $bg = $w->cget('-background');
+   $activeBg = $w->cget('-activebackground');
+   $w->configure('-activebackground' => $bg);
+  }
+ $w->activate($w->identify($e->x,$e->y));
+}
+
+# end of Tk::Scrollbar::Enter
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/Leave.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/Leave.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/Leave.al	(revision 14139)
@@ -0,0 +1,18 @@
+# NOTE: Derived from ..\blib\lib\Tk\Scrollbar.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Scrollbar;
+
+#line 89 "..\blib\lib\Tk\Scrollbar.pm (autosplit into ..\blib\lib\auto\Tk\Scrollbar\Leave.al)"
+sub Leave
+{
+ my $w = shift;
+ if ($Tk::strictMotif)
+  {
+   $w->configure('-activebackground' => $activeBg) if (defined $activeBg) ;
+  }
+ $w->activate('');
+}
+
+# end of Tk::Scrollbar::Leave
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/Motion.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/Motion.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/Motion.al	(revision 14139)
@@ -0,0 +1,15 @@
+# NOTE: Derived from ..\blib\lib\Tk\Scrollbar.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Scrollbar;
+
+#line 99 "..\blib\lib\Tk\Scrollbar.pm (autosplit into ..\blib\lib\auto\Tk\Scrollbar\Motion.al)"
+sub Motion
+{
+ my $w = shift;
+ my $e = $w->XEvent;
+ $w->activate($w->identify($e->x,$e->y));
+}
+
+# end of Tk::Scrollbar::Motion
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/ScrlByPages.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/ScrlByPages.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/ScrlByPages.al	(revision 14139)
@@ -0,0 +1,38 @@
+# NOTE: Derived from ..\blib\lib\Tk\Scrollbar.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Scrollbar;
+
+#line 333 "..\blib\lib\Tk\Scrollbar.pm (autosplit into ..\blib\lib\auto\Tk\Scrollbar\ScrlByPages.al)"
+# tkScrlByPages --
+# This procedure tells the scrollbar's associated widget to scroll up
+# or down by a given number of screenfuls.  It notifies the associated
+# widget in different ways for old and new command syntaxes.
+#
+# Arguments:
+# w -		The scrollbar widget.
+# orient -	Which kinds of scrollbars this applies to:  "h" for
+#		horizontal, "v" for vertical, "hv" for both.
+# amount -	How many screens to scroll:  typically 1 or -1.
+
+sub ScrlByPages
+{
+ my $w = shift;
+ my $orient = shift;
+ my $amount = shift;
+ my $cmd    = $w->cget('-command');
+ return unless (defined $cmd);
+ return if (index($orient,substr($w->cget('-orient'),0,1)) < 0);
+ my @info = $w->get;
+ if (@info == 2)
+  {
+   $cmd->Call('scroll',$amount,'pages');
+  }
+ else
+  {
+   $cmd->Call($info[2]+$amount*($info[1]-1));
+  }
+}
+
+# end of Tk::Scrollbar::ScrlByPages
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/ScrlByUnits.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/ScrlByUnits.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/ScrlByUnits.al	(revision 14139)
@@ -0,0 +1,37 @@
+# NOTE: Derived from ..\blib\lib\Tk\Scrollbar.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Scrollbar;
+
+#line 304 "..\blib\lib\Tk\Scrollbar.pm (autosplit into ..\blib\lib\auto\Tk\Scrollbar\ScrlByUnits.al)"
+# tkScrlByUnits --
+# This procedure tells the scrollbar's associated widget to scroll up
+# or down by a given number of units.  It notifies the associated widget
+# in different ways for old and new command syntaxes.
+#
+# Arguments:
+# w -		The scrollbar widget.
+# orient -	Which kinds of scrollbars this applies to:  "h" for
+#		horizontal, "v" for vertical, "hv" for both.
+# amount -	How many units to scroll:  typically 1 or -1.
+
+sub ScrlByUnits
+{my $w = shift;
+ my $orient = shift;
+ my $amount = shift;
+ my $cmd    = $w->cget('-command');
+ return unless (defined $cmd);
+ return if (index($orient,substr($w->cget('-orient'),0,1)) < 0);
+ my @info = $w->get;
+ if (@info == 2)
+  {
+   $cmd->Call('scroll',$amount,'units');
+  }
+ else
+  {
+   $cmd->Call($info[2]+$amount);
+  }
+}
+
+# end of Tk::Scrollbar::ScrlByUnits
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/ScrlToPos.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/ScrlToPos.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/ScrlToPos.al	(revision 14139)
@@ -0,0 +1,35 @@
+# NOTE: Derived from ..\blib\lib\Tk\Scrollbar.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Scrollbar;
+
+#line 363 "..\blib\lib\Tk\Scrollbar.pm (autosplit into ..\blib\lib\auto\Tk\Scrollbar\ScrlToPos.al)"
+# tkScrlToPos --
+# This procedure tells the scrollbar's associated widget to scroll to
+# a particular location, given by a fraction between 0 and 1.  It notifies
+# the associated widget in different ways for old and new command syntaxes.
+#
+# Arguments:
+# w -		The scrollbar widget.
+# pos -		A fraction between 0 and 1 indicating a desired position
+#		in the document.
+
+sub ScrlToPos
+{
+ my $w = shift;
+ my $pos = shift;
+ my $cmd = $w->cget('-command');
+ return unless (defined $cmd);
+ my @info = $w->get;
+ if (@info == 2)
+  {
+   $cmd->Call('moveto',$pos);
+  }
+ else
+  {
+   $cmd->Call(int($info[0]*$pos));
+  }
+}
+
+# end of Tk::Scrollbar::ScrlToPos
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/ScrlTopBottom.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/ScrlTopBottom.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/ScrlTopBottom.al	(revision 14139)
@@ -0,0 +1,32 @@
+# NOTE: Derived from ..\blib\lib\Tk\Scrollbar.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Scrollbar;
+
+#line 390 "..\blib\lib\Tk\Scrollbar.pm (autosplit into ..\blib\lib\auto\Tk\Scrollbar\ScrlTopBottom.al)"
+# tkScrlTopBottom
+# Scroll to the top or bottom of the document, depending on the mouse
+# position.
+#
+# Arguments:
+# w -		The scrollbar widget.
+# x, y -	Mouse coordinates within the widget.
+
+sub ScrlTopBottom
+{
+ my $w = shift;
+ my $e = $w->XEvent;
+ my $element = $w->identify($e->x,$e->y);
+ return unless ($element);
+ if ($element =~ /1$/)
+  {
+   $w->ScrlToPos(0);
+  }
+ elsif ($element =~ /2$/)
+  {
+   $w->ScrlToPos(1);
+  }
+}
+
+1;
+# end of Tk::Scrollbar::ScrlTopBottom
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/Select.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/Select.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/Select.al	(revision 14139)
@@ -0,0 +1,59 @@
+# NOTE: Derived from ..\blib\lib\Tk\Scrollbar.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Scrollbar;
+
+#line 171 "..\blib\lib\Tk\Scrollbar.pm (autosplit into ..\blib\lib\auto\Tk\Scrollbar\Select.al)"
+# tkScrollSelect --
+# This procedure is invoked when button 1 is pressed over the scrollbar.
+# It invokes one of several scrolling actions depending on where in
+# the scrollbar the button was pressed.
+#
+# Arguments:
+# w -		The scrollbar widget.
+# element -	The element of the scrollbar that was selected, such
+#		as "arrow1" or "trough2".  Shouldn't be "slider".
+# repeat -	Whether and how to auto-repeat the action:  "noRepeat"
+#		means don't auto-repeat, "initial" means this is the
+#		first action in an auto-repeat sequence, and "again"
+#		means this is the second repetition or later.
+
+sub Select
+{
+ my $w = shift;
+ my $element = shift;
+ my $repeat  = shift;
+ return unless defined ($element);
+ if ($element eq 'arrow1')
+  {
+   $w->ScrlByUnits('hv',-1);
+  }
+ elsif ($element eq 'trough1')
+  {
+   $w->ScrlByPages('hv',-1);
+  }
+ elsif ($element eq 'trough2')
+  {
+   $w->ScrlByPages('hv', 1);
+  }
+ elsif ($element eq 'arrow2')
+  {
+   $w->ScrlByUnits('hv', 1);
+  }
+ else
+  {
+   return;
+  }
+
+ if ($repeat eq 'again')
+  {
+   $w->RepeatId($w->after($w->cget('-repeatinterval'),['Select',$w,$element,'again']));
+  }
+ elsif ($repeat eq 'initial')
+  {
+   $w->RepeatId($w->after($w->cget('-repeatdelay'),['Select',$w,$element,'again']));
+  }
+}
+
+# end of Tk::Scrollbar::Select
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/StartDrag.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/StartDrag.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/StartDrag.al	(revision 14139)
@@ -0,0 +1,33 @@
+# NOTE: Derived from ..\blib\lib\Tk\Scrollbar.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Scrollbar;
+
+#line 222 "..\blib\lib\Tk\Scrollbar.pm (autosplit into ..\blib\lib\auto\Tk\Scrollbar\StartDrag.al)"
+# tkScrollStartDrag --
+# This procedure is called to initiate a drag of the slider.  It just
+# remembers the starting position of the slider.
+#
+# Arguments:
+# w -		The scrollbar widget.
+# x, y -	The mouse position at the start of the drag operation.
+
+sub StartDrag
+{my $w = shift;
+ my $x = shift;
+ my $y = shift;
+ return unless (defined ($w->cget('-command')));
+ $initMouse  = $w->fraction($x,$y);
+ @initValues = $w->get();
+ if (@initValues == 2)
+  {
+   $initPos = $initValues[0];
+  }
+ else
+  {
+   $initPos = $initValues[2] / $initValues[0];
+  }
+}
+
+# end of Tk::Scrollbar::StartDrag
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/autosplit.ix
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/autosplit.ix	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Scrollbar/autosplit.ix	(revision 14139)
@@ -0,0 +1,30 @@
+# Index created by AutoSplit for ..\blib\lib\Tk\Scrollbar.pm
+#    (file acts as timestamp)
+package Tk::Scrollbar;
+sub Enter 
+;
+sub Leave 
+;
+sub Motion 
+;
+sub ButtonDown 
+;
+sub ButtonUp 
+;
+sub Select 
+;
+sub StartDrag 
+;
+sub Drag 
+;
+sub EndDrag 
+;
+sub ScrlByUnits 
+;
+sub ScrlByPages 
+;
+sub ScrlToPos 
+;
+sub ScrlTopBottom 
+;
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Selection.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Selection.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Selection.al	(revision 14139)
@@ -0,0 +1,18 @@
+# NOTE: Derived from blib\lib\Tk.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk;
+
+#line 628 "blib\lib\Tk.pm (autosplit into blib\lib\auto\Tk\Selection.al)"
+# These wrappers don't use method syntax so need to live
+# in same package as raw Tk routines are newXS'ed into.
+
+sub Selection
+{my $widget = shift;
+ my $cmd    = shift;
+ croak 'Use SelectionOwn/SelectionOwner' if ($cmd eq 'own');
+ croak "Use Selection\u$cmd()";
+}
+
+# end of Tk::Selection
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Table/Create.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Table/Create.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Table/Create.al	(revision 14139)
@@ -0,0 +1,17 @@
+# NOTE: Derived from blib\lib\Tk\Table.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Table;
+
+#line 475 "blib\lib\Tk\Table.pm (autosplit into blib\lib\auto\Tk\Table\Create.al)"
+sub Create
+{
+ my $t = shift;
+ my $r = shift;
+ my $c = shift;
+ my $kind = shift;
+ $t->put($r,$c,$t->$kind(@_));
+}
+
+# end of Tk::Table::Create
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Table/Posn.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Table/Posn.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Table/Posn.al	(revision 14139)
@@ -0,0 +1,15 @@
+# NOTE: Derived from blib\lib\Tk\Table.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Table;
+
+#line 494 "blib\lib\Tk\Table.pm (autosplit into blib\lib\auto\Tk\Table\Posn.al)"
+sub Posn
+{
+ my ($t,$s) = @_;
+ my $info   = $t->{Slave}{$s->PathName};
+ return (wantarray) ? @$info : $info;
+}
+
+# end of Tk::Table::Posn
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Table/autosplit.ix
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Table/autosplit.ix	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Table/autosplit.ix	(revision 14139)
@@ -0,0 +1,14 @@
+# Index created by AutoSplit for blib\lib\Tk\Table.pm
+#    (file acts as timestamp)
+package Tk::Table;
+sub Create 
+;
+sub totalColumns 
+;
+sub totalRows 
+;
+sub Posn 
+;
+sub see 
+;
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Table/see.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Table/see.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Table/see.al	(revision 14139)
@@ -0,0 +1,46 @@
+# NOTE: Derived from blib\lib\Tk\Table.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Table;
+
+#line 501 "blib\lib\Tk\Table.pm (autosplit into blib\lib\auto\Tk\Table\see.al)"
+sub see
+{
+ my $t = shift;
+ my ($row,$col) = (@_ == 2) ? @_ : @{$t->{Slave}{$_[0]->PathName}};
+ my $see = 1;
+ if (($row -= $t->cget('-fixedrows')) >= 0)
+  {
+   if ($row < $t->{Top})
+    {
+     $t->{Top} = $row;
+     $t->QueueLayout(4);
+     $see = 0;
+    }
+   elsif ($row >= $t->{Bottom})
+    {
+     $t->{Top} += ($row - $t->{Bottom}+1);
+     $t->QueueLayout(4);
+     $see = 0;
+    }
+  }
+ if (($col -= $t->cget('-fixedcolumns')) >= 0)
+  {
+   if ($col < $t->{Left})
+    {
+     $t->{Left} = $col;
+     $t->QueueLayout(4);
+     $see = 0;
+    }
+   elsif ($col >= $t->{Right})
+    {
+     $t->{Left} += ($col - $t->{Right}+1);
+     $t->QueueLayout(4);
+     $see = 0;
+    }
+  }
+ return $see;
+}
+
+1;
+# end of Tk::Table::see
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Table/totalColumns.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Table/totalColumns.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Table/totalColumns.al	(revision 14139)
@@ -0,0 +1,13 @@
+# NOTE: Derived from blib\lib\Tk\Table.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Table;
+
+#line 484 "blib\lib\Tk\Table.pm (autosplit into blib\lib\auto\Tk\Table\totalColumns.al)"
+sub totalColumns
+{
+ scalar @{shift->{'Width'}};
+}
+
+# end of Tk::Table::totalColumns
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Table/totalRows.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Table/totalRows.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Table/totalRows.al	(revision 14139)
@@ -0,0 +1,13 @@
+# NOTE: Derived from blib\lib\Tk\Table.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Table;
+
+#line 489 "blib\lib\Tk\Table.pm (autosplit into blib\lib\auto\Tk\Table\totalRows.al)"
+sub totalRows
+{
+ scalar @{shift->{'Height'}};
+}
+
+# end of Tk::Table::totalRows
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Text/autosplit.ix
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Text/autosplit.ix	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Text/autosplit.ix	(revision 14139)
@@ -0,0 +1,3 @@
+# Index created by AutoSplit for ..\blib\lib\Tk\Text.pm
+#    (file acts as timestamp)
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/TextEdit/autosplit.ix
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/TextEdit/autosplit.ix	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/TextEdit/autosplit.ix	(revision 14139)
@@ -0,0 +1,3 @@
+# Index created by AutoSplit for blib\lib\Tk\TextEdit.pm
+#    (file acts as timestamp)
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/TextUndo/autosplit.ix
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/TextUndo/autosplit.ix	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/TextUndo/autosplit.ix	(revision 14139)
@@ -0,0 +1,3 @@
+# Index created by AutoSplit for blib\lib\Tk\TextUndo.pm
+#    (file acts as timestamp)
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Toplevel/FG_BindIn.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Toplevel/FG_BindIn.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Toplevel/FG_BindIn.al	(revision 14139)
@@ -0,0 +1,19 @@
+# NOTE: Derived from blib\lib\Tk\Toplevel.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Toplevel;
+
+#line 128 "blib\lib\Tk\Toplevel.pm (autosplit into blib\lib\auto\Tk\Toplevel\FG_BindIn.al)"
+# tkFocusGroup_BindIn --
+#
+# Add a widget into the "FocusIn" list of the focus group. The $cmd will be
+# called when the widget is focused on by the user.
+#
+sub FG_BindIn {
+    my($t, $w, $cmd) = @_;
+    $t->Error("focus group \"$t\" doesn't exist") unless (exists $t->{'_fg'});
+    $t->{'_FocusIn'}{$w} = Tk::Callback->new($cmd);
+}
+
+# end of Tk::Toplevel::FG_BindIn
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Toplevel/FG_BindOut.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Toplevel/FG_BindOut.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Toplevel/FG_BindOut.al	(revision 14139)
@@ -0,0 +1,20 @@
+# NOTE: Derived from blib\lib\Tk\Toplevel.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Toplevel;
+
+#line 139 "blib\lib\Tk\Toplevel.pm (autosplit into blib\lib\auto\Tk\Toplevel\FG_BindOut.al)"
+# tkFocusGroup_BindOut --
+#
+#	Add a widget into the "FocusOut" list of the focus group. The
+#	$cmd will be called when the widget loses the focus (User
+#	types Tab or click on another widget).
+#
+sub FG_BindOut {
+    my($t, $w, $cmd) = @_;
+    $t->Error("focus group \"$t\" doesn't exist") unless (exists $t->{'_fg'});
+    $t->{'_FocusOut'}{$w} = Tk::Callback->new($cmd);
+}
+
+# end of Tk::Toplevel::FG_BindOut
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Toplevel/FG_Create.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Toplevel/FG_Create.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Toplevel/FG_Create.al	(revision 14139)
@@ -0,0 +1,56 @@
+# NOTE: Derived from blib\lib\Tk\Toplevel.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Toplevel;
+
+#line 80 "blib\lib\Tk\Toplevel.pm (autosplit into blib\lib\auto\Tk\Toplevel\FG_Create.al)"
+#----------------------------------------------------------------------
+#
+#			Focus Group
+#
+# Focus groups are used to handle the user's focusing actions inside a
+# toplevel.
+#
+# One example of using focus groups is: when the user focuses on an
+# entry, the text in the entry is highlighted and the cursor is put to
+# the end of the text. When the user changes focus to another widget,
+# the text in the previously focused entry is validated.
+#
+
+#----------------------------------------------------------------------
+# tkFocusGroup_Create --
+#
+#	Create a focus group. All the widgets in a focus group must be
+#	within the same focus toplevel. Each toplevel can have only
+#	one focus group, which is identified by the name of the
+#	toplevel widget.
+#
+sub FG_Create {
+    my $t = shift;
+    unless (exists $t->{'_fg'}) {
+	$t->{'_fg'} = 1;
+	$t->bind('<FocusIn>', sub {
+		     my $w = shift;
+		     my $Ev = $w->XEvent;
+		     $t->FG_In($w, $Ev->d);
+		 }
+		);
+	$t->bind('<FocusOut>', sub {
+		     my $w = shift;
+		     my $Ev = $w->XEvent;
+		     $t->FG_Out($w, $Ev->d);
+		 }
+		);
+	$t->bind('<Destroy>', sub {
+		     my $w = shift;
+		     my $Ev = $w->XEvent;
+		     $t->FG_Destroy($w);
+		 }
+		);
+	# <Destroy> is not sufficient to break loops if never mapped.
+	$t->OnDestroy([$t,'FG_Destroy']);
+    }
+}
+
+# end of Tk::Toplevel::FG_Create
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Toplevel/FG_Destroy.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Toplevel/FG_Destroy.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Toplevel/FG_Destroy.al	(revision 14139)
@@ -0,0 +1,29 @@
+# NOTE: Derived from blib\lib\Tk\Toplevel.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Toplevel;
+
+#line 151 "blib\lib\Tk\Toplevel.pm (autosplit into blib\lib\auto\Tk\Toplevel\FG_Destroy.al)"
+# tkFocusGroup_Destroy --
+#
+#	Cleans up when members of the focus group is deleted, or when the
+#	toplevel itself gets deleted.
+#
+sub FG_Destroy {
+    my($t, $w) = @_;
+    if (!defined($w) || $t == $w) {
+	delete $t->{'_fg'};
+	delete $t->{'_focus'};
+	delete $t->{'_FocusOut'};
+	delete $t->{'_FocusIn'};
+    } else {
+	if (exists $t->{'_focus'}) {
+	    delete $t->{'_focus'} if ($t->{'_focus'} == $w);
+	}
+	delete $t->{'_FocusIn'}{$w};
+	delete $t->{'_FocusOut'}{$w};
+    }
+}
+
+# end of Tk::Toplevel::FG_Destroy
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Toplevel/FG_In.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Toplevel/FG_In.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Toplevel/FG_In.al	(revision 14139)
@@ -0,0 +1,24 @@
+# NOTE: Derived from blib\lib\Tk\Toplevel.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Toplevel;
+
+#line 172 "blib\lib\Tk\Toplevel.pm (autosplit into blib\lib\auto\Tk\Toplevel\FG_In.al)"
+# tkFocusGroup_In --
+#
+#	Handles the <FocusIn> event. Calls the FocusIn command for the newly
+#	focused widget in the focus group.
+#
+sub FG_In {
+    my($t, $w, $detail) = @_;
+    if (defined $t->{'_focus'} and $t->{'_focus'} eq $w) {
+	# This is already in focus
+	return;
+    } else {
+	$t->{'_focus'} = $w;
+        $t->{'_FocusIn'}{$w}->Call if exists $t->{'_FocusIn'}{$w};
+    }
+}
+
+# end of Tk::Toplevel::FG_In
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Toplevel/FG_Out.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Toplevel/FG_Out.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Toplevel/FG_Out.al	(revision 14139)
@@ -0,0 +1,32 @@
+# NOTE: Derived from blib\lib\Tk\Toplevel.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Toplevel;
+
+#line 188 "blib\lib\Tk\Toplevel.pm (autosplit into blib\lib\auto\Tk\Toplevel\FG_Out.al)"
+# tkFocusGroup_Out --
+#
+#	Handles the <FocusOut> event. Checks if this is really a lose
+#	focus event, not one generated by the mouse moving out of the
+#	toplevel window.  Calls the FocusOut command for the widget
+#	who loses its focus.
+#
+sub FG_Out {
+    my($t, $w, $detail) = @_;
+    if ($detail ne 'NotifyNonlinear' and $detail ne 'NotifyNonlinearVirtual') {
+	# This is caused by mouse moving out of the window
+	return;
+    }
+    unless (exists $t->{'_FocusOut'}{$w}) {
+	return;
+    } else {
+	$t->{'_FocusOut'}{$w}->Call;
+	delete $t->{'_focus'};
+    }
+}
+
+1;
+
+__END__
+1;
+# end of Tk::Toplevel::FG_Out
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Toplevel/autosplit.ix
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Toplevel/autosplit.ix	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Toplevel/autosplit.ix	(revision 14139)
@@ -0,0 +1,10 @@
+# Index created by AutoSplit for blib\lib\Tk\Toplevel.pm
+#    (file acts as timestamp)
+package Tk::Toplevel;
+sub FG_Create  ;
+sub FG_BindIn  ;
+sub FG_BindOut  ;
+sub FG_Destroy  ;
+sub FG_In  ;
+sub FG_Out  ;
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/TraverseToMenu.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/TraverseToMenu.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/TraverseToMenu.al	(revision 14139)
@@ -0,0 +1,27 @@
+# NOTE: Derived from blib\lib\Tk.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk;
+
+#line 597 "blib\lib\Tk.pm (autosplit into blib\lib\auto\Tk\TraverseToMenu.al)"
+# tkTraverseToMenu --
+# This procedure implements keyboard traversal of menus. Given an
+# ASCII character "char", it looks for a menubutton with that character
+# underlined. If one is found, it posts the menubutton's menu
+#
+# Arguments:
+# w - Window in which the key was typed (selects
+# a toplevel window).
+# char - Character that selects a menu. The case
+# is ignored. If an empty string, nothing
+# happens.
+sub TraverseToMenu
+{
+ my $w = shift;
+ my $char = shift;
+ return unless(defined $char && $char ne '');
+ $w = $w->toplevel->FindMenu($char);
+}
+
+# end of Tk::TraverseToMenu
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Widget/ASkludge.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Widget/ASkludge.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Widget/ASkludge.al	(revision 14139)
@@ -0,0 +1,30 @@
+# NOTE: Derived from blib\lib\Tk\Widget.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Widget;
+
+#line 1224 "blib\lib\Tk\Widget.pm (autosplit into blib\lib\auto\Tk\Widget\ASkludge.al)"
+sub ASkludge
+{
+ my ($hash,$sense) = @_;
+ foreach my $key (%$hash)
+  {
+   if ($key =~ /-.*variable/ && ref($hash->{$key}) eq 'SCALAR')
+    {
+     if ($sense)
+      {
+       my $val = ${$hash->{$key}};
+       require Tie::Scalar;
+       tie ${$hash->{$key}},'Tie::StdScalar';
+       ${$hash->{$key}} = $val;
+      }
+     else
+      {
+       untie ${$hash->{$key}};
+      }
+    }
+  }
+}
+
+# end of Tk::Widget::ASkludge
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Widget/autosplit.ix
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Widget/autosplit.ix	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Widget/autosplit.ix	(revision 14139)
@@ -0,0 +1,10 @@
+# Index created by AutoSplit for blib\lib\Tk\Widget.pm
+#    (file acts as timestamp)
+package Tk::Widget;
+sub ASkludge 
+;
+sub clipboardKeysyms 
+;
+sub pathname 
+;
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Widget/clipboardKeysyms.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Widget/clipboardKeysyms.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Widget/clipboardKeysyms.al	(revision 14139)
@@ -0,0 +1,51 @@
+# NOTE: Derived from blib\lib\Tk\Widget.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Widget;
+
+#line 1248 "blib\lib\Tk\Widget.pm (autosplit into blib\lib\auto\Tk\Widget\clipboardKeysyms.al)"
+# clipboardKeysyms --
+# This procedure is invoked to identify the keys that correspond to
+# the "copy", "cut", and "paste" functions for the clipboard.
+#
+# Arguments:
+# copy - Name of the key (keysym name plus modifiers, if any,
+# such as "Meta-y") used for the copy operation.
+# cut - Name of the key used for the cut operation.
+# paste - Name of the key used for the paste operation.
+#
+# This method is obsolete use clipboardOperations and abstract
+# event types instead. See Clipboard.pm and Mainwindow.pm
+
+sub clipboardKeysyms
+{
+ my @class = ();
+ my $mw    = shift;
+ if (ref $mw)
+  {
+   $mw = $mw->DelegateFor('bind');
+  }
+ else
+  {
+   push(@class,$mw);
+   $mw = shift;
+  }
+ if (@_)
+  {
+   my $copy  = shift;
+   $mw->Tk::bind(@class,"<$copy>",'clipboardCopy')   if (defined $copy);
+  }
+ if (@_)
+  {
+   my $cut   = shift;
+   $mw->Tk::bind(@class,"<$cut>",'clipboardCut')     if (defined $cut);
+  }
+ if (@_)
+  {
+   my $paste = shift;
+   $mw->Tk::bind(@class,"<$paste>",'clipboardPaste') if (defined $paste);
+  }
+}
+
+# end of Tk::Widget::clipboardKeysyms
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Widget/pathname.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Widget/pathname.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Widget/pathname.al	(revision 14139)
@@ -0,0 +1,15 @@
+# NOTE: Derived from blib\lib\Tk\Widget.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Widget;
+
+#line 1291 "blib\lib\Tk\Widget.pm (autosplit into blib\lib\auto\Tk\Widget\pathname.al)"
+sub pathname
+{
+ my ($w,$id) = @_;
+ my $x = $w->winfo('pathname',-displayof  => oct($id));
+ return $x->PathName;
+}
+
+1;
+# end of Tk::Widget::pathname
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Wm/AnchorAdjust.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Wm/AnchorAdjust.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Wm/AnchorAdjust.al	(revision 14139)
@@ -0,0 +1,17 @@
+# NOTE: Derived from blib\lib\Tk\Wm.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Wm;
+
+#line 84 "blib\lib\Tk\Wm.pm (autosplit into blib\lib\auto\Tk\Wm\AnchorAdjust.al)"
+sub AnchorAdjust
+{
+ my ($anchor,$X,$Y,$w,$h) = @_;
+ $anchor = 'c' unless (defined $anchor);
+ $Y += ($anchor =~ /s/) ? $h : ($anchor =~ /n/) ? 0 : $h/2;
+ $X += ($anchor =~ /e/) ? $w : ($anchor =~ /w/) ? 0 : $w/2;
+ return ($X,$Y);
+}
+
+# end of Tk::Wm::AnchorAdjust
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Wm/FullScreen.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Wm/FullScreen.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Wm/FullScreen.al	(revision 14139)
@@ -0,0 +1,29 @@
+# NOTE: Derived from blib\lib\Tk\Wm.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Wm;
+
+#line 130 "blib\lib\Tk\Wm.pm (autosplit into blib\lib\auto\Tk\Wm\FullScreen.al)"
+sub FullScreen
+{
+ my $w = shift;
+ my $over = (@_) ? shift : 0;
+ my $width  = $w->screenwidth;
+ my $height = $w->screenheight;
+ $w->GeometryRequest($width,$height);
+ $w->overrideredirect($over & 1);
+ $w->Post(0,0);
+ $w->update;
+ if ($over & 2)
+  {
+   my $x = $w->rootx;
+   my $y = $w->rooty;
+   $width -= 2*$x;
+   $height -= $x + $y;
+   $w->GeometryRequest($width,$height);
+   $w->update;
+  }
+}
+
+# end of Tk::Wm::FullScreen
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Wm/Popup.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Wm/Popup.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Wm/Popup.al	(revision 14139)
@@ -0,0 +1,45 @@
+# NOTE: Derived from blib\lib\Tk\Wm.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Wm;
+
+#line 93 "blib\lib\Tk\Wm.pm (autosplit into blib\lib\auto\Tk\Wm\Popup.al)"
+sub Popup
+{
+ my $w = shift;
+ $w->configure(@_) if @_;
+ $w->idletasks;
+ my ($mw,$mh) = ($w->reqwidth,$w->reqheight);
+ my ($rx,$ry,$rw,$rh) = (0,0,0,0);
+ my $base    = $w->cget('-popover');
+ my $outside = 0;
+ if (defined $base)
+  {
+   if ($base eq 'cursor')
+    {
+     ($rx,$ry) = $w->pointerxy;
+    }
+   else
+    {
+     $rx = $base->rootx;
+     $ry = $base->rooty;
+     $rw = $base->Width;
+     $rh = $base->Height;
+    }
+  }
+ else
+  {
+   my $sc = ($w->parent) ? $w->parent->toplevel : $w;
+   $rx = -$sc->vrootx;
+   $ry = -$sc->vrooty;
+   $rw = $w->screenwidth;
+   $rh = $w->screenheight;
+  }
+ my ($X,$Y) = AnchorAdjust($w->cget('-overanchor'),$rx,$ry,$rw,$rh);
+ ($X,$Y)    = AnchorAdjust($w->cget('-popanchor'),$X,$Y,-$mw,-$mh);
+ $w->Post($X,$Y); 
+ $w->waitVisibility;
+}
+
+# end of Tk::Wm::Popup
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Wm/Post.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Wm/Post.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Wm/Post.al	(revision 14139)
@@ -0,0 +1,20 @@
+# NOTE: Derived from blib\lib\Tk\Wm.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Wm;
+
+#line 72 "blib\lib\Tk\Wm.pm (autosplit into blib\lib\auto\Tk\Wm\Post.al)"
+sub Post
+{
+ my ($w,$X,$Y) = @_;
+ $X = int($X);
+ $Y = int($Y);
+ $w->positionfrom('user');
+ # $w->geometry("+$X+$Y");
+ $w->MoveToplevelWindow($X,$Y);
+ $w->deiconify;
+ $w->raise;
+}
+
+# end of Tk::Wm::Post
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Wm/autosplit.ix
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Wm/autosplit.ix	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Wm/autosplit.ix	(revision 14139)
@@ -0,0 +1,14 @@
+# Index created by AutoSplit for blib\lib\Tk\Wm.pm
+#    (file acts as timestamp)
+package Tk::Wm;
+sub Post 
+;
+sub AnchorAdjust 
+;
+sub Popup 
+;
+sub FullScreen 
+;
+sub iconposition 
+;
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Wm/iconposition.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Wm/iconposition.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/Wm/iconposition.al	(revision 14139)
@@ -0,0 +1,24 @@
+# NOTE: Derived from blib\lib\Tk\Wm.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk::Wm;
+
+#line 151 "blib\lib\Tk\Wm.pm (autosplit into blib\lib\auto\Tk\Wm\iconposition.al)"
+sub iconposition
+{
+ my $w = shift;
+ if (@_ == 1)
+  {
+   return $w->wm('iconposition',$1,$2) if $_[0] =~ /^(\d+),(\d+)$/;
+   if ($_[0] =~ /^([+-])(\d+)([+-])(\d+)$/)
+    {
+     my $x = ($1 eq '-') ? $w->screenwidth-$2 : $2;
+     my $y = ($3 eq '-') ? $w->screenheight-$4 : $4;
+     return $w->wm('iconposition',$x,$y);
+    }
+  }
+ $w->wm('iconposition',@_);
+}
+
+1;
+# end of Tk::Wm::iconposition
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/X/autosplit.ix
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/X/autosplit.ix	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/X/autosplit.ix	(revision 14139)
@@ -0,0 +1,3 @@
+# Index created by AutoSplit for ..\..\blib\lib\Tk\X.pm
+#    (file acts as timestamp)
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/autosplit.ix
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/autosplit.ix	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/autosplit.ix	(revision 14139)
@@ -0,0 +1,43 @@
+# Index created by AutoSplit for blib\lib\Tk.pm
+#    (file acts as timestamp)
+package Tk;
+sub Error 
+;
+sub CancelRepeat 
+;
+sub RepeatId 
+;
+sub FocusChildren  ;
+sub focusNext 
+;
+sub focusPrev 
+;
+sub FocusOK 
+;
+sub EnterFocus 
+;
+sub tabFocus 
+;
+sub focusFollowsMouse 
+;
+sub TraverseToMenu 
+;
+sub FirstMenu 
+;
+sub Selection 
+;
+sub Receive 
+;
+sub break 
+;
+sub updateWidgets 
+;
+sub ImageNames 
+;
+sub ImageTypes 
+;
+sub interps 
+;
+sub lsearch 
+;
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/break.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/break.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/break.al	(revision 14139)
@@ -0,0 +1,13 @@
+# NOTE: Derived from blib\lib\Tk.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk;
+
+#line 653 "blib\lib\Tk.pm (autosplit into blib\lib\auto\Tk\break.al)"
+sub break
+{
+ die "_TK_BREAK_\n";
+}
+
+# end of Tk::break
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/focusFollowsMouse.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/focusFollowsMouse.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/focusFollowsMouse.al	(revision 14139)
@@ -0,0 +1,14 @@
+# NOTE: Derived from blib\lib\Tk.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk;
+
+#line 591 "blib\lib\Tk.pm (autosplit into blib\lib\auto\Tk\focusFollowsMouse.al)"
+sub focusFollowsMouse
+{
+ my $widget = shift;
+ $widget->bind('all','<Enter>','EnterFocus');
+}
+
+# end of Tk::focusFollowsMouse
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/focusNext.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/focusNext.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/focusNext.al	(revision 14139)
@@ -0,0 +1,45 @@
+# NOTE: Derived from blib\lib\Tk.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk;
+
+#line 449 "blib\lib\Tk.pm (autosplit into blib\lib\auto\Tk\focusNext.al)"
+sub focusNext
+{
+ my $w = shift;
+ my $cur = $w;
+ while (1)
+  {
+   # Descend to just before the first child of the current widget.
+   my $parent = $cur;
+   my @children = $cur->FocusChildren();
+   my $i = -1;
+   # Look for the next sibling that isn't a top-level.
+   while (1)
+    {
+     $i += 1;
+     if ($i < @children)
+      {
+       $cur = $children[$i];
+       next if ($cur->toplevel == $cur);
+       last
+      }
+     # No more siblings, so go to the current widget's parent.
+     # If it's a top-level, break out of the loop, otherwise
+     # look for its next sibling.
+     $cur = $parent;
+     last if ($cur->toplevel() == $cur);
+     $parent = $parent->parent();
+     @children = $parent->FocusChildren();
+     $i = lsearch(\@children,$cur);
+    }
+   if ($cur == $w || $cur->FocusOK)
+    {
+     $cur->tabFocus;
+     return;
+    }
+  }
+}
+
+# end of Tk::focusNext
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/focusPrev.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/focusPrev.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/focusPrev.al	(revision 14139)
@@ -0,0 +1,65 @@
+# NOTE: Derived from blib\lib\Tk.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk;
+
+#line 485 "blib\lib\Tk.pm (autosplit into blib\lib\auto\Tk\focusPrev.al)"
+# focusPrev --
+# This procedure is invoked to move the input focus to the previous
+# window before a given one. "Previous" is defined in terms of the
+# window stacking order, with all the windows underneath a given
+# top-level (no matter how deeply nested in the hierarchy) considered.
+#
+# Arguments:
+# w - Name of a window: the procedure will set the focus
+# to the previous window before this one in the traversal
+# order.
+sub focusPrev
+{
+ my $w = shift;
+ my $cur = $w;
+ my @children;
+ my $i;
+ my $parent;
+ while (1)
+  {
+   # Collect information about the current window's position
+   # among its siblings. Also, if the window is a top-level,
+   # then reposition to just after the last child of the window.
+   if ($cur->toplevel() == $cur)
+    {
+     $parent = $cur;
+     @children = $cur->FocusChildren();
+     $i = @children;
+    }
+   else
+    {
+     $parent = $cur->parent();
+     @children = $parent->FocusChildren();
+     $i = lsearch(\@children,$cur);
+    }
+   # Go to the previous sibling, then descend to its last descendant
+   # (highest in stacking order. While doing this, ignore top-levels
+   # and their descendants. When we run out of descendants, go up
+   # one level to the parent.
+   while ($i > 0)
+    {
+     $i--;
+     $cur = $children[$i];
+     next if ($cur->toplevel() == $cur);
+     $parent = $cur;
+     @children = $parent->FocusChildren();
+     $i = @children;
+    }
+   $cur = $parent;
+   if ($cur == $w || $cur->FocusOK)
+    {
+     $cur->tabFocus;
+     return;
+    }
+  }
+
+}
+
+# end of Tk::focusPrev
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/interps.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/interps.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/interps.al	(revision 14139)
@@ -0,0 +1,14 @@
+# NOTE: Derived from blib\lib\Tk.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk;
+
+#line 677 "blib\lib\Tk.pm (autosplit into blib\lib\auto\Tk\interps.al)"
+sub interps
+{
+ my $w = shift;
+ return $w->winfo('interps','-displayof');
+}
+
+# end of Tk::interps
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/lsearch.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/lsearch.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/lsearch.al	(revision 14139)
@@ -0,0 +1,19 @@
+# NOTE: Derived from blib\lib\Tk.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk;
+
+#line 683 "blib\lib\Tk.pm (autosplit into blib\lib\auto\Tk\lsearch.al)"
+sub lsearch
+{my $ar = shift;
+ my $x  = shift;
+ my $i;
+ for ($i = 0; $i < scalar @$ar; $i++)
+  {
+   return $i if ($$ar[$i] eq $x);
+  }
+ return -1;
+}
+
+1;
+# end of Tk::lsearch
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/pTk/extralibs.ld
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/pTk/extralibs.ld	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/pTk/extralibs.ld	(revision 14139)
@@ -0,0 +1,1 @@
+"" 
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/tabFocus.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/tabFocus.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/tabFocus.al	(revision 14139)
@@ -0,0 +1,13 @@
+# NOTE: Derived from blib\lib\Tk.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk;
+
+#line 586 "blib\lib\Tk.pm (autosplit into blib\lib\auto\Tk\tabFocus.al)"
+sub tabFocus
+{
+ shift->Tk::focus;
+}
+
+# end of Tk::tabFocus
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/updateWidgets.al
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/updateWidgets.al	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Tk/updateWidgets.al	(revision 14139)
@@ -0,0 +1,17 @@
+# NOTE: Derived from blib\lib\Tk.pm.
+# Changes made here will be lost when autosplit is run again.
+# See AutoSplit.pm.
+package Tk;
+
+#line 658 "blib\lib\Tk.pm (autosplit into blib\lib\auto\Tk\updateWidgets.al)"
+sub updateWidgets
+{
+ my ($w) = @_;
+ while ($w->DoOneEvent(DONT_WAIT|IDLE_EVENTS|WINDOW_EVENTS))
+  {
+  }
+ $w;
+}
+
+# end of Tk::updateWidgets
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/URI/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/URI/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/URI/.packlist	(revision 14139)
@@ -0,0 +1,49 @@
+C:\mdewsnip\perl-5.6.1\site\lib\URI.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\Escape.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\Heuristic.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\QueryParam.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\Split.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\URL.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\WithBase.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\_foreign.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\_generic.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\_ldap.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\_login.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\_query.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\_segment.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\_server.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\_userpass.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\data.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\file.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\file\Base.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\file\FAT.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\file\Mac.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\file\OS2.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\file\QNX.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\file\Unix.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\file\Win32.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\ftp.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\gopher.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\http.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\https.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\ldap.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\ldapi.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\ldaps.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\mailto.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\mms.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\news.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\nntp.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\pop.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\rlogin.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\rsync.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\rtsp.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\rtspu.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\sip.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\sips.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\snews.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\ssh.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\telnet.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\tn3270.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\urn.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\urn\isbn.pm
+C:\mdewsnip\perl-5.6.1\site\lib\URI\urn\oid.pm
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Unicode/String/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Unicode/String/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Unicode/String/.packlist	(revision 14139)
@@ -0,0 +1,6 @@
+C:\mdewsnip\perl-5.6.1\site\lib\Unicode\CharName.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Unicode\String.pm
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Unicode\String\String.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Unicode\String\String.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Unicode\String\String.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Unicode\String\String.lib
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Win32/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Win32/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Win32/.packlist	(revision 14139)
@@ -0,0 +1,158 @@
+C:\mdewsnip\perl-5.6.1\site\lib\OLE.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32API\File.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32API\File\cFile.pc
+C:\mdewsnip\perl-5.6.1\site\lib\Win32API\Net.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32API\Registry.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32API\Registry\cRegistry.pc
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\ChangeNotify.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\Client.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\Clipboard.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\Console.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\Event.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\EventLog.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\File.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\FileSecurity.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\IPC.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\Internet.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\Job.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\Mutex.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\NetAdmin.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\NetResource.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\ODBC.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\OLE.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\OLE\Const.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\OLE\Enum.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\OLE\Lite.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\OLE\NEWS.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\OLE\NLS.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\OLE\TPJ.pod
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\OLE\TypeInfo.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\OLE\Variant.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\PerfLib.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\Pipe.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\Process.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\Registry.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\Semaphore.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\Server.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\Service.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\Shortcut.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\Sound.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\Test.pl
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\TieRegistry.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\WinError.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\test-async.pl
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32API\File\File.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32API\File\File.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32API\File\File.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32API\File\File.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32API\Net\Net.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32API\Net\Net.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32API\Net\Net.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32API\Net\Net.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32API\Registry\Registry.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32API\Registry\Registry.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32API\Registry\Registry.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32API\Registry\Registry.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\ChangeNotify\ChangeNotify.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\ChangeNotify\ChangeNotify.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\ChangeNotify\ChangeNotify.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\ChangeNotify\ChangeNotify.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Clipboard\Clipboard.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Clipboard\Clipboard.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Clipboard\Clipboard.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Clipboard\Clipboard.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Console\Console.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Console\Console.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Console\Console.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Console\Console.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\EventLog\EventLog.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\EventLog\EventLog.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\EventLog\EventLog.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\EventLog\EventLog.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Event\Event.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Event\Event.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Event\Event.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Event\Event.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\FileSecurity\FileSecurity.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\FileSecurity\FileSecurity.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\FileSecurity\FileSecurity.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\FileSecurity\FileSecurity.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\File\File.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\File\File.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\File\File.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\File\File.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\IPC\IPC.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\IPC\IPC.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\IPC\IPC.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\IPC\IPC.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Internet\Internet.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Internet\Internet.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Internet\Internet.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Internet\Internet.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Job\Job.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Job\Job.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Job\Job.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Job\Job.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Mutex\Mutex.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Mutex\Mutex.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Mutex\Mutex.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Mutex\Mutex.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\NetAdmin\NetAdmin.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\NetAdmin\NetAdmin.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\NetAdmin\NetAdmin.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\NetAdmin\NetAdmin.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\NetResource\NetResource.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\NetResource\NetResource.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\NetResource\NetResource.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\NetResource\NetResource.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\NetResource\autosplit.ix
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\ODBC\ODBC.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\ODBC\ODBC.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\ODBC\ODBC.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\ODBC\ODBC.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\OLE\OLE.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\OLE\OLE.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\OLE\OLE.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\OLE\OLE.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\PerfLib\PerfLib.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\PerfLib\PerfLib.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\PerfLib\PerfLib.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\PerfLib\PerfLib.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\PerfLib\autosplit.ix
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Pipe\Pipe.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Pipe\Pipe.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Pipe\Pipe.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Pipe\Pipe.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Process\Process.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Process\Process.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Process\Process.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Process\Process.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Registry\Registry.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Registry\Registry.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Registry\Registry.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Registry\Registry.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Semaphore\Semaphore.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Semaphore\Semaphore.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Semaphore\Semaphore.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Semaphore\Semaphore.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Service\Service.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Service\Service.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Service\Service.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Service\Service.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Shortcut\Shortcut.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Shortcut\Shortcut.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Shortcut\Shortcut.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Shortcut\Shortcut.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Sound\Sound.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Sound\Sound.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Sound\Sound.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Sound\Sound.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Win32.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Win32.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Win32.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Win32.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\WinError\WinError.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\WinError\WinError.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\WinError\WinError.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\WinError\WinError.lib
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Win32/AuthenticateUser/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Win32/AuthenticateUser/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Win32/AuthenticateUser/.packlist	(revision 14139)
@@ -0,0 +1,6 @@
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\AuthenticateUser.pm
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\AuthenticateUser\AuthenticateUser.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\AuthenticateUser\AuthenticateUser.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\AuthenticateUser\AuthenticateUser.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\AuthenticateUser\AuthenticateUser.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\AuthenticateUser\autosplit.ix
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Win32/AuthenticateUser/autosplit.ix
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Win32/AuthenticateUser/autosplit.ix	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Win32/AuthenticateUser/autosplit.ix	(revision 14139)
@@ -0,0 +1,3 @@
+# Index created by AutoSplit for blib\lib\Win32\AuthenticateUser.pm
+#    (file acts as timestamp)
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Win32/NetResource/autosplit.ix
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Win32/NetResource/autosplit.ix	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Win32/NetResource/autosplit.ix	(revision 14139)
@@ -0,0 +1,3 @@
+# Index created by AutoSplit for ..\blib\lib\Win32\NetResource.pm
+#    (file acts as timestamp)
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Win32/PerfLib/autosplit.ix
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Win32/PerfLib/autosplit.ix	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Win32/PerfLib/autosplit.ix	(revision 14139)
@@ -0,0 +1,3 @@
+# Index created by AutoSplit for ..\blib\lib\Win32\PerfLib.pm
+#    (file acts as timestamp)
+1;
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Win32/Shortcut/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Win32/Shortcut/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/Win32/Shortcut/.packlist	(revision 14139)
@@ -0,0 +1,6 @@
+C:\mdewsnip\perl-5.6.1\site\lib\Win32\Shortcut.pm
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Shortcut\Shortcut.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Shortcut\Shortcut.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Shortcut\Shortcut.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Shortcut\Shortcut.lib
+C:\mdewsnip\perl-5.6.1\site\lib\auto\Win32\Shortcut\Shortcut.pdb
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/XML/Parser/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/XML/Parser/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/XML/Parser/.packlist	(revision 14139)
@@ -0,0 +1,69 @@
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser.pm
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Encodings\Japanese_Encodings.msg
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Encodings\README
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Encodings\big5.enc
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Encodings\euc-kr.enc
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Encodings\iso-8859-2.enc
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Encodings\iso-8859-3.enc
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Encodings\iso-8859-4.enc
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Encodings\iso-8859-5.enc
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Encodings\iso-8859-7.enc
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Encodings\iso-8859-8.enc
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Encodings\iso-8859-9.enc
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Encodings\windows-1250.enc
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Encodings\x-euc-jp-jisx0221.enc
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Encodings\x-euc-jp-unicode.enc
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Encodings\x-sjis-cp932.enc
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Encodings\x-sjis-jdk117.enc
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Encodings\x-sjis-jisx0221.enc
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Encodings\x-sjis-unicode.enc
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat.pm
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\Makefile
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\bin\xmlparse.dll
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\bin\xmltok.dll
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\bin\xmlwf.exe
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\expat.dsw
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\expat.html
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\gennmtab\gennmtab.c
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\gennmtab\gennmtab.dsp
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\lib\xmlparse.lib
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\lib\xmltok.lib
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\sample\build.bat
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\sample\elements.c
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmlparse\hashtable.c
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmlparse\hashtable.h
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmlparse\xmlparse.c
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmlparse\xmlparse.c.orig
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmlparse\xmlparse.dsp
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmlparse\xmlparse.h
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmlparse\xmlparse.h.orig
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmltok\asciitab.h
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmltok\dllmain.c
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmltok\iasciitab.h
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmltok\latin1tab.h
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmltok\nametab.h
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmltok\utf8tab.h
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmltok\xmldef.h
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmltok\xmlrole.c
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmltok\xmlrole.h
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmltok\xmltok.c
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmltok\xmltok.dsp
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmltok\xmltok.h
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmltok\xmltok_impl.c
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmltok\xmltok_impl.h
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmltok\xmltok_ns.c
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmlwf\codepage.c
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmlwf\codepage.h
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmlwf\filemap.h
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmlwf\readfilemap.c
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmlwf\unixfilemap.c
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmlwf\win32filemap.c
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmlwf\xmlfile.c
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmlwf\xmlfile.h
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmlwf\xmltchar.h
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmlwf\xmlwf.c
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Parser\Expat\xmlwf\xmlwf.dsp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\XML\Parser\Expat\Expat.bs
+C:\mdewsnip\perl-5.6.1\site\lib\auto\XML\Parser\Expat\Expat.dll
+C:\mdewsnip\perl-5.6.1\site\lib\auto\XML\Parser\Expat\Expat.exp
+C:\mdewsnip\perl-5.6.1\site\lib\auto\XML\Parser\Expat\Expat.lib
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/XML/Simple/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/XML/Simple/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/XML/Simple/.packlist	(revision 14139)
@@ -0,0 +1,2 @@
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Simple.pm
+C:\mdewsnip\perl-5.6.1\site\lib\XML\Simple\FAQ.pod
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/libwww-perl/.packlist
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/libwww-perl/.packlist	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/libwww-perl/.packlist	(revision 14139)
@@ -0,0 +1,67 @@
+C:\mdewsnip\perl-5.6.1\bin\GET
+C:\mdewsnip\perl-5.6.1\bin\GET.bat
+C:\mdewsnip\perl-5.6.1\bin\HEAD
+C:\mdewsnip\perl-5.6.1\bin\HEAD.bat
+C:\mdewsnip\perl-5.6.1\bin\POST
+C:\mdewsnip\perl-5.6.1\bin\POST.bat
+C:\mdewsnip\perl-5.6.1\bin\lwp-download
+C:\mdewsnip\perl-5.6.1\bin\lwp-download.bat
+C:\mdewsnip\perl-5.6.1\bin\lwp-mirror
+C:\mdewsnip\perl-5.6.1\bin\lwp-mirror.bat
+C:\mdewsnip\perl-5.6.1\bin\lwp-request
+C:\mdewsnip\perl-5.6.1\bin\lwp-request.bat
+C:\mdewsnip\perl-5.6.1\bin\lwp-rget
+C:\mdewsnip\perl-5.6.1\bin\lwp-rget.bat
+C:\mdewsnip\perl-5.6.1\site\lib\Bundle\LWP.pm
+C:\mdewsnip\perl-5.6.1\site\lib\File\Listing.pm
+C:\mdewsnip\perl-5.6.1\site\lib\HTML\Form.pm
+C:\mdewsnip\perl-5.6.1\site\lib\HTTP\Cookies.pm
+C:\mdewsnip\perl-5.6.1\site\lib\HTTP\Cookies\Microsoft.pm
+C:\mdewsnip\perl-5.6.1\site\lib\HTTP\Cookies\Netscape.pm
+C:\mdewsnip\perl-5.6.1\site\lib\HTTP\Daemon.pm
+C:\mdewsnip\perl-5.6.1\site\lib\HTTP\Date.pm
+C:\mdewsnip\perl-5.6.1\site\lib\HTTP\Headers.pm
+C:\mdewsnip\perl-5.6.1\site\lib\HTTP\Headers\Auth.pm
+C:\mdewsnip\perl-5.6.1\site\lib\HTTP\Headers\ETag.pm
+C:\mdewsnip\perl-5.6.1\site\lib\HTTP\Headers\Util.pm
+C:\mdewsnip\perl-5.6.1\site\lib\HTTP\Message.pm
+C:\mdewsnip\perl-5.6.1\site\lib\HTTP\Negotiate.pm
+C:\mdewsnip\perl-5.6.1\site\lib\HTTP\Request.pm
+C:\mdewsnip\perl-5.6.1\site\lib\HTTP\Request\Common.pm
+C:\mdewsnip\perl-5.6.1\site\lib\HTTP\Response.pm
+C:\mdewsnip\perl-5.6.1\site\lib\HTTP\Status.pm
+C:\mdewsnip\perl-5.6.1\site\lib\LWP.pm
+C:\mdewsnip\perl-5.6.1\site\lib\LWP\Authen\Basic.pm
+C:\mdewsnip\perl-5.6.1\site\lib\LWP\Authen\Digest.pm
+C:\mdewsnip\perl-5.6.1\site\lib\LWP\Authen\Ntlm.pm
+C:\mdewsnip\perl-5.6.1\site\lib\LWP\ConnCache.pm
+C:\mdewsnip\perl-5.6.1\site\lib\LWP\Debug.pm
+C:\mdewsnip\perl-5.6.1\site\lib\LWP\DebugFile.pm
+C:\mdewsnip\perl-5.6.1\site\lib\LWP\MediaTypes.pm
+C:\mdewsnip\perl-5.6.1\site\lib\LWP\MemberMixin.pm
+C:\mdewsnip\perl-5.6.1\site\lib\LWP\Protocol.pm
+C:\mdewsnip\perl-5.6.1\site\lib\LWP\Protocol\GHTTP.pm
+C:\mdewsnip\perl-5.6.1\site\lib\LWP\Protocol\cpan.pm
+C:\mdewsnip\perl-5.6.1\site\lib\LWP\Protocol\data.pm
+C:\mdewsnip\perl-5.6.1\site\lib\LWP\Protocol\file.pm
+C:\mdewsnip\perl-5.6.1\site\lib\LWP\Protocol\ftp.pm
+C:\mdewsnip\perl-5.6.1\site\lib\LWP\Protocol\gopher.pm
+C:\mdewsnip\perl-5.6.1\site\lib\LWP\Protocol\http.pm
+C:\mdewsnip\perl-5.6.1\site\lib\LWP\Protocol\http10.pm
+C:\mdewsnip\perl-5.6.1\site\lib\LWP\Protocol\https.pm
+C:\mdewsnip\perl-5.6.1\site\lib\LWP\Protocol\https10.pm
+C:\mdewsnip\perl-5.6.1\site\lib\LWP\Protocol\mailto.pm
+C:\mdewsnip\perl-5.6.1\site\lib\LWP\Protocol\nntp.pm
+C:\mdewsnip\perl-5.6.1\site\lib\LWP\Protocol\nogo.pm
+C:\mdewsnip\perl-5.6.1\site\lib\LWP\RobotUA.pm
+C:\mdewsnip\perl-5.6.1\site\lib\LWP\Simple.pm
+C:\mdewsnip\perl-5.6.1\site\lib\LWP\UserAgent.pm
+C:\mdewsnip\perl-5.6.1\site\lib\LWP\media.types
+C:\mdewsnip\perl-5.6.1\site\lib\Net\HTTP.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Net\HTTPS.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Net\HTTP\Methods.pm
+C:\mdewsnip\perl-5.6.1\site\lib\Net\HTTP\NB.pm
+C:\mdewsnip\perl-5.6.1\site\lib\WWW\RobotRules.pm
+C:\mdewsnip\perl-5.6.1\site\lib\WWW\RobotRules\AnyDBM_File.pm
+C:\mdewsnip\perl-5.6.1\site\lib\lwpcook.pod
+C:\mdewsnip\perl-5.6.1\site\lib\lwptut.pod
Index: collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/zlib/extralibs.ld
===================================================================
--- collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/zlib/extralibs.ld	(revision 14139)
+++ collections/trunk/cic-hcap/bin/windows/perl/site/lib/auto/zlib/extralibs.ld	(revision 14139)
@@ -0,0 +1,1 @@
+"" 
Index: collections/trunk/cic-hcap/cic-hcap.col
===================================================================
--- collections/trunk/cic-hcap/cic-hcap.col	(revision 14139)
+++ collections/trunk/cic-hcap/cic-hcap.col	(revision 14139)
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE GathererCollection [
+  <!ELEMENT GathererCollection (Argument*, GathererConfig, BuildConfig)>
+  <!ELEMENT GathererConfig    (Arguments*)>
+  <!ELEMENT BuildConfig       (Build, Import)>
+  <!ELEMENT Build             (Arguments*)>
+  <!ELEMENT Import            (Arguments*)>
+  <!ELEMENT Argument          (#PCDATA)>
+  <!ATTLIST Argument
+            name              CDATA #REQUIRED
+				enabled           CDATA "true">
+]>
+<GathererCollection>
+    <Argument name="built">false</Argument>
+    <Argument name="imported">true</Argument>
+    <GathererConfig/>
+    <BuildConfig>
+        <Build/>
+        <Import>
+            <Argument enabled="false" name="maxdocs">1</Argument>
+        </Import>
+    </BuildConfig>
+</GathererCollection>
Index: collections/trunk/cic-hcap/etc/collect.cfg
===================================================================
--- collections/trunk/cic-hcap/etc/collect.cfg	(revision 14139)
+++ collections/trunk/cic-hcap/etc/collect.cfg	(revision 14139)
@@ -0,0 +1,157 @@
+creator		mdewsnip@cs.waikato.ac.nz
+maintainer	mdewsnip@cs.waikato.ac.nz
+public		true
+
+buildtype	mgpp
+searchtype	plain form
+indexes		text Institution_name State PlaceType Architect Functions Time_period Style Materials Designation Reference ReferenceTitle ReferenceAuthor metadata
+levels		document section
+
+plugin		GAPlug
+plugin		CICPlug -cache_directory C:\\mdewsnip\\CIC\\Cache -images_directory C:\\mdewsnip\\CIC\\Images
+plugin		CICWordPlug
+plugin		ArcPlug 
+plugin		RecPlug -use_metadata_files 
+
+format AllowExtendedOptions true
+
+format DocumentHeading ""
+
+format DocumentText "
+&nbsp;</p>
+<table cellpadding=\"0\" cellspacing=\"0\" width=\"100%\" style=\"margin-top: -3em;\">
+{If}{[DocumentType] eq \"Place\",
+<tr>
+<td width=\"225\" style=\"padding-right: 1em;\">&nbsp;</td>
+<td><div class=\"cicheading\">[Current_name]</div></td>
+</tr>
+
+<tr>
+<td colspan=\"2\"><hr></td>
+</tr>
+
+<tr>
+<td valign=\"top\" style=\"padding-right: 1em;\">
+Click on image titles for larger views.<br />
+[PlaceImagesHTML]
+</td>
+
+<td valign=\"top\">
+<table cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">
+<tr>
+<td valign=\"top\" width=\"50%\">
+<b>Institution Name:</b> <a href=\"_gwcgi_?a=d&amp;d=i[Institution_ID]\">[Institution_name]</a><br />
+<b>Original/Historic Place Name:</b> [Original_or_historic_name]<br />
+<b>Location on Campus:</b> [Location_on_campus]<br />
+<b>Date(s) of Construction:</b>[PlaceConstructionDatesTableHTML]
+<b>Designer:</b> [Architect]<br />
+<b>Type of Place:</b> [PlaceType]<br />
+<b>Style:</b> [sibling(All\'\, \'):Style] <a href=\"_gwcgi_?a=p&amp;p=glossary\">(Glossary)</a><br />
+<b>Significance:</b> [sibling(All\'\, \'):Significance]<br />
+<b>Narrative:</b> <a href=\"#narrative\">see below</a><br />
+<b>References:</b> <a href=\"#references\">see below</a><br />
+</td>
+
+<td valign=\"top\">
+{If}{[PlaceType] eq \"Individual building\",
+<b>Materials:</b><br />
+<table id=\"cicplacematerialstable\" cellpadding=\"0\" cellspacing=\"0\">
+<tr><td>Foundation: [MaterialFoundation]</td></tr>
+<tr><td>Walls: [MaterialWalls]</td></tr>
+<tr><td>Roof: [MaterialRoof]</td></tr>
+</table>
+_cicblankline_
+}
+
+<b>Function:</b><br />[PlaceFunctionsTableHTML]
+</td>
+</tr>
+</table>
+
+_cicblankline_
+<hr>
+<a name=\"narrative\"></a><b>Narrative:</b><br />[PlaceNarrativeHTML]
+
+_cicblankline_
+<hr>
+<a name=\"references\"></a><b>References:</b><br />[PlaceReferencesHTML]
+</td>
+</tr>
+}
+
+{If}{[DocumentType] eq \"Institution\",
+<tr>
+<td width=\"100%\" valign=\"top\">
+<div class=\"cicheading\">[Institution_Name]</div>
+
+<p>[City]&#44; [State] [Zip]<br />
+[County] county<br />
+{If}{[Institution_webpage],<a href=\"[Institution_webpage]\">[Institution_webpage]</a>}</p>
+
+{If}{[InstitutionCampusPlansListHTML],<p><b>Campus plans:</b><br />[InstitutionCampusPlansListHTML]</p>}
+{If}{[InstitutionPlacesListHTML],<p><b>Places:</b><br />[InstitutionPlacesListHTML]</p>}
+</td>
+<td width=\"375\" valign=\"top\">
+<center>[InstitutionBestPlaceImageHTML]</center>
+</td>
+</tr>
+}
+
+{If}{[DocumentType] eq \"Designer\",
+<tr>
+<td width=\"100%\" valign=\"top\">
+<div class=\"cicheading\">[Designer_name]</div>
+_cicblankline_
+[DesignerPlacesListHTML]
+</td>
+</tr>
+}
+
+{If}{[DocumentType] eq \"Image\",
+<tr>
+<td width=\"100%\" valign=\"top\">
+<div class=\"cicheading\">[Title]</div>
+
+<center><p><img alt=\"[Title]\" src=\"[ImagePath]\"/></p></center>
+</td>
+</tr>
+}
+
+</table>
+"
+
+format SearchVList "
+<td valign=\"top\">
+{If}{[DocumentType] eq \"Place\",<a href=\"_gwcgi_?a=d&amp;d=[DocOID]\"><img alt=\"Place\" src=\"_httpimg_/itext.gif\"></a>}
+{If}{[DocumentType] eq \"Institution\",<a href=\"_gwcgi_?a=d&amp;d=[DocOID]\"><img alt=\"Institution\" src=\"_httpimg_/itext.gif\"></a>}
+{If}{[DocumentType] eq \"Designer\",<a href=\"_gwcgi_?a=d&amp;d=[DocOID]\"><img alt=\"Designer\" src=\"_httpimg_/itext.gif\"></a>}
+{If}{[DocumentType] eq \"PlaceReference\",<a href=\"_gwcgi_?a=d&amp;d=p[PlaceID]\"><img alt=\"Place\" src=\"_httpimg_/itext.gif\"></a>}
+</td>
+<td valign=\"top\">
+{If}{[DocumentType] eq \"Place\",<i>Place:</i> <a href=\"_gwcgi_?a=d&amp;d=[DocOID]\">[Current_name]</a>&#44; [Institution_name]}
+{If}{[DocumentType] eq \"Institution\",<i>Institution:</i> <a href=\"_gwcgi_?a=d&amp;d=[DocOID]\">[Institution_Name]</a>}
+{If}{[DocumentType] eq \"Designer\",<i>Designer:</i> <a href=\"_gwcgi_?a=d&amp;d=[DocOID]\">[Designer_name]</a>}
+{If}{[DocumentType] eq \"PlaceReference\",<i>Place Reference:</i> <a href=\"_gwcgi_?a=d&amp;d=p[PlaceID]\">[PlaceName]</a>&#44; [PlaceInstitutionName]<br />[Reference]}
+{If}{[DocumentType] eq \"Reference\",<i>Reference:</i> [Reference]}
+</td>"
+
+# Not used
+format DateList "<td>[link][icon][/link]</td>
+<td>[highlight]{Or}{[dls.Title],[dc.Title],[ex.Title],Untitled}[/highlight]</td>
+<td>[ex.Date]</td>"
+
+# Not used
+format HList "[link][highlight][ex.Title][/highlight][/link]"
+
+# Not used
+format VList "<td valign=top>[link][icon][/link]</td>
+<td valign=top>[ex.srclink]{Or}{[ex.thumbicon],[ex.srcicon]}[ex./srclink]</td>
+<td valign=top>[highlight]
+{Or}{[dls.Title],[dc.Title],[ex.Title],Untitled}
+[/highlight]{If}{[ex.Source],<br><i>([ex.Source])</i>}</td>"
+
+# Not used
+format DocumentButtons "Detach|Highlight"
+
+collectionmeta	collectionname [l=en] "CIC Historic Campus Architecture Project"
+collectionmeta	.document:text [l=en] "text"
Index: collections/trunk/cic-hcap/etc/main.cfg
===================================================================
--- collections/trunk/cic-hcap/etc/main.cfg	(revision 14139)
+++ collections/trunk/cic-hcap/etc/main.cfg	(revision 14139)
@@ -0,0 +1,263 @@
+# This file must be utf-8 encoded
+#
+# This is the main configuration file for configuring
+# your Greenstone receptionist (the bit responsible for the way
+# things are displayed) and contains information common
+# to the interface of all collections served by the site.
+
+# Email address of the webmaster of this Greenstone installation
+# If maintainer is set to "NULL" EmailEvents and EmailUserEvents
+# will be disabled.
+maintainer      NULL
+
+# Outgoing (SMTP) mail server for this Greenstone installation.
+# This will default to mail.maintainer-domain if it's not set
+# (i.e. if maintainer is greenstone@cs.waikato.ac.nz then MailServer
+# will default to mail.cs.waikato.ac.nz). If MailServer doesn't
+# resolve to a valid SMTP server then the EmailEvents and
+# EmailUserEvents options (see below) won't be functional. Likewise,
+# turning off EmailEvents and EmailUserEvents will remove any 
+# reliance on MailServer.
+MailServer      NULL
+
+# Set status to "disabled" if you don't want the Maintenance and
+# Administration facility to be available.
+status          enabled
+
+# Set collector to "disabled" if you don't want the "collector"
+# end-user collection building facility to be available.
+collector       disabled
+
+# Set gliapplet to "disabled" if you don't want the remote users
+# to be able to build collections on your server through an applet
+# version of GLI
+gliapplet       disabled
+
+# Set translator to "enabled" if you want the translation
+# service for keeping language fragments of macro text up to date 
+translator      disabled
+
+# Set logcgiargs to true to keep a log of usage information in
+# $GSDLHOME/etc/usage.txt.
+logcgiargs      false
+
+# Set usecookies to true to use cookies to identify users (cookie 
+# information will be written to the usage log if logcgiargs is
+# true).
+usecookies      false
+
+# LogDateFormat sets the format that timestamps will be stored in the usage
+# log (i.e. if logcgiargs is enabled). It takes the following values:
+# LocalTime: (the default) The local time and date in the form 
+#            "Thu Dec 07 23:47:00 NZDT 2000".
+# UTCTime: Coordinated universal time (GMT) in the same format as LocalTime.
+# Absolute: Integer value representing the number of seconds since 
+#           00:00:00 1/1/1970 GMT
+LogDateFormat   LocalTime
+
+# Log any events that Greenstone deems important in 
+# $GSDLHOME/etc/events.txt. 
+# The only events that are currently implemented come from the 
+# collector (e.g. someone just built/deleted the following collection)
+# LogEvents may take values of:
+# AllEvents: All important events
+# CollectorEvents: Just those events originating from the collector
+#                  (e.g. someone just built a collection)
+# disabled: Don't log events
+LogEvents       disabled
+
+# Email the maintainer whenever any event occurs. EmailEvents
+# takes the same values as LogEvents.
+# Note that perl must be installed for EmailEvents or
+# EmailUserEvents to work.
+EmailEvents     disabled
+
+# In some cases it may be appropriate to email the user about a
+# certain event (e.g. notification from the collector that a collection
+# was built successfully)
+EmailUserEvents false
+
+
+# The list of display macro files used by this receptionist
+macrofiles      tip.dm style.dm base.dm query.dm help.dm pref.dm about.dm \
+                document.dm browse.dm status.dm authen.dm users.dm html.dm \
+                extlink.dm gsdl.dm extra.dm home.dm collect.dm docs.dm \
+		bsummary.dm gti.dm garish.dm gli.dm \
+		english.dm english2.dm \
+		..\collect\cic-hcap\macros\institutions.dm \
+		..\collect\cic-hcap\macros\designers.dm \
+		..\collect\cic-hcap\macros\states.dm \
+		..\collect\cic-hcap\macros\types.dm \
+		..\collect\cic-hcap\macros\styles.dm \
+		..\collect\cic-hcap\macros\dates.dm \
+		..\collect\cic-hcap\macros\functions.dm
+
+# Define the interface languages and encodings supported by this receptionist
+
+# An "Encoding" line defines an encoding to be used by the receptionist.
+# Uncomment "Encoding" lines to include an encoding on your "preferences" page.
+# Encoding line options are:
+# shortname -- The standard charset label for the given encoding. The
+#              shortname option is mandatory.
+# longname  -- The display name of the given encoding. If longname isn't set
+#              it will default to using shortname instead.
+# map       -- The name of the map file (i.e. the .ump file) for use when
+#              converting between unicode and the given encoding. The map
+#              option is mandatory for all encoding lines except the
+#              special case for utf8.
+# multibyte -- This optional argument should be set for all encodings that use
+#              multibyte characters.
+
+# The utf8 encoding is handled internally and doesn't require a map file.
+# As a rule the utf8 encoding should always be enabled, especially if you
+# have collections of documents that may not all be in the same
+# language/encoding.
+Encoding shortname=utf-8 "longname=Unicode (UTF-8)"
+
+# This is very experimental, and you almost certainly don't need it
+#Encoding shortname=utf-16be "longname=Unicode (UTF-16BE)"
+
+# The ISO-8859 series
+Encoding shortname=iso-8859-1 "longname=Western (ISO-8859-1)" map=8859_1.ump
+#Encoding shortname=iso-8859-2 "longname=Central European (ISO-8859-2)" map=8859_2.ump
+#Encoding shortname=iso-8859-3 "longname=Latin 3 (ISO-8859-3)" map=8859_3.ump
+#Encoding shortname=iso-8859-4 "longname=Latin 4 (ISO-8859-4)" map=8859_4.ump
+#Encoding shortname=iso-8859-5 "longname=Cyrillic (ISO-8859-5)" map=8859_5.ump
+#Encoding shortname=iso-8859-6 "longname=Arabic (ISO-8859-6)" map=8859_6.ump
+#Encoding shortname=iso-8859-7 "longname=Greek (ISO-8859-7)" map=8859_7.ump
+#Encoding shortname=iso-8859-8 "longname=Hebrew (ISO-8859-8)" map=8859_8.ump
+#Encoding shortname=iso-8859-9 "longname=Turkish (ISO-8859-9)" map=8859_9.ump
+#Encoding shortname=iso-8859-15 "longname=Western (ISO-8859-15)" map=8859_15.ump
+
+# Windows codepages
+Encoding shortname=windows-1250 "longname=Central European (Windows-1250)" map=win1250.ump
+Encoding shortname=windows-1251 "longname=Cyrillic (Windows-1251)" map=win1251.ump
+#Encoding shortname=windows-1252 "longname=Western (Windows-1252)" map=win1252.ump
+Encoding shortname=windows-1253 "longname=Greek (Windows-1253)" map=win1253.ump
+Encoding shortname=windows-1254 "longname=Turkish (Windows-1254)" map=win1254.ump
+Encoding shortname=windows-1255 "longname=Hebrew (Windows-1255)" map=win1255.ump
+Encoding shortname=windows-1256 "longname=Arabic (Windows-1256)" map=win1256.ump
+#Encoding shortname=windows-1257 "longname=Baltic (Windows-1257)" map=win1257.ump
+#Encoding shortname=windows-1258 "longname=Vietnamese (Windows-1258)" map=win1258.ump
+#Encoding shortname=windows-874 "longname=Thai (Windows-874)" map=win874.ump
+#Encoding shortname=cp866 "longname=Cyrillic (DOS)" map=dos866.ump
+#Encoding shortname=cp850 "longname=Latin-1 (DOS)" map=dos850.ump
+
+# KOI8 Cyrillic encodings
+#Encoding shortname=koi8-r "longname=Cyrillic (KOI8-R)" map=koi8_r.ump
+#Encoding shortname=koi8-u "longname=Cyrillic (KOI8-U)" map=koi8_u.ump
+
+# CJK encodings (note that Shift-JIS Japanese isn't currently supported)
+Encoding shortname=gbk "longname=æ±è¯­ (Chinese Simplified GBK)" map=gbk.ump multibyte
+Encoding shortname=big5 "longname=æŒ¢èª (Chinese Traditional Big5)" map=big5.ump multibyte
+Encoding shortname=euc-jp "longname=Japanese (EUC)" map=euc_jp.ump multibyte
+Encoding shortname=euc-kr "longname=Korean (UHC)" map=uhc.ump multibyte
+
+
+# A "Language" line defines an interface language to be used by the
+# interface. Note that it is possible to display only a subset of the
+# specified languages on the preferences page for a given collection by
+# using the "PreferenceLanguages" format option in your collect.cfg
+# configuration file.
+# Arguments are:
+# shortname        -- ISO 639 two letter language symbol. The shortname
+#                     argument is mandatory.
+# longname         -- The display name for the given language. If longname
+#                     isn't set it will default to using shortname instead.
+# default_encoding -- The encoding to use by default when using the given
+#                     interface language. This should be set to the
+#                     "shortname" of a valid "Encoding" line
+# Language shortname=ar longname=Arabic default_encoding=windows-1256
+# Language shortname=bn "longname=àŠ¬àŠŸàŠàŠ²àŠŸ (Bengali)" default_encoding=utf-8
+# Language shortname=ca "longname=CatalÃ  (Catalan)" default_encoding=utf-8
+# Language shortname=cs "longname=Äesky (Czech)" default_encoding=utf-8
+# Language shortname=de "longname=Deutsch (German)" default_encoding=utf-8
+# Language shortname=el "longname=ÎÎ»Î»Î·ÎœÎ¹ÎºÎ¬ (Greek)" default_encoding=windows-1253
+Language shortname=en longname=English default_encoding=utf-8
+Language shortname=es "longname=EspaÃ±ol (Spanish)" \
+	 default_encoding=utf-8
+# Language shortname=fa longname=Farsi default_encoding=utf-8
+# Language shortname=fi longname=Finnish default_encoding=utf-8
+Language shortname=fr "longname=FranÃ§ais (French)" \
+	default_encoding=utf-8
+# Language shortname=gl longname=Galician default_encoding=utf-8
+# Language shortname=he longname=Hebrew default_encoding=windows-1255
+# Language shortname=hi longname=Hindi default_encoding=utf-8
+# Language shortname=hr longname=Croatian default_encoding=windows-1250
+# Language shortname=hy longname=Armenian default_encoding=utf-8
+# Language shortname=id "longname=Bahasa Indonesia (Indonesian)" default_encoding=utf-8
+# Language shortname=it longname=Italiano default_encoding=utf-8
+# Language shortname=ja "longname=æ¥æ¬èª (Japanese)" default_encoding=utf-8
+# Language shortname=ka longname=Georgian default_encoding=utf-8
+# Language shortname=kk "longname=ÒÐ°Ð·Ð°Ò (Kazakh)" default_encoding=utf-8
+# Language shortname=kn longname=Kannada default_encoding=utf-8
+# Language shortname=ky "longname=ÐÑÑÐ³ÑÐ·ÑÐ° (Kirghiz)" default_encoding=utf-8
+# Language shortname=lv longname=Latvian default_encoding=utf-8
+# Language shortname=mi "longname=MÄori" default_encoding=utf-8
+# Language shortname=mn "longname=ÐÐŸÐœÐ³ÐŸÐ» (Mongolian)" default_encoding=utf-8
+# Language shortname=nl "longname=Nederlands (Dutch)" default_encoding=utf-8
+# Language shortname=pl "longname=polski (Polish)" default_encoding=utf-8
+# Language shortname=pt-br "longname=portuguÃªs-BR (Brasil)" \
+#	default_encoding=utf-8
+# Language shortname=pt-pt "longname=portuguÃªs-PT (Portugal)" \
+#	default_encoding=utf-8
+Language shortname=ru "longname=ÑÑÑÑÐºÐžÐ¹ (Russian)" default_encoding=windows-1251
+# Language shortname=sr longname=Serbian default_encoding=utf-8
+# Language shortname=th longname=Thai default_encoding=utf-8
+# Language shortname=tr longname=Turkish default_encoding=windows-1254
+# Language shortname=uk longname=Ukrainian default_encoding=utf-8
+# Language shortname=vi "longname=Tiáº¿ng Viá»t (Vietnamese)" default_encoding=utf-8
+# Language shortname=zh "longname=ç®äœäž­æ (Simplified Chinese)" \
+# 	default_encoding=gbk
+# Language shortname=zh-tr "longname=ç¹é«äž­æ (Traditional Chinese)" default_encoding=big5
+
+
+# Define any additional page parameters to be used by the above macro files
+# (the current default page parameters are c (collection) and l (language)
+
+# Define v (version -- text or graphic) page parameter and give it a default
+# value of 0 (0 = text version off)
+pageparam       v 0
+
+# Set the precedence given to the page parameters. This effects which macro 
+# will be selected for display when there are multiple versions of the same 
+# macro with different page parameters.
+# e.g. Given a macroprecedence of "c,v,l" and the following macro definitions:
+# _content_ []
+# _content_ [l=en]
+# _content_ [c=demo]
+# _content_ [v=1]
+# _content_ [l=fr,v=1,c=hdl]
+# If the corresponding cgi arguments were set to l=en&v=1&c=hdl then the
+# _content_[v=1] macro would be selected for display. It would be selected 
+# ahead of the _content_[l=en] macro because "v" has a higher precedence 
+# than "l". The _content_[l=fr,v=1,c=hdl] macro would not be selected 
+# because one of the page parameters is completely wrong ("l").
+macroprecedence c,v,l
+
+
+# Define any additional cgi arguments. Most cgi arguments are built into
+# Greenstone but it's possible to define them here (or set defaults for
+# existing built-in cgi arguments).
+
+# define the "v" cgi argument (to correspond to the "v" page parameter defined
+# above).
+cgiarg          shortname=v longname=version multiplechar=false argdefault=0 \
+                defaultstatus=weak savedarginfo=must
+
+# set a default value for the built-in "a" cgi argument
+cgiarg          shortname=a argdefault=p
+
+# set the default encoding to utf-8
+cgiarg          shortname=w argdefault=utf-8
+ cgiarg          shortname=l argdefault=en 
+
+# CIC default settings
+cgiarg	    shortname=c argdefault=cic-hcap
+cgiarg      shortname=p argdefault=home
+cgiarg	    shortname=fqk argdefault=0,0,0,0,0,0,0
+cgiarg	    shortname=fqs argdefault=0,0,0,0,0,0,0
+cgiarg	    shortname=g argdefault=Doc
+cgiarg	    shortname=o argdefault=50
+cgiarg	    shortname=qf argdefault=1
+cgiarg	    shortname=qt argdefault=1
Index: collections/trunk/cic-hcap/help/cic-hcap.html
===================================================================
--- collections/trunk/cic-hcap/help/cic-hcap.html	(revision 14139)
+++ collections/trunk/cic-hcap/help/cic-hcap.html	(revision 14139)
@@ -0,0 +1,74 @@
+<html>
+<head>
+<title>CIC: Historic Campus Architecture Project</title>
+</head>
+
+<body>
+<h1>CIC: Historic Campus Architecture Project</h1>
+
+The CIC Historic Campus Architecture Project (HCAP) collection contains records from a survey of architecture in colleges represented by CIC. A Microsoft Access database contains the textual information from the survey, and also links to the place images (stored separately).
+
+<h2>Configuration</h2>
+
+The HCAP collection was developed with Greenstone v2.62, and is unlikely to work with other versions. It does not have a collection-specific receptionist, but has a collection-specific plugin and highly customised macrofiles.
+
+<p>
+The steps involved to install this collection on a new computer are:
+
+<ol>
+<li>Install Greenstone v2.62.
+<li>Copy the place images from the CIC server onto the computer.
+<li>Copy the "cic-hcap" collection folder into the Greenstone "collect" directory.
+<li>Copy the "cic-hcap\main.cfg" file into the Greenstone "etc" directory.
+<li>Copy the "cic-hcap\bin\windows\perl\lib\DBI.pm" file into the Greenstone "bin\windows\perl\lib" directory.
+<li>Copy the "cic-hcap\bin\windows\perl\site" directory into the Greenstone "bin\windows\perl" directory.
+<li>Copy the current version of the database into the "cic-hcap\import" folder.
+<li>Create an ODBC Data Source for the collection database:
+  <p>
+  Start -> Control Panel -> Administrative Tools -> Data Sources (ODBC)
+  <p>
+  Add Microsoft Access Driver (*.mdb) source "CIC-HCAP" for the collection database (in the "cic-hcap\import" directory).
+</ol>
+
+<h2>Rebuilding the collection</h2>
+
+<ol>
+<li>Close Microsoft Access if it is running. (You should not edit the database while the collection is building).
+<li>Run the Greenstone Local Library (Start -> Program Files -> Greenstone Digital Library -> Greenstone Librarian Interface).
+<li>Open the "CIC Historic Campus Architecture Project" collection.
+<li>Change to the Design pane, then choose "Document Plugins", then configure the "CICPlug" plugin. Check that the "-images_directory" and "-cache_directory" options are correct, and the "-michael_mode" option isn't on.
+<li>Change to the Create pane and click "Build Collection". Check the building output for errors.
+<li>Click "Preview Collection" to view the built collection.
+</ol>
+
+<h2>Implementation notes</h2>
+
+The key files for this collection are:
+
+<dl>
+  <dt><b>etc/collect.cfg</b></dt>
+  <dd>Contains format statements for generating the place, institution and designer display pages.</dd>
+  <p>
+  <dt><b>macros/extra.dm</b></dt>
+  <dd>Contains macros for the customised look of the collection and all of the static pages.</dd>
+  <p>
+  <dt><b>perllib/plugins/CICPlug.pm</b></dt>
+  <dd>This plugin uses DBI to extract the places, institutions and designers out of the database; processes the place images; and writes the static macrofiles for the browse pages.</dd>
+</dl>
+
+<h2>Editing collection text</h2>
+
+Static text within the collection can be changed by editing the macros/extra.dm file. Search for the text you want to change and edit it, taking care with HTML tags.
+<p>
+Refresh the browser window to see the effect of your changes (you do not need to restart the Greenstone Local Library).
+
+<!--
+<h2>Future work?</h2>
+
+<ul>
+<li>Make "designer" field of places a link.
+</ul>
+-->
+
+</body>
+</html>
Index: collections/trunk/cic-hcap/macros/.cvsignore
===================================================================
--- collections/trunk/cic-hcap/macros/.cvsignore	(revision 14139)
+++ collections/trunk/cic-hcap/macros/.cvsignore	(revision 14139)
@@ -0,0 +1,7 @@
+dates.dm
+designers.dm
+functions.dm
+institutions.dm
+states.dm
+styles.dm
+types.dm
Index: collections/trunk/cic-hcap/macros/anylink.js
===================================================================
--- collections/trunk/cic-hcap/macros/anylink.js	(revision 14139)
+++ collections/trunk/cic-hcap/macros/anylink.js	(revision 14139)
@@ -0,0 +1,125 @@
+/***********************************************
+* AnyLink Drop Down Menu- © Dynamic Drive (www.dynamicdrive.com)
+* This notice MUST stay intact for legal use
+* Visit http://www.dynamicdrive.com/ for full source code
+***********************************************/
+
+/////No further editting needed
+
+var ie4=document.all
+var ns6=document.getElementById&&!document.all
+
+if (ie4||ns6)
+document.write('<div id="dropmenudiv" style="visibility:hidden;width:'+menuwidth+';background-color:'+menubgcolor+'" onMouseover="clearhidemenu()" onMouseout="dynamichide(event)"></div>')
+
+function getposOffset(what, offsettype){
+var totaloffset=(offsettype=="left")? what.offsetLeft : what.offsetTop;
+var parentEl=what.offsetParent;
+while (parentEl!=null){
+totaloffset=(offsettype=="left")? totaloffset+parentEl.offsetLeft : totaloffset+parentEl.offsetTop;
+parentEl=parentEl.offsetParent;
+}
+return totaloffset;
+}
+
+
+function showhide(obj, e, visible, hidden, menuwidth){
+if (ie4||ns6)
+dropmenuobj.style.left=dropmenuobj.style.top=-500
+if (menuwidth!=""){
+dropmenuobj.widthobj=dropmenuobj.style
+dropmenuobj.widthobj.width=menuwidth
+}
+if (e.type=="click" && obj.visibility==hidden || e.type=="mouseover")
+obj.visibility=visible
+else if (e.type=="click")
+obj.visibility=hidden
+}
+
+function iecompattest(){
+return (document.compatMode && document.compatMode!="BackCompat")? document.documentElement : document.body
+}
+
+function clearbrowseredge(obj, whichedge){
+var edgeoffset=0
+if (whichedge=="rightedge"){
+var windowedge=ie4 && !window.opera? iecompattest().scrollLeft+iecompattest().clientWidth-15 : window.pageXOffset+window.innerWidth-15
+dropmenuobj.contentmeasure=dropmenuobj.offsetWidth
+if (windowedge-dropmenuobj.x < dropmenuobj.contentmeasure)
+edgeoffset=dropmenuobj.contentmeasure-obj.offsetWidth
+}
+else{
+var topedge=ie4 && !window.opera? iecompattest().scrollTop : window.pageYOffset
+var windowedge=ie4 && !window.opera? iecompattest().scrollTop+iecompattest().clientHeight-15 : window.pageYOffset+window.innerHeight-18
+dropmenuobj.contentmeasure=dropmenuobj.offsetHeight
+if (windowedge-dropmenuobj.y < dropmenuobj.contentmeasure){ //move up?
+edgeoffset=dropmenuobj.contentmeasure+obj.offsetHeight
+if ((dropmenuobj.y-topedge)<dropmenuobj.contentmeasure) //up no good either?
+edgeoffset=dropmenuobj.y+obj.offsetHeight-topedge
+}
+}
+return edgeoffset
+}
+
+function populatemenu(what){
+if (ie4||ns6)
+dropmenuobj.innerHTML=what.join("")
+}
+
+
+function dropdownmenu(obj, e, menucontents, menuwidth){
+if (window.event) event.cancelBubble=true
+else if (e.stopPropagation) e.stopPropagation()
+clearhidemenu()
+dropmenuobj=document.getElementById? document.getElementById("dropmenudiv") : dropmenudiv
+populatemenu(menucontents)
+
+if (ie4||ns6){
+showhide(dropmenuobj.style, e, "visible", "hidden", menuwidth)
+dropmenuobj.x=getposOffset(obj, "left")
+dropmenuobj.y=getposOffset(obj, "top")
+dropmenuobj.style.left=dropmenuobj.x-clearbrowseredge(obj, "rightedge")+"px"
+dropmenuobj.style.top=dropmenuobj.y-clearbrowseredge(obj, "bottomedge")+obj.offsetHeight+"px"
+}
+
+return clickreturnvalue()
+}
+
+function clickreturnvalue(){
+if (ie4||ns6) return false
+else return true
+}
+
+function contains_ns6(a, b) {
+while (b.parentNode)
+if ((b = b.parentNode) == a)
+return true;
+return false;
+}
+
+function dynamichide(e){
+if (ie4&&!dropmenuobj.contains(e.toElement))
+delayhidemenu()
+else if (ns6&&e.currentTarget!= e.relatedTarget&& !contains_ns6(e.currentTarget, e.relatedTarget))
+delayhidemenu()
+}
+
+function hidemenu(e){
+if (typeof dropmenuobj!="undefined"){
+if (ie4||ns6)
+dropmenuobj.style.visibility="hidden"
+}
+}
+
+function delayhidemenu(){
+if (ie4||ns6)
+delayhide=setTimeout("hidemenu()",disappeardelay)
+}
+
+function clearhidemenu(){
+if (typeof delayhide!="undefined")
+clearTimeout(delayhide)
+}
+
+if (hidemenu_onclick=="yes")
+document.onclick=hidemenu
Index: collections/trunk/cic-hcap/macros/extra.dm
===================================================================
--- collections/trunk/cic-hcap/macros/extra.dm	(revision 14139)
+++ collections/trunk/cic-hcap/macros/extra.dm	(revision 14139)
@@ -0,0 +1,2079 @@
+# ------------------------------------------------------------------------------------------
+#   GLOBAL
+# ------------------------------------------------------------------------------------------
+
+package Global
+
+# Remove the Greenstone bar down the left-hand side
+_httpiconchalk_ {}
+
+# Don't display any of the Greenstone horizontal bars
+_iconblankbar_ {}
+
+# Wider than usual pages
+_pagewidth_ {100%}
+
+# Turn off highlighting within text
+_starthighlight_ {}
+_endhighlight_ {}
+
+# Convenience macro for a HTML 4 compliant blank line
+_cicblankline_ {<div>&nbsp;</div>}
+
+# Custom navigation bar
+_cicnavigationbar_ {
+<div class="cicprinthide">
+  <ul id="topnav">
+    <li>_cicaboutmenu_</li>
+    <li>_cicbrowsemenu_</li>
+    <li>_cicsearchmenu_</li>
+    <li id="btn_quick">_query:cicsimplequeryform_</li>
+  </ul>
+</div>
+}
+
+_cicaboutmenu_ {<a id="btn_about" href="_gwcgi_?a=p&amp;p=home" onClick="clickreturnvalue()" onMouseover="dropdownmenu(this, event, aboutmenu, '233px')" onMouseout="delayhidemenu()">About</a>}
+
+_cicbrowsemenu_ {<a id="btn_browse" href="_gwcgi_?a=p&amp;p=institutions" onClick="clickreturnvalue()" onMouseover="dropdownmenu(this, event, browsemenu, '233px')" onMouseout="delayhidemenu()">Browse</a>}
+
+_cicsearchmenu_ {<a id="btn_search" href="_gwcgi_?a=q" onClick="clickreturnvalue()" onMouseover="dropdownmenu(this, event, searchmenu, '233px')" onMouseout="delayhidemenu()">Search</a>}
+
+
+
+# ------------------------------------------------------------------------------------------
+#   STYLE
+# ------------------------------------------------------------------------------------------
+
+package Style
+
+# Pages have a common style: page banner, then navigation bar, then page content
+_content_ {
+_pagebanner_
+
+_cicnavigationbar_
+
+_cicpagecontent_
+}
+
+_header_ {_cicheader_}
+
+_cicheader_ {
+_cgihead_
+_htmlhead_(_1_)_startspacer_
+}
+
+_cicmenujavascript_ {
+<script type="text/javascript">
+   var menuwidth = '165px'          // default menu width
+   var menubgcolor = 'lightyellow'  // menu bgcolor
+   var disappeardelay = 250         // menu disappear speed onMouseout (in milliseconds)
+   var hidemenu_onclick = "yes"     // hide menu when user clicks within menu?
+
+   // Contents of the "about" menu
+   var aboutmenu = new Array()
+   aboutmenu[0] = '<a href="_gwcgi_?a=p&p=background">Project background<\\/a>'
+   aboutmenu[1] = '<a href="_gwcgi_?a=p&p=copyright">Copyright information<\\/a>'
+   aboutmenu[2] = '<a href="_gwcgi_?a=p&p=documents">Application documents<\\/a>'
+   aboutmenu[3] = '<a href="_gwcgi_?a=p&p=releases">News coverage<\\/a>'
+   aboutmenu[4] = '<a href="_gwcgi_?a=p&p=glossary">Glossary<\\/a>'
+   aboutmenu[5] = '<a href="_gwcgi_?a=p&p=links">Links for further research<\\/a>'
+
+   // Contents of the "browse" menu
+   var browsemenu = new Array()
+   browsemenu[0] = '<a href="_gwcgi_?a=p&p=institutions">Institutions by name<\\/a>'
+   browsemenu[1] = '<a href="_gwcgi_?a=p&p=states">Institutions by state<\\/a>'
+   browsemenu[2] = '<a href="_gwcgi_?a=p&p=types">Places by type<\\/a>'
+   browsemenu[3] = '<a href="_gwcgi_?a=p&p=designers">Places by designer<\\/a>'
+   browsemenu[4] = '<a href="_gwcgi_?a=p&p=styles">Places by building style<\\/a>'
+   browsemenu[5] = '<a href="_gwcgi_?a=p&p=functions">Places by function<\\/a>'
+   browsemenu[6] = '<a href="_gwcgi_?a=p&p=dates">Places by time period<\\/a>'
+
+   // Contents of the "search" menu
+   var searchmenu = new Array()
+   searchmenu[0] = '<a href="_gwcgi_?a=q&qst=1">Institutions by state/region<\\/a>'
+   searchmenu[1] = '<a href="_gwcgi_?a=q&qre=1">Bibliography search<\\/a>'
+   searchmenu[2] = '<a href="_gwcgi_?a=q">Advanced search<\\/a>'
+
+_anylink:anylinkjavascript_
+
+</script>
+}
+
+# May be overridden by individual pages
+_cicpagejavascript_ {}
+
+
+
+# htmlhead uses:
+# _1_ - extra parameters for the body tag
+# _pagetitle_
+# _globalscripts_
+_htmlhead_ {
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html_htmlextra_>
+<head>
+<title>_pagetitle_</title>
+<link rel="stylesheet" href="_httpcollection_/macros/style.css" type="text/css"/>
+_cicmenujavascript_
+_query:cicjavascript_
+_cicpagejavascript_
+</head>
+
+<body bgcolor="\#ffffff" text="\#000000" link="\#006666" alink="\#cc9900" vlink="\#006666" _1_>
+<div class="ciccontent">
+}
+
+_htmlfooter_ {
+_cicblankline_
+<hr>
+<center>
+<a href="mailto:cic@cic.nche.edu">Contact us</a> / <a href="_gwcgi_?a=p&amp;p=home">About Site</a> / <a href="http://www.cic.edu">About CIC</a><br />
+&copy; 2006<br />
+Council of Independent Colleges<br />
+Washington, DC<br />
+All rights reserved<br />
+Last update: November 2006<br />
+</center>
+</div>
+
+</body>
+</html>
+}
+
+# We use a very simple pagebanner: just the collection icon, no javalinks etc
+_pagebanner_ {<a href="_gwcgi_?a=p&amp;p=home"><img class="cicmastheadimage" alt="Council of Independent Colleges Historic Campus Architecture Project" src="_httpcollection_/images/masthead.gif"></a>}
+
+_pagetitle_ {The Council of Independent Colleges: Historic Campus Architecture Project}
+
+# No left margin
+_startspacer_ {}
+_endspacer_ {}
+
+
+
+# ------------------------------------------------------------------------------------------
+#   HOME
+# ------------------------------------------------------------------------------------------
+
+package home
+
+_cicpagejavascript_ {
+<script type="text/javascript">
+var photos = new Array();
+photos[1] = "Timothy Alden and Alexander Temple, <i>Bentley Hall<\\/i> (1820), Allegheny College (PA)";
+photos[2] = "James Key Wilson (Walter & Wilson), <i>Old Main (view from the southwest)<\\/i> (1858-71 and later), Bethany College (WV)";
+photos[3] = "Marcel Breuer, <i>Abbey Church and Bell Tower<\\/i> (1958-61), Saint John's University (MN)";
+photos[4] = "John Shaver & Co., <i>Eugene E. Clossen Physical Education Center<\\/i> (1967), Graceland University (IA)";
+photos[5] = "<i>East Hall<\\/i> (1909), Oakwood College, Huntsville (AL)";
+photos[6] = "<i>Ralston Hall (view from the northwest)<\\/i> (late 1860s), Notre Dame de Namur University (CA)";
+photos[7] = "O'Meara and Hills & G.E. Quick, <i>Our Lady Queen of Peace Chapel and College Library<\\/i> (1938), College of St. Scholastica (MN)";
+photos[8] = "Fonthill Castle 1852, orig. constr.; 1872 add'n), College of Mount Saint Vincent (NY)";
+photos[9] = "Gordon Kaufman, Edward Huntsman-Trout, and others, <i>Jaqua Quadrangle<\\/i> (1926-73), Scripps College (CA)";
+photos[10] = "T. D. McLaughlin and Oliver Davidson, <i>Musselman Library<\\/i> (1929-30), Bluffton University (OH)";
+photos[11] = "John CarrÃšre & Thomas Hastings,<i>Hotel Ponce de Leon and Residence Hall<\\/i> (1885-88), Flagler College (FL)"; 
+photos[12] = "";
+photos[13] = "Peabody & Stearns, <i>Rosary Hall<\\/i> (1905), Albertus Magnus College (CT)";
+photos[14] = "<i>John Umble Center or the Performing Arts<\\/i> (1976-79), Goshen College (IN)";
+photos[15] = "<i>Old Main (Hauptgebaude)<\\/i> Elmhurst College (IL)";
+photos[16] = "Tallman & Tallman, <i>Dillingham Center<\\/i> (1969), Ithaca College (NY)";
+photos[17] = "Philip Johnson, <i>Chapel of St. Basil<\\/i> 1957, orig. master plan; 1997 chapel completed), University of St. Thomas (TX)";
+photos[18] = "<i>Cast iron gazebo<\\/i> (early 19th century), at center of gardens at Belmont University (TN)";
+photos[19] = "";
+
+window.onload = function() \{
+   // Function called when page loads
+   if (!document.getElementById) return;
+   if (!document.getElementById('cichomephoto')) return;
+
+   var rand = get_random(photos.length);
+   var photo = document.getElementById('cichomephoto');
+   photo.setAttribute('src', '_httpcollection_/images/mainphoto/' + rand + '.jpg');
+   photo.setAttribute('alt', photos[rand]); 
+
+   var caption = document.getElementById('cichomephotocaption');
+   caption.innerHTML = photos[rand];
+\}
+
+function get_random(max) \{
+   var randNum = Math.floor(Math.random()*(max-1))+1;
+   return randNum;
+\}
+</script>
+}
+
+_cicpagecontent_ {
+<table cellspacing="0" cellpadding="0">
+  <tr>
+    <td id="cichomephotoarea" valign="top">
+      <img id="cichomephoto" src="_httpcollection_/images/mainphoto/blank.gif" alt="HCAP Photo" /><br />
+      <span id="cichomephotocaption">&nbsp;</span>
+    </td>
+
+    <td id="cichometext" valign="top">
+      <div class="cicheading">Welcome</div>
+
+      <p>Welcome to the CIC Historic Campus Architecture Project (HCAP), the first national architecture and landscape database of independent college and university campuses. This project presents information about significant buildings, landscapes, campus plans, and heritage sites of American higher education and identifies sources for further research. Supported by grants from the Getty Foundation, the CIC HCAP website documents nearly 2,000 places of historical significance on private college and university campuses and includes more than 4,300 images relating to these sites. To date, nearly 370 institutions have participated. On this site, web users can find institutions or places in a particular state or region; seek information about a specific type of architecture, designer, or time period; or gather data for future research.</p>
+
+      <p><b>List of Participating Institutions</b>: <a href="http://www.cic.org/projects_services/grants/getty_participants.pdf">Click here</a> to view the list of institutions and sites that are included in the CIC HCAP database. <br /><span style="font-size: 0.8em; line-height: 1.6em;">(This file is in PDF format. To view, you will need Adobe Acrobat, available for free from the <a href="http://www.adobe.com/products/acrobat/readermain.html">Adobe website</a>.)</span></p>
+    </td>
+  </tr>
+</table>
+}
+
+
+
+# ------------------------------------------------------------------------------------------
+#   BACKGROUND  (About -> Project Background)
+# ------------------------------------------------------------------------------------------
+
+package background
+
+_cicpagecontent_ {
+<div class="cicheading">Project Background</div>
+
+<p>In recent years, the study of campus history has received increasing interest in and attention by many sectors of the educational community. Institutions are working to understand more completely their physical environments and how these relate to educational mission, as well as wider historical trends. The CIC HCAP survey data and website have been developed to help various constituencies gain an awareness of and appreciation for campus history and also to learn from the architecture and landscape preservation efforts made by institutions.</p>
+
+<p>Between 2002 and 2006, the CIC HCAP was supported by two generous grants from the Campus Heritage Initiative of the Getty Foundation. From 2002-2004, CIC developed a survey to collect information about places of significant historical interest (in relation to architecture, landscape, American history, and the histories of education, religion, engineering, and culture) identified by representatives of institutions themselves. This survey was distributed among 724 independent, four-year, B.A.-granting institutions with less than 5,000 students. Nearly 50 percent of this original group participated in the project. In 2005, CIC began website development with a second two-year grant from the Getty Foundation.</p>
+
+<p>The CIC HCAP was guided by an advisory committee and developed by the coordinated efforts of a team of people from HCAP, CIC, and several independent professionals with whom HCAP contracted for specific services.</p>
+
+_cicblankline_
+<i>Advisory committee</i>
+
+<p><b>Thomas C. Celli</b>, President, Celli-Flynn Brennan, Architects and Planners (PA)</p>
+
+<p><b>Jeffrey A. Cohen</b>, Senior Lecturer, Bryn Mawr College</p>
+
+<p><b>Russell V. Keune</b>, Former Director of International Relations at the American Institute of Architects</p>
+
+<p><b>Randall Mason</b>, Associate Professor of Architecture, Graduate Program in Historic Preservation, School of Design, University of Pennsylvania</p>
+
+<p><b>Therese O'Malley</b>, Associate Dean of the Center for Advanced Study in the Visual Arts, National Gallery of Art in Washington, DC</p>
+
+<p><b>Damie Stillman</b>, Professor of Art History Emeritus, University of Delaware</p>
+
+<p><b>John Strassburger</b>, President, Ursinus College (PA)</p>
+
+_cicblankline_
+<i>CIC HCAP staff</i>
+
+<p><b>Barbara S. Christen</b>, Project Director<br />
+Project planning and management</p>
+
+<p><u>Part-time personnel:</u></p>
+
+<p><b>Jennifer M. Baggot</b>, Research Associate<br />
+Data input, document scanning, project correspondence, editing</p>
+
+<p><b>Jennifer R. D'Urso</b>, Research Associate<br />
+Data evaluation, database development, project research</p>
+
+<p><b>Lael J. Ensor</b>, Research Associate<br />
+Data editing, bibliographic research</p>
+
+<p><b>Amanda L. Hockensmith</b>, Research Associate<br />
+Data input and editing, design development</p>
+
+<p><b>Jane E. Lesnick</b>, Research Associate<br />
+Data editing, bibliographic research</p>
+
+<p><b>Matthew E. Linder</b>, Research Assistant<br />
+Data input, bibliographic research</p>
+
+<p><b>Timothy J. Mackin</b>, Research Associate<br />
+Data input and editing, data evaluation</p>
+
+<p><b>Christina Myers</b>, Research Associate<br />
+Data editing, bibliographic research</p>
+
+<p><b>Marianne S. Percival</b>, Research Associate<br />
+Data collection, project correspondence, project and bibliographic research</p>
+
+<p><b>Honora Shea</b>, Research Assistant<br />
+Data input, project correspondence</p>
+
+_cicblankline_
+<i>CIC staff</i>
+
+<p><b>Richard H. Ekman</b>, President<br />
+Project management</p>
+
+<p><b>Frederik Ohles</b>, Vice President for Advancement<br />
+Project liaison</p>
+
+<p><b>Laura A. Wilcox</b>, Vice President for Communications<br />
+Public relations, graphic design development</p>
+
+<p><b>August A. Adams</b>, Communications and Web Manager<br />
+Web postings, graphic design evaluation</p>
+
+_cicblankline_
+<i>Consultants</i>
+
+<p><b>Rodolfo Castro</b>, Catalone Design Company<br />
+Graphic and interface design</p>
+
+<p><b>Michael Collinson and Joseph Reggetz</b>, Business Engineering Incorporated<br />
+Hardware and server consultation</p>
+
+<p><b>Michael Dewsnip</b>, New Zealand Digital Library Project, University of Waikato<br />
+Greenstone software customization and development</p>
+
+<p><b>Joyce Essel</b>, Independent consultant<br />
+Database development</p>
+
+<p><b>Brian Harrington</b>, Independent consultant<br />
+Software and hardware consultation</p>
+
+<p><b>Stephen Rutz</b>, Steve Rutz Software<br />
+Database consultation</p>
+
+<p><b>David Seaman</b>, Executive Director, Digital Library Federation<br />
+Management and software consultation</p>
+
+<p><b>Allison Zhang</b>, Independent consultant<br />
+Software consultation</p>
+
+_cicblankline_
+<i>Site Design and Development</i>
+
+<p><b>Catalone Design Company</b> of Bethesda, Maryland, provided graphic and interface design for the website. For more information, see <a href="http://www.catalonedesign.com/">www.catalonedesign.com</a>.</p>
+
+<p><b>Greenstone</b>, a software package developed by the New Zealand Digital Library Project at the University of Waikato, generates web pages dynamically in response to users navigating through the site. This has many advantages, including seamless search integration and the ability to instantly change the look and feel of the site. Search indexes and browsing structures are also precomputed, for quick browsing and searching.</p>
+
+<p>The CIC Historic Campus Architecture Project collection uses two purpose-built plugins to process the project data files. One plugin processes the Microsoft Access database used to store the data from the survey, generating a Greenstone "object" for each of the institutions, places, designers and references. It also generates small (thumbnail), medium, and large versions of each place image, and the site "browse" pages. The second plugin processes the Microsoft Word file containing bibliographic references not associated with particular places in the database.</p>
+
+<p>As well as having highly-customized document importing programs, the CIC HCAP collection has a completely customized design and user interface. This was implemented using Greenstone's formatting and macro languages, with over 120 new or customized macros. For more information about Greenstone, see <a href="http://www.greenstone.org/">www.greenstone.org</a>.</p>
+
+_cicblankline_
+<i>Server Technical Information</i>
+
+<p>The CIC HCAP site runs on a Intel Pentium III server class machine with 512MB of RAM and 140GB of disk space. The site is currently hosted in Hamilton, New Zealand but in the future will be hosted on the CIC's servers in Washington, DC.</p>
+
+_cicblankline_
+<hr>
+<p>The <b>Council of Independent Colleges</b> is an association of more than 560 independent, liberal arts colleges and universities and higher education affiliates and organizations that work together to strengthen college and university leadership, sustain high-quality education, and enhance private higher education's contributions to society. To fulfill this mission, CIC provides its members with skills, tools, and knowledge that address aspects of leadership, financial management and performance, academic quality, and institutional visibility. The Council is headquartered at One Dupont Circle in Washington, DC.</p>
+
+<p><b>The Getty Foundation</b> provides support to institutions and individuals throughout the world, funding a diverse range of projects that promote the understanding and conservation of the visual arts. The grant-making foundation furthers the work of all Getty Programs. The Foundation also encompasses the Getty Leadership Institute, the leading source of continuing professional development for current and future museum leaders. For more information, see: <a href="http://www.getty.edu">www.getty.edu</a>.</p>
+}
+
+
+
+# ------------------------------------------------------------------------------------------
+#   COPYRIGHT   (About -> Copyright Information)
+# ------------------------------------------------------------------------------------------
+
+package copyright
+
+_cicpagecontent_ {
+<div class="cicheading">Copyright and Permissions Information for CIC Historic Campus Architecture Project</div>
+
+<p>We ask you to adhere to the terms under which these materials are made available. The CIC Historic Campus Architecture Project as a whole, its texts, and its images are protected under the copyright laws of the United States and the Universal Copyright Convention. The copyright to the CIC Survey is held by the Council of Independent Colleges. The copyright to the images is held by the institutions and individuals who have generously contributed them.</p>
+
+<p>Publication (print or electronic) or commercial use of any of the copyrighted materials without direct authorization from the copyright holders is prohibited. The copying of materials is permitted only under the fair-use provisions of copyright law. To obtain the right to reuse an image, in most cases, permission must be obtained from the owning institution.</p>
+
+<p>The Library of Congress provides useful information on copyright at <a href="http://lcweb.loc.gov/copyright">http://lcweb.loc.gov/copyright</a> as well as an explanation of the fair-use doctrine at <a href="http://fairuse.stanford.edu">http://fairuse.stanford.edu</a>.</p>
+
+<hr>
+<p><i>Web Links</i>: It is not necessary to request permission in order to link to the CIC Survey from your website; however, we prefer that links be targeted to the introductory page of the CIC Survey (http://www.cicsurvey.org), and that any links to individual items be accompanied by a link to the introduction page.</p>
+
+<p><i>Citations</i>: To identify the CIC Survey as the source of information that you are using in a paper, article, or book, we ask that you include the complete title of the CIC Survey, its URL, and the date you accessed it, along with other relevant documentation. Here is an example: "Narrative History of Agnes Scott Hall, at Agnes Scott College," <i>Council of Independent Colleges Historic Campus Architecture Project</i>. 13 November 2005 &lt;http://www.cicsurvey.org&gt;.</p>
+
+<p>By accessing the Survey, you acknowledge that you have read and accepted these conditions.</p>
+}
+
+
+
+# ------------------------------------------------------------------------------------------
+#   RELEASES  (About -> News Coverage)
+# ------------------------------------------------------------------------------------------
+
+package releases
+
+_cicpagecontent_ {
+<div class="cicheading">News Coverage</div>
+_cicblankline_
+
+<p class="cicreference">Biemiller, Lawrence. "From Modest to Magnificent." <i>The Chronicle of Higher Education</i> 52, no. 29 (March 24, 2006): A34-A35.</p>
+
+<p class="cicreference">Rubman, Kerri. "Getty Campus Grants Promote Preservation Planning." <i>Forum News</i> (March/April 2005): 3.</p>
+
+<p class="cicreference"><a href="http://www.cic.org/publications/independent/online/spring2005/getty_grant.htm">"CIC Receives Second Getty Grant for Historic Campus Architecture and Design Project."</a> <i>Independent</i>, newsletter of the Council of Independent Colleges (Spring 2005): 18-19.</p>
+
+<p class="cicreference">Munitz, Barry. "Place and History Matter on All Campuses." <i>The Chronicle of Higher Education</i> 51, no. 9 (October 22, 2004): B15.</p>
+
+<p class="cicreference"><a href="http://www.cic.org/publications/independent/online/summer2004/historic_architecture.html">"CIC Develops Historic Architecture Database."</a> <i>Independent</i>, newsletter of the Council of Independent Colleges (Summer 2004): 11.</p>
+
+<p class="cicreference">Arenson, Karen W. "Regilding a Stanford White Landmark." <i>New York Times</i>, July 30, 2004, C13 (national edition).</p>
+
+<p class="cicreference">Christen, Barbara S. "The Council of Independent Colleges Survey of Historic Architecture and Design: Research Issues in Landscape Studies." <i>Vineyard</i> 5, no. 1 (2004): 8-10.</p>
+
+<p class="cicreference"><a href="http://www.cic.org/publications/independent/online/summer2003/historic_arch.html">"Hundreds Respond to CIC Survey On Historic Architecture."</a> <i>Independent</i>, newsletter of the Council of Independent Colleges (Summer 2003): 8.</p>
+}
+
+
+
+# ------------------------------------------------------------------------------------------
+#   DOCUMENTS  (About -> Application Documents)
+# ------------------------------------------------------------------------------------------
+
+package documents
+
+_cicpagecontent_ {
+<div class="cicheading">Application Documents</div>
+
+<p>To view the application documents from phase one, click on the links below. (In order to view the PDF files, the minimum software requirement is version 4.0 Adobe Acrobat, available for free from the <a href="http://www.adobe.com/products/acrobat/readermain.html">Adobe web site</a>.)</p>
+
+<a href="http://www.cic.org/projects_services/grants/getty_letter.asp">Letter of Instruction to Campus Liaison</a><br />
+<a href="http://www.cic.org/projects_services/grants/getty_questionnaire.pdf">Questionnaire</a> (PDF)<br />
+<a href="http://www.cic.org/projects_services/grants/getty_definitions.pdf">Definitions and Visual Examples</a> (PDF)<br />
+<a href="http://www.cic.org/projects_services/grants/getty_guidelines.pdf">Submission Guidelines</a> (PDF)<br />
+}
+
+
+
+# ------------------------------------------------------------------------------------------
+#   GLOSSARY  (About -> Glossary)
+# ------------------------------------------------------------------------------------------
+
+package glossary
+
+_cicpagecontent_ {
+<div class="cicheading">Glossary</div>
+
+<p><span class="cicsubheading">Definitions and Visual Examples</span> (some based on definitions of the Getty Art and Architecture Thesaurus)<br />
+(as noted in Questionnaire, Part II./Section 2. Description/A. Building/1. Architectural classification)</p>
+
+<div class="cicglossaryentry">
+<img class="cicglossaryphoto" alt="Dartmouth Hall, Dartmouth College (photo courtesy of University of Maryland slide collection)" src="_httpcollection_/images/americancolonial.jpg"/>
+AMERICAN COLONIAL<br />
+Refers to the culture and style of architecture created in the region of the current United States during the period when it was colonized by Europeans, primarily during the 17th and 18th centuries. The term generally refers specifically to the culture and styles of the British colonies on the East Coast of the United States, generally not including the French or Spanish colonies, which are usually called French colonial or Spanish colonial.<br />
+<i>Example image: Dartmouth Hall, 1784-1791 (and later), Dartmouth College, Hanover, N.H. (photo courtesy of University of Maryland slide collection)</i>
+</div>
+
+<div class="cicglossaryentry">
+<img class="cicglossaryphoto" alt="President's House, Williams College (HABS/HAER)" src="_httpcollection_/images/federal.jpg"/>
+FEDERAL<br />
+Refers to the architecture that flourished in the new American republic from approximately 1785 to 1820. Inspired by European neo-classicism, especially as practiced in England by Robert Adam, though modified by late colonial tendencies, it also reflects the revival of Roman architectural styles, especially in the design of government buildings. Endorsed by Thomas Jefferson and Benjamin Henry Latrobe, that theme was driven partially by the metaphorical concept of the United States as analogous to the Roman Republic in its political philosophy.<br />
+<i>Example image: President's House, Williams College, Williamstown, Mass. (HABS/HAER)</i>
+</div>
+
+<div class="cicglossaryentry">
+<img class="cicglossaryphoto" alt="Morrison College, Transylvania University (HABS/HAER)" src="_httpcollection_/images/greekrevival.jpg"/>
+GREEK REVIVAL<br />
+Refers to a style of architecture in Europe and the United States begun in the 1750s in Europe, and flourishing there from the 1790s and then in this country from approximately 1815 to the 1850s, which was characterized by the use of classical Greek forms and ornament. Inspired by 18th-century archaeological discoveries, it attempted to follow closely original models. Greek revival buildings often look like temples, with a series of large stone or wood columns marking part or all of the structure, though there are many examples that emphasize Greek details rather than whole buildings. In the United States, it flourished at the time of the Greek war for independence from Turkey, and many saw the style as a manifestation of democracy.<br />
+<i>Example image: Morrison College, 1830, Transylvania University, Lexington, Ky. (HABS/HAER)</i>
+</div>
+
+<div class="cicglossaryentry">
+<img class="cicglossaryphoto" alt="Ralston Hall, Univ. of Notre Dame de Namur" src="_httpcollection_/images/italianate.jpg"/>
+ITALIANATE<br />
+A mid- to-late-19th-century architectural style, it was inspired by Italian Renaissance buildings, both the high-style urban palazzo and the less formal country villa. Often residential and often featuring a low-pitched hipped roof topped by a belvedere, or rooftop pavilions intended as lookouts or for the enjoyment of a view, it can also refer to more formal buildings ranging from commercial to public and residential.<br />
+<i>Example image: Ralston Hall, University of Notre Dame de Namur, after 1865, Belmont, Calif. (HABS/HAER)</i>
+</div>
+
+<div class="cicglossaryentry">
+<img class="cicglossaryphoto" alt="Old Main building, Bethany College (HABS/HAER)" src="_httpcollection_/images/gothicrevival.jpg"/>
+GOTHIC REVIVAL<br />
+Refers mainly to a style that flourished first in England and then spread to the European continent but even more strongly to America, beginning in the mid- to late 18th century, triumphing in the mid-19th century, and continuing into the twentieth. The style is characterized by the use of pointed arches, rosettes, pinnacles, tracery, foils, and polychrome effects inspired by Gothic architecture and at times reproduced with the general aim of historical accuracy, though often the spirit was as important as the details. Especially associated with churches, it could also be found in a wide range of building types, including by the late 19th and 20th century examples in campus architecture in what came to be called Collegiate Gothic.<br />
+<i>Example image: "Old Main" Building, 1911-1912, Bethany College, Bethany, W. Va. (HABS/HAER)</i>
+</div>
+
+<div class="cicglossaryentry">
+<img class="cicglossaryphoto" alt="Glatfelter Hall, Gettysbury College (HABS/HAER)" src="_httpcollection_/images/romanesquerevival.jpg"/>
+ROMANESQUE REVIVAL<br />
+Refers to a style in European and American architecture dating from the 1820s to the end of the 19th century that was based on 11th- and 12th-century Romanesque church architecture. It is primarily characterized by the use of semicircular arches, barrel and groin vaults, massive blocks of masonry and, at times, the spare use of Romanesque and/or naturalistic ornament. A specific variety, called Richardsonian Romanesque, was inspired by the architecture of the American H. H. Richardson, and flourished in the last three decades of the 19th century.<br />
+<i>Example image: Glatfelter Hall, 1888-1889, Gettysbury College, Gettysburg, Pa. (HABS/HAER)</i>
+</div>
+
+<div class="cicglossaryentry">
+<img class="cicglossaryphoto" alt="Residential Village (Theme House), Agnes Scott College (CIC-HCAP collection)" src="_httpcollection_/images/victorianstyles.jpg"/>
+VICTORIAN STYLES<br />
+Refers to a wide variety of styles exhibited during the 19th century during Queen Victorias reign in Britain (1837-1900) and during the same period in the United States. Often labeled Romantic, these styles, which ranged from Italianate and Gothic revival to vernacular and Queen Anne revival, were expressed in all building types.<br />
+<i>Example image: Residential Village (Theme House), 1895-1896, Agnes Scott College, Decatur, Ga. (CIC-HCAP collection)</i>
+</div>
+
+<div class="cicglossaryentry">
+<img class="cicglossaryphoto" alt="Cochran Hall, Allegheny College (CIC-HCAP collection)" src="_httpcollection_/images/beauxartsclassicism.jpg"/>
+BEAUX-ARTS CLASSICISM<br />
+Refers to the revival of classicism, especially as practiced in Italy and France during the Renaissance and Baroque eras of the 15th to 18th centuries, that flourished in Europe and America in the late 19th and early 20th centuries. Inspired by the approach to architectural design espoused at the Ecole des Beaux-Arts in Paris, this style included the use of classically articulated and often symmetrical massing, a primary axial orientation in plan (often with subsidiary axes), and hierarchically arranged and related internal spaces that offered the opportunity for a directed, processional movement through a building. Its flourishing in America coincided with the emergence of the United States as a world power.<br />
+<i>Example image: Cochran Hall, 1907-1908, Allegheny College, Meadville, Penn. (CIC-HCAP collection)</i>
+</div>
+
+<div class="cicglossaryentry">
+<img class="cicglossaryphoto" alt="Washington Hall, Washington and Lee University" src="_httpcollection_/images/colonialrevival.jpg"/>
+COLONIAL REVIVAL<br />
+Refers to a movement in architecture and interior design prevalent in the late 19th century and well into the 20th that revives the styles of the 17th, 18th, and early 19th centuries in colonial and federal America. The style, though especially seen in domestic architecture, also was found in other building types. Subsumed within this general rubric was not only a revival of 17th century clapboard buildings, but also a Georgian revival, which was inspired by English and American architecture of the 18th century. This latter tends to feature symmetrical faÃ§ades, often characterized by brick, pitched roofs, windows with sashes, and fanlights. It also often includes white painted trim and decorative moldings and elements.<br />
+<i>Example image: Washington Hall, 1824, Washington and Lee University, Lexington, Va. (HABS)</i>
+</div>
+
+<div class="cicglossaryentry">
+<img class="cicglossaryphoto" alt="Our Lady Queen of Peace Chapel, Lourdes College (CIC-HCAP collection)" src="_httpcollection_/images/mission.jpg"/>
+MISSION/MISSION REVIVAL<br />
+As a subtype of Spanish Colonial revival architectural style, this style is characterized by simplicity of form and ornamentation. Particularly between approximately 1900 and 1915 (although also later) especially in the southern, western, and southwestern regions of the United States, Mission revival architecture was utilized in all kinds of buildings.<br />
+<i>Example image: Our Lady Queen of Peace Chapel, 1959-1961, Lourdes College, Sylvania, Ohio (CIC-HCAP collection)</i>
+</div>
+
+<div class="cicglossaryentry">
+<img class="cicglossaryphoto" alt="Annie Pfeiffer Chapel, Florida Southern College (HABS/HAER)" src="_httpcollection_/images/modern.jpg"/>
+MODERN/PRE- AND POST-WWII<br />
+Refers to the style of architecture that emerged in Holland, France, and Germany  just before but primarily after World War I and spread throughout the world, becoming a leading architectural style until the 1960s/1970s. This style is characterized by a rejection of traditional period styling; an emphasis on volume over mass; the use of lightweight, mass-produced, industrial materials, but also reinforced concrete; frequent rejection of ornament and color; repetitive modular forms; and the use of flat surfaces, typically alternating with areas of glass. Some later examples may also be particularly sculptural in massing.<br />
+<i>Example image: Annie Pfeiffer Chapel, des. 1940, Florida Southern College, Lakeland, Fla. (HABS/HAER)</i>
+</div>
+
+<div class="cicglossaryentry">
+<img class="cicglossaryphoto" alt="Williams College Museum of Art (rear faÃ§ade), Williams College (Williams College Department of Art slide collection)" src="_httpcollection_/images/postmodern.jpg"/>
+POSTMODERN<br />
+Refers to architecture as early as the mid-1960s but more often from the mid-1970s to the early 1990s, in which buildings often have a renewed interest in the color and patterns of materials, and, in many cases, the use of stylistic quotations from many different periods combined to a contradictory effect of varying scale, proportions, and scenographic effect.<br />
+<i>Example image: Williams College Museum of Art (rear faÃ§ade), addition of ca. 1981, Williamstown, Mass. (Williams College, Dept. of Art, slide collection)</i>
+</div>
+
+<div class="cicglossaryentry">
+<img class="cicglossaryphoto" alt="Admissions and Careers Services Center, Trinity College (CIC-HCAP collection)" src="_httpcollection_/images/contemporary.jpg"/>
+CONTEMPORARY<br />
+Although often used earlier in the twentieth century to refer to modernism, it especially refers to architecture from 1995 to the present, encompassing a wide range of architectural styles and approaches, often incorporating elements of modernism and postmodernism.<br />
+<i>Example image: Admissions and Careers Services Center (detail, exterior), Trinity College, Hartford, Conn. (CIC-HCAP collection)</i>
+</div>
+
+<div class="cicglossaryentry">
+<img class="cicglossaryphoto" alt="Old Castle, Baker University (HABS/HAER)" src="_httpcollection_/images/vernacularregionalist.jpg"/>
+REGIONALIST/VERNACULAR<br />
+Refers to architecture that does not fit easily into the stylistic categories given above that rely primarily on period styling. This kind of architecture instead emphasizes the building traditions and materials of a particular region. These buildings may have been constructed during any period in American architecture. Fieldstone buildings in Pennsylvania or the Midwest, adobe or stucco mission-type buildings with tile roofs in the West or Southwest, and local limestone buildings in Indiana, are a few examples of this kind of response in campus architecture.<br />
+<i>Example image: Old Castle, 1858, Baker University, Baldwin City, Kans. (HABS/HAER)</i>
+</div>
+
+<p style="clear: both"><span class="cicsubheading">Further Definitions</span><br />
+(as noted in Questionnaire, Part II./Section 2. Description/B. Entire campus and C. Campus plan)</p>
+
+<p><b>Informal or not formally planned:</b><br />
+No comprehensive master plan was a part of campus building or landscaping efforts. Campus has developed without any overarching schema.</p>
+
+<p><b>Irregular/Picturesque:</b><br />
+Master plan of part or all of the campus has curving roads and pathways that provide circulation amidst non-hierarchically placed buildings. Vegetation, either natural or planned, often is clustered in irregular, unsymmetrical groupings, so as to create a more natural, though actually planned, picturesque effect.</p>
+
+<p><b>Linear:</b><br />
+Master plan of all or part of the campus has a primary axis, on one or both sides of which building and/or landscaping efforts have been concentrated. Circulation on the campus is directed along this primary axis.</p>
+
+<p><b>Quadrangle/Beaux-Arts classicism:</b><br />
+Master plan of part or all of the campus has a primary axis that serves as an important means of circulation and orientation for buildings. Structures are often placed in symmetrical arrangements, with a clear hierarchy in size and location established between the focal point(s) of a central building or structure placed at one end or both ends of the plan and subsidiary buildings located around these elements.</p>
+
+<p><b>Modern (open plan):</b><br />
+Though clearly planned, these campuses utilize a master plan that has a more open orientation between buildings, with no obvious reliance on the hierarchical arrangements of the more classically-ordered quadrangle and Beaux-Arts tradition.</p>
+}
+
+
+
+# ------------------------------------------------------------------------------------------
+#   LINKS  (About -> Links for Further Research)
+# ------------------------------------------------------------------------------------------
+
+package links
+
+_cicpagecontent_ {
+<div class="cicheading">Links</div>
+
+<div class="cicsubheading"><p>Supporting Organizations</p></div>
+
+<p>
+Council of Independent Colleges: <a href="http://www.cic.org">http://www.cic.org</a><br />
+
+Getty Foundation: <a href="http://www.getty.edu">http://www.getty.edu</a>
+</p>
+
+<div class="cicsubheading"><p>Related Websites</p></div>
+
+<p>
+Society for College and University Planning: <a href="http://www.scup.org">http://www.scup.org</a><br />
+
+National Historic Landmarks: <a href="http://www.cr.nps.gov/nhl/">http://www.cr.nps.gov/nhl/</a><br />
+
+National Register of Historic Places: <a href="http://www.cr.nps.gov/nr/">http://www.cr.nps.gov/nr/</a><br />
+
+State Historic Preservation Offices: <a href="http://www.cr.nps.gov/nr/shpolist.htm">http://www.cr.nps.gov/nr/shpolist.htm</a><br />
+
+Historic American Building Survey and Historic American Engineering Record: <a href="http://www.cr.nps.gov/habshaer">http://www.cr.nps.gov/habshaer</a><br />
+
+Chronicle of Higher Education: <a href="http://chronicle.com">http://chronicle.com</a><br />
+
+American Planning Association: <a href="http://www.planning.org">http://www.planning.org</a><br />
+
+National Association of State Universities and Land-Grant Colleges: <a href="http://www.nasulgc.org">http://www.nasulgc.org</a>
+</p>
+}
+
+
+
+# ------------------------------------------------------------------------------------------
+#   INSTITUTIONS  (Browse -> Institution)
+# ------------------------------------------------------------------------------------------
+
+package institutions
+
+_cicpagecontent_ {
+<div class="cicheading">Institutions</div>
+
+<center>_cicstaticbrowserquicklinks_</center>
+
+_cicstaticbrowser_
+}
+
+
+
+# ------------------------------------------------------------------------------------------
+#   TYPES  (Browse -> Type of Place)
+# ------------------------------------------------------------------------------------------
+
+package types
+
+_cicpagecontent_ {
+<div class="cicheading">Type of Place</div>
+_cicblankline_
+
+<center>
+<table cellpadding="5">
+  <tr>
+    <td><center><a href="_gwcgi_?a=p&amp;p=typesIndividualbuilding">Buildings</a></center></td>
+    <td><a href="_gwcgi_?a=p&amp;p=typesIndividualbuilding"><img alt="Geneva Hall (detail, entrance), Hobart and William Smith Colleges" src="_httpcollection_/images/building.jpg" title="Geneva Hall (detail, entrance), Hobart and William Smith Colleges"></a></td>
+    <td><a href="_gwcgi_?a=p&amp;p=typesCampusarrangement"><img alt="Campus (aerial view), Clarke College" src="_httpcollection_/images/arrangement.jpg" title="Campus (aerial view), Clarke College"></a></td>
+    <td><center><a href="_gwcgi_?a=p&amp;p=typesCampusarrangement">Campus arrangements</a></center></td>
+  </tr>
+  <tr>
+    <td><center><div style="padding-bottom: 10px"><a href="_gwcgi_?a=p&amp;p=typesLandscapesite">Landscape sites</a></div></center></td>
+    <td><a href="_gwcgi_?a=p&amp;p=typesLandscapesite"><img alt="Italian Gardens and Apollo Fountain (gardens), Georgian Court University" src="_httpcollection_/images/landscapesite.jpg" title="Italian Gardens and Apollo Fountain (gardens), Georgian Court University"></a></td>
+    <td><a href="_gwcgi_?a=p&amp;p=typesBuildinggroup"><img alt="Greylock Quadrangle (ca. 1970), Williams College" src="_httpcollection_/images/buildinggroup.jpg" title="Greylock Quadrangle (ca. 1970), Williams College"></a></td>
+    <td><center><div style="padding-bottom: 10px"><a href="_gwcgi_?a=p&amp;p=typesBuildinggroup">Building groups</a></div></center></td>
+  </tr>
+</table>
+</center>
+}
+
+package typesIndividualbuilding
+_cicpagecontent_ { <div class="cicheading">Buildings</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package typesLandscapesite
+_cicpagecontent_ { <div class="cicheading">Landscape Sites</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package typesCampusarrangement
+_cicpagecontent_ { <div class="cicheading">Campus Arrangements</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package typesBuildinggroup
+_cicpagecontent_ { <div class="cicheading">Building Groups</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+
+
+# ------------------------------------------------------------------------------------------
+#   DESIGNERS  (Browse -> Designer)
+# ------------------------------------------------------------------------------------------
+
+package designers
+
+_cicpagecontent_ { <div class="cicheading">Designers</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+
+
+# ------------------------------------------------------------------------------------------
+#   STATES  (Browse -> State)
+# ------------------------------------------------------------------------------------------
+
+package states
+
+_cicpagecontent_ {
+<div class="cicheading">States</div>
+
+<center><img alt="US state map" src="_httpcollection_/images/usa_map-mono.gif" usemap="#states"/></center>
+<map name="states">
+  <area shape="rect" coords="524,286,551,313" href="#Alabama">
+  <area shape="rect" coords="154,379,197,413" href="#Alaska">
+  <area shape="rect" coords="202,248,237,280" href="#Arizona">
+  <area shape="rect" coords="444,257,475,283" href="#Arkansas">
+  <area shape="rect" coords="104,177,140,209" href="#California">
+  <area shape="rect" coords="278,186,324,211" href="#Colorado">
+  <area shape="rect" coords="690,146,712,161" href="#Connecticut">
+  <area shape="rect" coords="677,183,701,196" href="#Delaware">
+  <area shape="rect" coords="680,216,706,234" href="#DistrictofColumbia">
+  <area shape="rect" coords="604,352,628,376" href="#Florida">
+  <area shape="rect" coords="564,280,598,303" href="#Georgia">
+  <area shape="rect" coords=" 69,314, 97,333" href="#Hawaii">
+  <area shape="rect" coords="197,103,228,123" href="#Idaho">
+  <area shape="rect" coords="483,171,509,193" href="#Illinois">
+  <area shape="rect" coords="521,169,545,189" href="#Indiana">
+  <area shape="rect" coords="432,149,462,169" href="#Iowa">
+  <area shape="rect" coords="371,201,404,223" href="#Kansas">
+  <area shape="rect" coords="539,215,565,232" href="#Kentucky">
+  <area shape="rect" coords="449,312,475,333" href="#Louisiana">
+  <area shape="rect" coords="693, 54,719, 75" href="#Maine">
+  <area shape="rect" coords="686,198,712,213" href="#Maryland">
+  <area shape="rect" coords="715,111,743,128" href="#Massachusetts">
+  <area shape="rect" coords="532,122,557,142" href="#Michigan">
+  <area shape="rect" coords="418, 88,449,108" href="#Minnesota">
+  <area shape="rect" coords="485,287,513,308" href="#Mississippi">
+  <area shape="rect" coords="441,202,474,222" href="#Missouri">
+  <area shape="rect" coords="258, 57,291, 80" href="#Montana">
+  <area shape="rect" coords="358,156,390,173" href="#Nebraska">
+  <area shape="rect" coords="153,159,185,179" href="#Nevada">
+  <area shape="rect" coords="706, 95,732,109" href="#NewHampshire">
+  <area shape="rect" coords="680,165,702,180" href="#NewJersey">
+  <area shape="rect" coords="274,258,309,278" href="#NewMexico">
+  <area shape="rect" coords="641,108,665,127" href="#NewYork">
+  <area shape="rect" coords="616,229,643,248" href="#NorthCarolina">
+  <area shape="rect" coords="353, 64,385, 83" href="#NorthDakota">
+  <area shape="rect" coords="557,165,587,181" href="#Ohio">
+  <area shape="rect" coords="383,250,416,269" href="#Oklahoma">
+  <area shape="rect" coords="128, 82,163,105" href="#Oregon">
+  <area shape="rect" coords="614,145,643,165" href="#Pennsylvania">
+  <area shape="rect" coords="703,133,719,146" href="#RhodeIsland">
+  <area shape="rect" coords="600,260,624,279" href="#SouthCarolina">
+  <area shape="rect" coords="353,109,384,128" href="#SouthDakota">
+  <area shape="rect" coords="523,241,549,257" href="#Tennessee">
+  <area shape="rect" coords="360,307,400,337" href="#Texas">
+  <area shape="rect" coords="214,176,247,200" href="#Utah">
+  <area shape="rect" coords="657, 55,680, 72" href="#Vermont">
+  <area shape="rect" coords="616,202,642,217" href="#Virginia">
+  <area shape="rect" coords="144, 35,177, 51" href="#Washington">
+  <area shape="rect" coords="587,191,610,204" href="#WestVirginia">
+  <area shape="rect" coords="471,109,499,128" href="#Wisconsin">
+  <area shape="rect" coords="269,119,305,144" href="#Wyoming">
+</map>
+
+<center><b><a href="#Alabama">A</a>&nbsp;B&nbsp;<a href="#California">C</a>&nbsp;<a href="#Delaware">D</a>&nbsp;E&nbsp;<a href="#Florida">F</a>&nbsp;<a href="#Georgia">G</a>&nbsp;<a href="#Hawaii">H</a>&nbsp;<a href="#Idaho">I</a>&nbsp;J&nbsp;<a href="#Kansas">K</a>&nbsp;<a href="#Louisiana">L</a>&nbsp;<a href="#Maine">M</a>&nbsp;<a href="#Nebraska">N</a>&nbsp;<a href="#Ohio">O</a>&nbsp;<a href="#Pennsylvania">P</a>&nbsp;Q&nbsp;<a href="#RhodeIsland">R</a>&nbsp;<a href="#SouthCarolina">S</a>&nbsp;<a href="#Tennessee">T</a>&nbsp;<a href="#Utah">U</a>&nbsp;<a href="#Vermont">V</a>&nbsp;<a href="#Washington">W</a>&nbsp;X&nbsp;Y&nbsp;Z&nbsp;</b></center>
+
+_cicstaticbrowser_
+}
+
+
+
+# ------------------------------------------------------------------------------------------
+#   STYLES  (Browse -> Building Styles)
+# ------------------------------------------------------------------------------------------
+
+package styles
+
+_cicpagecontent_ {
+<div class="cicheading">Styles</div>
+
+<p>
+<a href="_gwcgi_?a=p&amp;p=stylesAmericancolonial">American Colonial</a><br />
+<a href="_gwcgi_?a=p&amp;p=stylesFederal">Federal</a><br />
+<a href="_gwcgi_?a=p&amp;p=stylesGreekrevival">Greek Revival</a><br />
+<a href="_gwcgi_?a=p&amp;p=stylesItalianate">Italianate</a><br />
+<a href="_gwcgi_?a=p&amp;p=stylesGothicrevival">Gothic Revival</a><br />
+<a href="_gwcgi_?a=p&amp;p=stylesRomanesquerevival">Romanesque Revival</a><br />
+<a href="_gwcgi_?a=p&amp;p=stylesVictorian">Victorian Styles</a><br />
+<a href="_gwcgi_?a=p&amp;p=stylesBeauxArtsclassicism">Beaux-Arts Classicism</a><br />
+<a href="_gwcgi_?a=p&amp;p=stylesColonialrevival">Colonial Revival</a><br />
+<a href="_gwcgi_?a=p&amp;p=stylesMissionMissionrevival">Mission/Mission Revival</a><br />
+<a href="_gwcgi_?a=p&amp;p=stylesModernpreWWII">Modern/pre-World War II</a><br />
+<a href="_gwcgi_?a=p&amp;p=stylesModernpostWWII">Modern/post-World War II</a><br />
+<a href="_gwcgi_?a=p&amp;p=stylesPostmodern">Postmodern</a><br />
+<a href="_gwcgi_?a=p&amp;p=stylesContemporary">Contemporary</a><br />
+<a href="_gwcgi_?a=p&amp;p=stylesRegionalistVernacular">Regionalist Vernacular</a><br />
+<a href="_gwcgi_?a=p&amp;p=stylesOther">Other</a><br />
+</p>
+
+<p>See the <a href="_gwcgi_?a=p&amp;p=glossary">Glossary</a> for full definition of terms.</p>
+}
+
+package stylesAmericancolonial
+_cicpagecontent_ { <div class="cicheading">American Colonial</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package stylesFederal
+_cicpagecontent_ { <div class="cicheading">Federal</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package stylesGreekrevival
+_cicpagecontent_ { <div class="cicheading">Greek Revival</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package stylesItalianate
+_cicpagecontent_ { <div class="cicheading">Italianate</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package stylesGothicrevival
+_cicpagecontent_ { <div class="cicheading">Gothic Revival</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package stylesRomanesquerevival
+_cicpagecontent_ { <div class="cicheading">Romanesque Revival</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package stylesVictorian
+_cicpagecontent_ { <div class="cicheading">Victorian</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package stylesBeauxArtsclassicism
+_cicpagecontent_ { <div class="cicheading">Beaux-Arts Classicism</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package stylesColonialrevival
+_cicpagecontent_ { <div class="cicheading">Colonial Revival</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package stylesMissionMissionrevival
+_cicpagecontent_ { <div class="cicheading">Mission/Mission Revival</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package stylesModernpreWWII
+_cicpagecontent_ { <div class="cicheading">Modern/pre-World War II</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package stylesModernpostWWII
+_cicpagecontent_ { <div class="cicheading">Modern/post-World War II</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package stylesPostmodern
+_cicpagecontent_ { <div class="cicheading">Postmodern</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package stylesContemporary
+_cicpagecontent_ { <div class="cicheading">Contemporary</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package stylesRegionalistVernacular
+_cicpagecontent_ { <div class="cicheading">Regionalist Vernacular</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package stylesOther
+_cicpagecontent_ { <div class="cicheading">Other</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+
+
+# ------------------------------------------------------------------------------------------
+#   DATES  (Browse -> Time Period)
+# ------------------------------------------------------------------------------------------
+
+package dates
+
+_cicpagecontent_ {
+<div class="cicheading">Time Period</div>
+
+<p>
+<a href="_gwcgi_?a=p&amp;p=datespre1800">pre-1800</a><br />
+<a href="_gwcgi_?a=p&amp;p=dates18001850">1800-1850</a><br />
+<a href="_gwcgi_?a=p&amp;p=dates18501900">1850-1900</a><br />
+<a href="_gwcgi_?a=p&amp;p=dates19001945">1900-1945</a><br />
+<a href="_gwcgi_?a=p&amp;p=dates19451995">1945-1995</a><br />
+<a href="_gwcgi_?a=p&amp;p=datespost1995">post-1995</a><br />
+</p>
+}
+
+package datespre1800
+_cicpagecontent_ { <div class="cicheading">pre-1800</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package dates18001850
+_cicpagecontent_ { <div class="cicheading">1800-1850</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package dates18501900
+_cicpagecontent_ { <div class="cicheading">1850-1900</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package dates19001945
+_cicpagecontent_ { <div class="cicheading">1900-1945</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package dates19451995
+_cicpagecontent_ { <div class="cicheading">1945-1995</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package datespost1995
+_cicpagecontent_ { <div class="cicheading">post-1995</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+
+
+# ------------------------------------------------------------------------------------------
+#   FUNCTIONS  (Browse -> Function)
+# ------------------------------------------------------------------------------------------
+
+package functions
+
+_cicpagecontent_ {
+<div class="cicheading">Function</div>
+_cicblankline_
+<table cellpadding="0" cellspacing="0" width="100%">
+<tr>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionsacademicdepartmentbuilding">Academic department building</a></td>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionsinfirmary">Infirmary</a></td>
+</tr>
+<tr>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionsadministration">Administration</a></td>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionslibrary">Library</a></td>
+</tr>
+<tr>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionsadmissionsoffice">Admissions office</a></td>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionsmasterplancampus">Master plan (campus)</a></td>
+</tr>
+<tr>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionsalumnicenter">Alumni center</a></td>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionsmasterplanlandscape">Master plan (landscape)</a></td>
+</tr>
+<tr>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionsarboretum">Arboretum</a></td>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionsmemorialsite">Memorial site</a></td>
+</tr>
+<tr>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionsarchaeologicalsite">Archaeological site</a></td>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionsmuseum">Museum</a></td>
+</tr>
+<tr>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionsauditorium">Auditorium</a></td>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionsobservatory">Observatory</a></td>
+</tr>
+<tr>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionsbelltower">Bell tower</a></td>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionsoldmain">Old main</a></td>
+</tr>
+<tr>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionschapel">Chapel</a></td>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionsoutdoorspace">Outdoor space</a></td>
+</tr>
+<tr>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionsclassrooms">Classroom(s)</a></td>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionspresidentshouse">President's house</a></td>
+</tr>
+<tr>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionsdebatingsociety">Debating society</a></td>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionsprivateresidence">Private residence</a></td>
+</tr>
+<tr>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionsdininghall">Dining hall</a></td>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionsresidencehall">Residence hall</a></td>
+</tr>
+<tr>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionsfacilitymanagementbuilding">Facility management building</a></td>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionsstadium">Stadium</a></td>
+</tr>
+<tr>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionsfacultyoffices">Faculty offices</a></td>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionsstudentunion">Student union</a></td>
+</tr>
+<tr>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionsgardens">Gardens (planned)</a></td>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionstheater">Theater</a></td>
+</tr>
+<tr>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionsgreeklettersociety">Greek letter society</a></td>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionsother">Other</a></td>
+</tr>
+<tr>
+<td width="50%"><a href="_gwcgi_?a=p&amp;p=functionsgymnasium">Gymnasium</a></td>
+<td width="50%">&nbsp;</td>
+</tr>
+</table>
+}
+
+package functionsacademicdepartmentbuilding
+_cicpagecontent_ { <div class="cicheading">Academic department building</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package functionsadministration
+_cicpagecontent_ { <div class="cicheading">Administration</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package functionsadmissionsoffice
+_cicpagecontent_ { <div class="cicheading">Admissions office</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package functionsalumnicenter
+_cicpagecontent_ { <div class="cicheading">Alumni center</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package functionsarboretum
+_cicpagecontent_ { <div class="cicheading">Arboretum</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package functionsarchaeologicalsite
+_cicpagecontent_ { <div class="cicheading">Archaeological site</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package functionsauditorium
+_cicpagecontent_ { <div class="cicheading">Auditorium</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package functionsbelltower
+_cicpagecontent_ { <div class="cicheading">Bell tower</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package functionschapel
+_cicpagecontent_ { <div class="cicheading">Chapel</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package functionsclassrooms
+_cicpagecontent_ { <div class="cicheading">Classroom(s)</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package functionsdebatingsociety
+_cicpagecontent_ { <div class="cicheading">Debating society</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package functionsdininghall
+_cicpagecontent_ { <div class="cicheading">Dining hall</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package functionsfacilitymanagementbuilding
+_cicpagecontent_ { <div class="cicheading">Facility management building</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package functionsfacultyoffices
+_cicpagecontent_ { <div class="cicheading">Faculty offices</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package functionsgardens
+_cicpagecontent_ { <div class="cicheading">Gardens (planned)</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package functionsgreeklettersociety
+_cicpagecontent_ { <div class="cicheading">Greek letter society</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package functionsgymnasium
+_cicpagecontent_ { <div class="cicheading">Gymnasium</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package functionsinfirmary
+_cicpagecontent_ { <div class="cicheading">Infirmary</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package functionslibrary
+_cicpagecontent_ { <div class="cicheading">Library</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package functionsmasterplancampus
+_cicpagecontent_ { <div class="cicheading">Master plan (campus)</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package functionsmasterplanlandscape
+_cicpagecontent_ { <div class="cicheading">Master plan (landscape)</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package functionsmemorialsite
+_cicpagecontent_ { <div class="cicheading">Memorial site</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package functionsmuseum
+_cicpagecontent_ { <div class="cicheading">Museum</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package functionsobservatory
+_cicpagecontent_ { <div class="cicheading">Observatory</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package functionsoldmain
+_cicpagecontent_ { <div class="cicheading">Old main</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package functionsoutdoorspace
+_cicpagecontent_ { <div class="cicheading">Outdoor space</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package functionspresidentshouse
+_cicpagecontent_ { <div class="cicheading">President's house</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package functionsprivateresidence
+_cicpagecontent_ { <div class="cicheading">Private residence</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package functionsresidencehall
+_cicpagecontent_ { <div class="cicheading">Residence hall</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package functionsstadium
+_cicpagecontent_ { <div class="cicheading">Stadium</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package functionsstudentunion
+_cicpagecontent_ { <div class="cicheading">Student union</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package functionstheater
+_cicpagecontent_ { <div class="cicheading">Theater</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+package functionsother
+_cicpagecontent_ { <div class="cicheading">Other</div><center>_cicstaticbrowserquicklinks_</center>_cicstaticbrowser_ }
+
+
+
+# ------------------------------------------------------------------------------------------
+#   DOCUMENT
+# ------------------------------------------------------------------------------------------
+
+package document
+
+_navarrows_ {}
+
+_textheader_ {_style:cicheader_}
+
+_cicpagecontent_ {}
+
+_footer_ {_style:htmlfooter_}
+
+
+
+# ------------------------------------------------------------------------------------------
+#   QUERY
+# ------------------------------------------------------------------------------------------
+
+package query
+
+_header_ {
+_If_(_cgiargq_,_style:header_,_If_("_cgiargqst_" eq "1",_cicstatesearchheader_,_If_("_cgiargqre_" eq "1",_cicbibliographysearchheader_,_cicadvancedsearchheader_)))
+}
+
+_cicjavascript_ {
+<script type="text/javascript">
+
+_cicsimplejavascript_
+_If_("_cgiargqst_" eq "1",_cicstatesearchjavascript_)
+_If_("_cgiargqre_" eq "1",_cicbibliographysearchjavascript_)
+_cicadvancedsearchjavascript_
+
+</script>
+}
+
+_cicpagecontent_ {
+_If_(_cgiargq_,_cicsearchresults_,_If_("_cgiargqst_" eq "1",_If_("_cgiargqrst_" eq "1",_cicstatesearchresults_,_cicstatesearchpage_),_If_("_cgiargqre_" eq "1",_cicbibliographysearchpage_,_cicadvancedsearchpage_)))
+}
+
+_cicsearchresults_ {
+<div class="cicheading">Search Results</div>
+
+<p>_resultline_</p>
+}
+
+# What is displayed on the submit buttons
+_textbeginsearch_ {Search}
+
+
+
+# ------------------------------------------------------------------------------------------
+#   QUERY  (Quick Search)
+# ------------------------------------------------------------------------------------------
+
+_cicsimplejavascript_ {
+function initializeSimpleSearch()
+\{
+   document.SimpleQueryForm.txq.focus();
+\}
+
+function onSimpleSearchFocus()
+\{
+   var txq_element = document.getElementById('search_query');
+   if (txq_element.value == txq_element.defaultValue) \{
+      txq_element.value = '';
+      txq_element.className = 'inputfocus';
+   \}
+\}
+
+function onSimpleSearchBlur()
+\{
+   var txq_element = document.getElementById('search_query');
+   if (txq_element.value == '') \{
+      txq_element.value = txq_element.defaultValue;
+      txq_element.className = 'inputblur';
+   \}
+\}
+
+function prepareSimpleSearch()
+\{
+   var txq_value = document.SimpleQueryForm.txq.value;
+   document.SimpleQueryForm.fqv.value = txq_value.replace(",", "");
+\}
+}
+
+
+_cicsimplequeryform_ {
+<form name="SimpleQueryForm" method="get" action="_gwcgi_" onSubmit="prepareSimpleSearch();">
+  <input type="hidden" name="a" value="q" />
+  <input type="hidden" name="fqc" value="and" />
+  <input type="hidden" name="fqf" value="ZZ" />
+  <input type="hidden" name="fqv" value="" />
+  <input type="text" name="txq" id="search_query" value="QUICK SEARCH" class="inputblur" onfocus="javascript: onSimpleSearchFocus();" onblur="javascript: onSimpleSearchBlur();" />
+  <input type="hidden" name="m" value="-1" />
+  <input type="submit" name="submit" id="search_submit" value="GO" />
+</form>
+}
+
+
+
+# ------------------------------------------------------------------------------------------
+#   QUERY  (Search -> Institutions by State/Region)
+# ------------------------------------------------------------------------------------------
+
+_cicstatesearchheader_ {
+_style:cicheader_(onLoad="initializeStateSearch();")
+}
+
+_cicstatesearchjavascript_ {
+function initializeStateSearch()
+\{
+   if ("_cgiargqrst_" == "1") \{
+      var stq_results = "";
+      var stq_values = "_cgiargstq_".split(",").sort();
+      var last_stq_value = "";
+      for (var i = 0; i < stq_values.length; i++) \{
+         // Avoid duplicates by checking this value is different from the last one
+         if (stq_values[i] == last_stq_value) \{
+	    continue;
+         \}
+	 last_stq_value = stq_values[i];
+
+         if (stq_values[i] == "AL") stq_results += '_states:cicstateALjs_';
+         if (stq_values[i] == "AK") stq_results += '_states:cicstateAKjs_';
+         if (stq_values[i] == "AZ") stq_results += '_states:cicstateAZjs_';
+         if (stq_values[i] == "AR") stq_results += '_states:cicstateARjs_';
+         if (stq_values[i] == "CA") stq_results += '_states:cicstateCAjs_';
+         if (stq_values[i] == "CO") stq_results += '_states:cicstateCOjs_';
+         if (stq_values[i] == "CT") stq_results += '_states:cicstateCTjs_';
+         if (stq_values[i] == "DE") stq_results += '_states:cicstateDEjs_';
+         if (stq_values[i] == "DC") stq_results += '_states:cicstateDCjs_';
+         if (stq_values[i] == "FL") stq_results += '_states:cicstateFLjs_';
+         if (stq_values[i] == "GA") stq_results += '_states:cicstateGAjs_';
+         if (stq_values[i] == "HI") stq_results += '_states:cicstateHIjs_';
+         if (stq_values[i] == "ID") stq_results += '_states:cicstateIDjs_';
+         if (stq_values[i] == "IL") stq_results += '_states:cicstateILjs_';
+         if (stq_values[i] == "IN") stq_results += '_states:cicstateINjs_';
+	 if (stq_values[i] == "IA") stq_results += '_states:cicstateIAjs_';
+	 if (stq_values[i] == "KS") stq_results += '_states:cicstateKSjs_';
+	 if (stq_values[i] == "KY") stq_results += '_states:cicstateKYjs_';
+	 if (stq_values[i] == "LA") stq_results += '_states:cicstateLAjs_';
+	 if (stq_values[i] == "ME") stq_results += '_states:cicstateMEjs_';
+	 if (stq_values[i] == "MD") stq_results += '_states:cicstateMDjs_';
+	 if (stq_values[i] == "MA") stq_results += '_states:cicstateMAjs_';
+	 if (stq_values[i] == "MI") stq_results += '_states:cicstateMIjs_';
+	 if (stq_values[i] == "MN") stq_results += '_states:cicstateMNjs_';
+	 if (stq_values[i] == "MS") stq_results += '_states:cicstateMSjs_';
+	 if (stq_values[i] == "MO") stq_results += '_states:cicstateMOjs_';
+	 if (stq_values[i] == "MT") stq_results += '_states:cicstateMTjs_';
+	 if (stq_values[i] == "NE") stq_results += '_states:cicstateNEjs_';
+	 if (stq_values[i] == "NV") stq_results += '_states:cicstateNVjs_';
+	 if (stq_values[i] == "NH") stq_results += '_states:cicstateNHjs_';
+	 if (stq_values[i] == "NJ") stq_results += '_states:cicstateNJjs_';
+	 if (stq_values[i] == "NM") stq_results += '_states:cicstateNMjs_';
+	 if (stq_values[i] == "NY") stq_results += '_states:cicstateNYjs_';
+	 if (stq_values[i] == "NC") stq_results += '_states:cicstateNCjs_';
+	 if (stq_values[i] == "ND") stq_results += '_states:cicstateNDjs_';
+	 if (stq_values[i] == "OH") stq_results += '_states:cicstateOHjs_';
+	 if (stq_values[i] == "OK") stq_results += '_states:cicstateOKjs_';
+	 if (stq_values[i] == "OR") stq_results += '_states:cicstateORjs_';
+	 if (stq_values[i] == "PA") stq_results += '_states:cicstatePAjs_';
+	 if (stq_values[i] == "RI") stq_results += '_states:cicstateRIjs_';
+	 if (stq_values[i] == "SC") stq_results += '_states:cicstateSCjs_';
+	 if (stq_values[i] == "SD") stq_results += '_states:cicstateSDjs_';
+	 if (stq_values[i] == "TN") stq_results += '_states:cicstateTNjs_';
+	 if (stq_values[i] == "TX") stq_results += '_states:cicstateTXjs_';
+	 if (stq_values[i] == "UT") stq_results += '_states:cicstateUTjs_';
+	 if (stq_values[i] == "VT") stq_results += '_states:cicstateVTjs_';
+	 if (stq_values[i] == "VA") stq_results += '_states:cicstateVAjs_';
+	 if (stq_values[i] == "WA") stq_results += '_states:cicstateWAjs_';
+	 if (stq_values[i] == "WV") stq_results += '_states:cicstateWVjs_';
+	 if (stq_values[i] == "WI") stq_results += '_states:cicstateWIjs_';
+	 if (stq_values[i] == "WY") stq_results += '_states:cicstateWYjs_';
+      \}
+
+      if (stq_results != "") \{
+         stq_results = '<table cellpadding="0" cellspacing="0" width="100%">' + stq_results + '<\\/table>';
+         document.getElementById("stq_results").innerHTML = stq_results;
+      \}
+      else \{
+         document.getElementById("stq_results").innerHTML = "<p>_textnodocs_<\\/p>";
+      \}
+   \}
+\}
+
+function prepareStateSearch()
+\{
+   var stq_value = "";
+   for (var i = 0; i < document.StateQueryForm.stc.options.length; i++) \{
+      if (document.StateQueryForm.stc.options[i].selected == true) \{
+         if (stq_value != "") stq_value += ",";
+         stq_value += document.StateQueryForm.stc.options[i].value;
+      \}
+   \}
+   document.StateQueryForm.stq.value = stq_value;
+\}
+
+function selectRegion(region)
+\{
+   for (var i = 0; i < document.StateQueryForm.stc.options.length; i++) \{
+      if (document.StateQueryForm.stc.options[i].text == region) \{
+         document.StateQueryForm.stc.options[i].selected = true;
+	 break;
+      \}
+   \}
+\}
+
+function clearSelection()
+\{
+   for (var i = 0; i < document.StateQueryForm.stc.options.length; i++) \{
+      document.StateQueryForm.stc.options[i].selected = false;
+   \}
+\}
+}
+
+_cicstatesearchpage_ {
+<span class="cicheading">State Search</span>
+
+<table cellpadding="0" cellspacing="0" width="100%">
+  <tr>
+    <td valign="top">
+      <img alt="US state map" src="_httpcollection_/images/usa_map-color.gif" usemap="#states"/>
+      <map name="states">
+        <area shape="rect" coords="524,286,551,313" href="javascript:selectRegion('Alabama')">
+	<area shape="rect" coords="154,379,197,413" href="javascript:selectRegion('Alaska')">
+	<area shape="rect" coords="202,248,237,280" href="javascript:selectRegion('Arizona')">
+	<area shape="rect" coords="444,257,475,283" href="javascript:selectRegion('Arkansas')">
+	<area shape="rect" coords="104,177,140,209" href="javascript:selectRegion('California')">
+	<area shape="rect" coords="278,186,324,211" href="javascript:selectRegion('Colorado')">
+	<area shape="rect" coords="690,146,712,161" href="javascript:selectRegion('Connecticut')">
+	<area shape="rect" coords="677,183,701,196" href="javascript:selectRegion('Delaware')">
+	<area shape="rect" coords="680,216,706,234" href="javascript:selectRegion('District%20of%20Columbia')">
+	<area shape="rect" coords="604,352,628,376" href="javascript:selectRegion('Florida')">
+	<area shape="rect" coords="564,280,598,303" href="javascript:selectRegion('Georgia')">
+	<area shape="rect" coords=" 69,314, 97,333" href="javascript:selectRegion('Hawaii')">
+	<area shape="rect" coords="197,103,228,123" href="javascript:selectRegion('Idaho')">
+	<area shape="rect" coords="483,171,509,193" href="javascript:selectRegion('Illinois')">
+	<area shape="rect" coords="521,169,545,189" href="javascript:selectRegion('Indiana')">
+	<area shape="rect" coords="432,149,462,169" href="javascript:selectRegion('Iowa')">
+	<area shape="rect" coords="371,201,404,223" href="javascript:selectRegion('Kansas')">
+	<area shape="rect" coords="539,215,565,232" href="javascript:selectRegion('Kentucky')">
+	<area shape="rect" coords="449,312,475,333" href="javascript:selectRegion('Louisiana')">
+	<area shape="rect" coords="693, 54,719, 75" href="javascript:selectRegion('Maine')">
+	<area shape="rect" coords="686,198,712,213" href="javascript:selectRegion('Maryland')">
+	<area shape="rect" coords="715,111,743,128" href="javascript:selectRegion('Massachusetts')">
+	<area shape="rect" coords="532,122,557,142" href="javascript:selectRegion('Michigan')">
+	<area shape="rect" coords="418, 88,449,108" href="javascript:selectRegion('Minnesota')">
+	<area shape="rect" coords="485,287,513,308" href="javascript:selectRegion('Mississippi')">
+	<area shape="rect" coords="441,202,474,222" href="javascript:selectRegion('Missouri')">
+	<area shape="rect" coords="258, 57,291, 80" href="javascript:selectRegion('Montana')">
+	<area shape="rect" coords="358,156,390,173" href="javascript:selectRegion('Nebraska')">
+	<area shape="rect" coords="153,159,185,179" href="javascript:selectRegion('Nevada')">
+	<area shape="rect" coords="706, 95,732,109" href="javascript:selectRegion('New%20Hampshire')">
+	<area shape="rect" coords="680,165,702,180" href="javascript:selectRegion('New%20Jersey')">
+	<area shape="rect" coords="274,258,309,278" href="javascript:selectRegion('New%20Mexico')">
+	<area shape="rect" coords="641,108,665,127" href="javascript:selectRegion('New%20York')">
+	<area shape="rect" coords="616,229,643,248" href="javascript:selectRegion('North%20Carolina')">
+	<area shape="rect" coords="353, 64,385, 83" href="javascript:selectRegion('North%20Dakota')">
+	<area shape="rect" coords="557,165,587,181" href="javascript:selectRegion('Ohio')">
+	<area shape="rect" coords="383,250,416,269" href="javascript:selectRegion('Oklahoma')">
+	<area shape="rect" coords="128, 82,163,105" href="javascript:selectRegion('Oregon')">
+	<area shape="rect" coords="614,145,643,165" href="javascript:selectRegion('Pennsylvania')">
+	<area shape="rect" coords="703,133,719,146" href="javascript:selectRegion('Rhode%20Island')">
+	<area shape="rect" coords="600,260,624,279" href="javascript:selectRegion('South%20Carolina')">
+	<area shape="rect" coords="353,109,384,128" href="javascript:selectRegion('South%20Dakota')">
+	<area shape="rect" coords="523,241,549,257" href="javascript:selectRegion('Tennessee')">
+	<area shape="rect" coords="360,307,400,337" href="javascript:selectRegion('Texas')">
+	<area shape="rect" coords="214,176,247,200" href="javascript:selectRegion('Utah')">
+	<area shape="rect" coords="657, 55,680, 72" href="javascript:selectRegion('Vermont')">
+	<area shape="rect" coords="616,202,642,217" href="javascript:selectRegion('Virginia')">
+	<area shape="rect" coords="144, 35,177, 51" href="javascript:selectRegion('Washington')">
+	<area shape="rect" coords="587,191,610,204" href="javascript:selectRegion('West%20Virginia')">
+	<area shape="rect" coords="471,109,499,128" href="javascript:selectRegion('Wisconsin')">
+	<area shape="rect" coords="269,119,305,144" href="javascript:selectRegion('Wyoming')">
+
+	<area shape="rect" coords="  9,513,130,540" href="javascript:selectRegion('West')">
+	<area shape="rect" coords="133,513,254,540" href="javascript:selectRegion('Mountain')">
+	<area shape="rect" coords="258,513,378,540" href="javascript:selectRegion('Southwest')">
+	<area shape="rect" coords="382,513,502,540" href="javascript:selectRegion('Midwest')">
+	<area shape="rect" coords="506,513,626,540" href="javascript:selectRegion('Southeast')">
+	<area shape="rect" coords="629,513,750,540" href="javascript:selectRegion('Northeast')">
+      </map>
+    </td>
+    <td align="right" valign="top" style="padding-top: 30px;">
+      <form name=StateQueryForm method=get action="_gwcgi_" onSubmit="prepareStateSearch();">
+        <input type="hidden" name="a" value="q">
+	<input type="hidden" name="qst" value="1">
+	<input type="hidden" name="qrst" value="1">
+	<input type="hidden" name="stq" value="">
+        <select name="stc" multiple="true" style="width: 150px; height: 325px;">
+	  <option value="CT,DE,DC,ME,MD,MA,NH,NJ,NY,PA,RI,VT">Northeast</option>
+	  <option value="AL,AR,FL,GA,KY,LA,MS,NC,SC,TN,VA,WV">Southeast</option>
+	  <option value="IL,IN,IA,KS,MI,MN,MO,NE,ND,OH,SD,WI">Midwest</option>
+	  <option value="AZ,NM,OK,TX">Southwest</option>
+	  <option value="CO,ID,MT,UT,WY">Mountain</option>
+	  <option value="AK,CA,HI,NV,OR,WA" style="margin-bottom: 10px;">West</option>
+          _cicstateoptions_
+        </select>
+
+	<p><input type="submit" value="_textbeginsearch_" onClick="prepareStateSearch();"></p>
+      </form>
+    </td>
+  </tr>
+</table>
+}
+
+_cicstatesearchresults_ {
+<div class="cicheading">Search Results</div>
+
+<div id="stq_results"></div>
+}
+
+# Shared between the "search institutions by state" and "advanced search" pages
+_cicstateoptions_ {
+  <option value="AL">Alabama</option>
+  <option value="AK">Alaska</option>
+  <option value="AZ">Arizona</option>
+  <option value="AR">Arkansas</option>
+  <option value="CA">California</option>
+  <option value="CO">Colorado</option>
+  <option value="CT">Connecticut</option>
+  <option value="DE">Delaware</option>
+  <option value="DC">District of Columbia</option>
+  <option value="FL">Florida</option>
+  <option value="GA">Georgia</option>
+  <option value="HI">Hawaii</option>
+  <option value="ID">Idaho</option>
+  <option value="IL">Illinois</option>
+  <option value="IN">Indiana</option>
+  <option value="IA">Iowa</option>
+  <option value="KS">Kansas</option>
+  <option value="KY">Kentucky</option>
+  <option value="LA">Louisiana</option>
+  <option value="ME">Maine</option>
+  <option value="MD">Maryland</option>
+  <option value="MA">Massachusetts</option>
+  <option value="MI">Michigan</option>
+  <option value="MN">Minnesota</option>
+  <option value="MS">Mississippi</option>
+  <option value="MO">Missouri</option>
+  <option value="MT">Montana</option>
+  <option value="NE">Nebraska</option>
+  <option value="NV">Nevada</option>
+  <option value="NH">New Hampshire</option>
+  <option value="NJ">New Jersey</option>
+  <option value="NM">New Mexico</option>
+  <option value="NY">New York</option>
+  <option value="NC">North Carolina</option>
+  <option value="ND">North Dakota</option>
+  <option value="OH">Ohio</option>
+  <option value="OK">Oklahoma</option>
+  <option value="OR">Oregon</option>
+  <option value="PA">Pennsylvania</option>
+  <option value="RI">Rhode Island</option>
+  <option value="SC">South Carolina</option>
+  <option value="SD">South Dakota</option>
+  <option value="TN">Tennessee</option>
+  <option value="TX">Texas</option>
+  <option value="UT">Utah</option>
+  <option value="VT">Vermont</option>
+  <option value="VA">Virginia</option>
+  <option value="WA">Washington</option>
+  <option value="WV">West Virginia</option>
+  <option value="WI">Wisconsin</option>
+  <option value="WY">Wyoming</option>
+}
+
+
+# ------------------------------------------------------------------------------------------
+#   QUERY  (Search -> Bibliography Search)
+# ------------------------------------------------------------------------------------------
+
+_cicbibliographysearchheader_ {
+_style:cicheader_(onLoad="initializeBibliographySearch();")
+}
+
+_cicbibliographysearchjavascript_ {
+function initializeBibliographySearch()
+\{
+   document.BibliographyQueryForm.req.focus();
+\}
+
+function prepareBibliographySearch()
+\{
+   var req_value = document.BibliographyQueryForm.req.value;
+   document.BibliographyQueryForm.fqv.value = req_value.replace(",", "");
+\}
+
+function initalizeAdvancedBibliographySearch()
+\{
+\}
+
+function prepareAdvancedBibliographySearch()
+\{
+   document.AdvancedBibliographyQueryForm.q.value = "";
+
+   for (var i = 0; i < document.AdvancedBibliographyQueryForm.abqv.length; i++) \{
+      var abqv_value = document.AdvancedBibliographyQueryForm.abqv[i].value;
+      if (abqv_value != "") \{
+	 var combiner = "&";
+	 if (i < (document.AdvancedBibliographyQueryForm.abqv.length - 1) && document.AdvancedBibliographyQueryForm.abqc[i].value == "or") \{
+	    combiner = "|";
+	 \}
+	 if (document.AdvancedBibliographyQueryForm.abqp[i].value == "1") \{
+	    abqv_value = '"' + abqv_value + '"';
+         \}
+         addQueryTerm(document.AdvancedBibliographyQueryForm.q, "[" + abqv_value + "]:" + document.AdvancedBibliographyQueryForm.abqi[i].value, combiner);
+      \}
+   \}
+
+   // Remove the trailing combiner
+   document.AdvancedBibliographyQueryForm.q.value = removeFromEnd(document.AdvancedBibliographyQueryForm.q.value, " & ");
+   document.AdvancedBibliographyQueryForm.q.value = removeFromEnd(document.AdvancedBibliographyQueryForm.q.value, " | ");
+\}
+}
+
+_cicabqline_ {
+  <tr>
+    <td style="white-space: nowrap;">
+      <select name="abqi" onChange="prepareAdvancedBibliographySearch();">
+        <option value="RE">General keyword</option>
+	<option value="RR">Author keyword</option>
+	<option value="RF">Title keyword</option>
+      </select>
+
+      <select name="abqp" onChange="prepareAdvancedBibliographySearch();">
+	<option value='0'>contains</option>
+	<option value='1'>is</option>
+      </select>
+
+      <input name='abqv' type='text' style='width: 450px'/>
+
+      <select name="abqc" onChange="prepareAdvancedBibliographySearch();">
+	<option value="and">and</option>
+	<option value="or">or</option>
+      </select>
+    </td>
+  </tr>
+}
+
+_cicabqlinenocombiner_ {
+  <tr>
+    <td style="white-space: nowrap;">
+      <select name="abqi" onChange="prepareAdvancedBibliographySearch();">
+        <option value="RE">General keyword</option>
+	<option value="RR">Author keyword</option>
+	<option value="RF">Title keyword</option>
+      </select>
+
+      <select name="abqp" onChange="prepareAdvancedBibliographySearch();">
+	<option value='0'>contains</option>
+	<option value='1'>is</option>
+      </select>
+
+      <input name='abqv' type='text' style='width: 450px'/>
+    </td>
+  </tr>
+}
+
+_cicbibliographysearchpage_ {
+<div class="cicheading">Bibliography Search</div>
+_cicblankline_
+<table>
+  <tr>
+    <td>
+    <form name=BibliographyQueryForm method=get action="_gwcgi_" onSubmit="prepareBibliographySearch();">
+      <input type="hidden" name="a" value="q" />
+      <input type="hidden" name="fqc" value="and" />
+
+      <select name="fqf" onChange="prepareBibliographySearch();">
+        <option value="RE">General keyword</option>
+        <option value="RR">Author keyword</option>
+        <option value="RF">Title keyword</option>
+      </select>
+
+      <input type="hidden" name="fqv" value="" />
+      <input name='req' type='text' style='width: 450px'/>
+
+      <input type="hidden" name="m" value="-1" />
+      <input type="submit" value="_textbeginsearch_" onClick="prepareBibliographySearch();">
+    </form>
+    </td>
+  </tr>
+</table>
+
+<p>&nbsp;</p>
+
+<div class="cicsubheading">Advanced Search for References</div>
+_cicblankline_
+<form name="AdvancedBibliographyQueryForm" method="get" action="_gwcgi_" onSubmit="prepareAdvancedBibliographySearch();">
+  <input type="hidden" name="a" value="q">
+  <input type="hidden" name="q" value="">
+  <input type="hidden" name="qt" value="1">
+  <input type="hidden" name="qf" value="1">
+  <input type="hidden" name="fqa" value="1">
+  <input type="hidden" name="m" value="-1">
+
+  <table>
+    _cicabqline_
+    _cicabqline_
+    _cicabqlinenocombiner_
+
+    <tr>
+      <td>
+        <div style="float:right"><input type="submit" value="_textbeginsearch_" onClick="prepareAdvancedBibliographySearch();"></div>
+      </td>
+    </tr>
+  </table>
+</form>
+}
+
+
+
+# ------------------------------------------------------------------------------------------
+#   QUERY  (Search -> Advanced Search)
+# ------------------------------------------------------------------------------------------
+
+# Hide the "or enter a query directly" box
+_advancedformextra_ {}
+
+# We have our own Javascript for the form searching
+_formfunctions_ {}
+
+# Hide the "search and display results in ... order" text
+_textformselect_ {}
+
+_cicadvancedsearchheader_ {
+_style:cicheader_(onLoad="initializeAdvancedSearch();")
+}
+
+_cicadvancedsearchpage_ {
+<div class="cicheading">Advanced Search</div>
+
+<noscript>
+<p><b>_textnojsformwarning_</b></p>
+</noscript>
+
+_cicblankline_
+<center>
+  <form name="QueryForm" method="get" action="_gwcgi_">
+    _advancedforms_
+  </form>
+</center>
+}
+
+_cicaqvdefault_ {<input id='aqv_1_field' name='aqv' type='text' style='width: 450px'/>}
+_cicaqvtypeofplace_ {<select id='aqv_1_field' name='aqv' style='width: 450px'><option value='Individual building'>Individual building<\\/option><option value='Landscape site'>Landscape site<\\/option><option value='Campus arrangement'>Campus arrangement<\\/option><option value='Building group'>Building group<\\/option><\\/select>}
+
+_cicaqline_ {
+<tr>
+  <td colspan="3" style="white-space: nowrap;">
+    <center>
+        <select name="aqi" onChange="changedAQI();">
+	  <option value="">Keyword</option>
+	  <option value="PL">Type of place</option>
+	  <option value="IN">Institution</option>
+	  <option value="AR">Designer</option>
+	</select>
+	<input type="hidden" name="aqib" value="">
+
+	<select name="aqp" onChange="prepareAdvancedSearch();">
+	  <option value='0'>contains</option>
+	  <option value='1'>is</option>
+	</select>
+
+	<span id="aqv_1_">
+	  _cicaqvdefault_(_1_)
+	</span>
+
+	<select name="aqc" onChange="prepareAdvancedSearch();">
+	  <option value="and">and</option>
+	  <option value="or">or</option>
+	</select>
+    </center>
+  </td>
+</tr>
+}
+
+_advancedforms_ {
+<input type="hidden" name="a" value="q">
+<input type="hidden" name="q" value="">
+<input type="hidden" name="qt" value="1">
+<input type="hidden" name="qf" value="1">
+<input type="hidden" name="fqa" value="1">
+<input type="hidden" name="m" value="-1">
+
+<table>
+_cicaqline_(0)
+_cicaqline_(1)
+_cicaqline_(2)
+
+<tr>
+  <td colspan="3">&nbsp;</td>
+</tr>
+
+<tr>
+  <td valign="top"><center><b>Function:</b></center></td>
+  <td valign="top"><center><b>Time period:</b></center></td>
+  <td valign="top"><center><b>Style:</b></center></td>
+</tr>
+
+<tr>
+  <!-- Function: Functions metadata, index FU -->
+  <td valign="top">
+    <select name="fuq" onChange="prepareAdvancedSearch();" size="10" multiple="true" style="width: 225px;">
+      <option value="academic department building">academic department building</option>
+      <option value="administration">administration</option>
+      <option value="admissions office">admissions office</option>
+      <option value="alumni center">alumni center</option>
+      <option value="arboretum">arboretum</option>
+      <option value="archaeological site">archaeological site</option>
+      <option value="auditorium">auditorium</option>
+      <option value="bell tower">bell tower</option>
+      <option value="chapel">chapel</option>
+      <option value="classrooms">classrooms</option>
+      <option value="debating society">debating society</option>
+      <option value="dining hall">dining hall</option>
+      <option value="facility management building">facility management building</option>
+      <option value="faculty offices">faculty offices</option>
+      <option value="gardens">gardens (planned)</option>
+      <option value="Greek letter society">Greek letter society</option>
+      <option value="gymnasium">gymnasium</option>
+      <option value="infirmary">infirmary</option>
+      <option value="library">library</option>
+      <option value="master plan campus">master plan (campus)</option>
+      <option value="master plan landscape">master plan (landscape)</option>
+      <option value="memorial site">memorial site</option>
+      <option value="museum">museum</option>
+      <option value="observatory">observatory</option>
+      <option value="old main">old main</option>
+      <option value="outdoor space">outdoor space</option>
+      <option value="president's house">president's house</option>
+      <option value="private residence">private residence</option>
+      <option value="residence hall">residence hall</option>
+      <option value="stadium">stadium</option>
+      <option value="student union">student union</option>
+      <option value="theatre">theatre</option>
+      <option value="other">other</option>
+    </select>
+  </td>
+
+  <!-- Time period: Time_period metadata, index TM -->
+  <td valign="top">
+    <select name="tmq" onChange="prepareAdvancedSearch();" size="10" multiple="true" style="width: 225px;">
+      <option value="pre 1800">pre-1800</option>
+      <option value="1800 1850">1800-1850</option>
+      <option value="1850 1900">1850-1900</option>
+      <option value="1900 1945">1900-1945</option>
+      <option value="1945 1995">1945-1995</option>
+      <option value="post 1995">post-1995</option>
+    </select>
+  </td>
+
+  <!-- Style: Style metadata, index SY -->
+  <td valign="top">
+    <select name="syq" onChange="prepareAdvancedSearch();" size="10" multiple="true" style="width: 225px;">
+      <option value="American colonial">American colonial</option>
+      <option value="Federal">Federal</option>
+      <option value="Greek revival">Greek revival</option>
+      <option value="Italianate">Italianate</option>
+      <option value="Gothic revival">Gothic revival</option>
+      <option value="Romanesque revival">Romanesque revival</option>
+      <option value="Victorian">Victorian</option>
+      <option value="Beaux arts classicism">Beaux-Arts classicism</option>
+      <option value="Colonial revival">Colonial revival</option>
+      <option value="Mission Mission revival">Mission/Mission revival</option>
+      <option value="Modern pre WWII">Modern/pre-World War II</option>
+      <option value="Modern post WWII">Modern/post-World War II</option>
+      <option value="Postmodern">Postmodern</option>
+      <option value="Contemporary">Contemporary</option>
+      <option value="Regionalist Vernacular">Regionalist/Vernacular</option>
+      <option value="Other">Other</option>
+    </select>
+  </td>
+</tr>
+
+<tr>
+  <td colspan="3">&nbsp;</td>
+</tr>
+
+<tr>
+  <td valign="top"><center><b>Materials:</b></center></td>
+  <td valign="top"><center><b>Designation:</b></center></td>
+  <td valign="top"><center><b>State:</b></center></td>
+</tr>
+
+<tr>
+  <!-- Materials: Materials metadata, index MA -->
+  <td valign="top">
+    <select name="maq" onChange="prepareAdvancedSearch();" size="10" multiple="true" style="width: 225px;">
+      <option value="aluminium siding">aluminium siding</option>
+      <option value="ashlar">ashlar</option>
+      <option value="asphalt">asphalt</option>
+      <option value="bluestone">bluestone</option>
+      <option value="brick">brick</option>
+      <option value="brownstone">brownstone</option>
+      <option value="cedar">cedar</option>
+      <option value="cement">cement</option>
+      <option value="cinderblock">cinderblock</option>
+      <option value="clapboard">clapboard</option>
+      <option value="clay block">clay block</option>
+      <option value="copper">copper</option>
+      <option value="cypress">cypress</option>
+      <option value="dolomite">dolomite</option>
+      <option value="fiberglass">fiberglass</option>
+      <option value="fieldstone">fieldstone</option>
+      <option value="flagstone">flagstone</option>
+      <option value="foam">foam</option>
+      <option value="gneiss">gneiss</option>
+      <option value="granite">granite</option>
+      <option value="gypsum block">gypsum block</option>
+      <option value="ignimbrite">ignimbrite</option>
+      <option value="lathe and plaster">lathe and plaster</option>
+      <option value="limestone">limestone</option>
+      <option value="logs">logs</option>
+      <option value="marble">marble</option>
+      <option value="masonry">masonry</option>
+      <option value="plaster">plaster</option>
+      <option value="quartzite">quartzite</option>
+      <option value="rubber">rubber</option>
+      <option value="sandstone">sandstone</option>
+      <option value="schist">schist</option>
+      <option value="slate">slate</option>
+      <option value="steel">steel</option>
+      <option value="stone">stone</option>
+      <option value="stucco">stucco</option>
+      <option value="terra cotta">terra cotta</option>
+      <option value="tile">tile</option>
+      <option value="wood">wood</option>
+    </select>
+  </td>
+
+  <!-- Designation: Designation metadata, index DE -->
+  <td valign="top">
+    <select name="deq" onChange="prepareAdvancedSearch();" size="10" multiple="true" style="width: 225px;">
+      <option value="National Register">National Register</option>
+      <option value="National Historic Landmark">National Historic Landmark</option>
+      <option value="HABS HAER">HABS/HAER</option>
+      <option value="Local state">Local and state designations</option>
+    </select>
+  </td>
+
+  <!-- State: State metadata, index ST -->
+  <td valign="top">
+    <select name="stq" onChange="prepareAdvancedSearch();" size="10" multiple="true" style="width: 225px;">
+      <option value="Northeast">Northeast</option>
+      <option value="Southeast">Southeast</option>
+      <option value="Midwest">Midwest</option>
+      <option value="Southwest">Southwest</option>
+      <option value="Mountain">Mountain</option>
+      <option value="West" style="margin-bottom: 10px">West</option>
+      _cicstateoptions_
+    </select>
+  </td>
+</tr>
+
+<tr>
+  <td colspan="3">
+    <div style="float:right"><input type="submit" value="_textbeginsearch_" onClick="prepareAdvancedSearch();"></div>
+  </td>
+</tr>
+
+</table>
+}
+
+_cicadvancedsearchjavascript_ {
+function initializeAdvancedSearch()
+\{
+   for (var i = 0; i < document.QueryForm.aqi.length; i++) \{
+      if (document.QueryForm.aqi[i].value == "PL") \{
+	 document.QueryForm.aqp[i].disabled = true;
+	 document.QueryForm.aqp[i].options[1].selected = true;
+	 document.getElementById("aqv" + i).innerHTML = "_cicaqvtypeofplace_(" + i + ")";
+      \}
+   \}
+
+   prepareAdvancedSearch();
+\}
+
+function changedAQI()
+\{
+   for (var i = 0; i < document.QueryForm.aqi.length; i++) \{
+      if (document.QueryForm.aqi[i].value != document.QueryForm.aqib[i].value) \{
+         if (document.QueryForm.aqi[i].value == "PL") \{
+	    document.QueryForm.aqp[i].disabled = true;
+	    document.QueryForm.aqp[i].options[1].selected = true;
+	    document.getElementById("aqv" + i).innerHTML = "_cicaqvtypeofplace_(" + i + ")";
+	 \}
+	 else \{
+	    document.QueryForm.aqp[i].disabled = false;
+	    document.getElementById("aqv" + i).innerHTML = "_cicaqvdefault_(" + i + ")";
+	 \}
+
+	 document.QueryForm.aqib[i].value = document.QueryForm.aqi[i].value;
+      \}
+   \}
+
+   prepareAdvancedSearch();
+\}
+
+function prepareAdvancedSearch()
+\{
+   document.QueryForm.q.value = "";
+
+   for (var aqv_i = 0; aqv_i < document.QueryForm.aqv.length; aqv_i++) \{
+      var aqv_value = document.QueryForm.aqv[aqv_i].value;
+      if (aqv_value != "") \{
+         var real_index = /aqv([0-9]+)field/.exec(document.QueryForm.aqv[aqv_i].id)[1];
+	 var combiner = "&";
+	 if (document.QueryForm.aqc[real_index].value == "or") \{
+	    combiner = "|";
+	 \}
+	 if (document.QueryForm.aqp[real_index].value == "1") \{
+	    aqv_value = '"' + aqv_value + '"';
+         \}
+         addQueryTerm(document.QueryForm.q, "[" + aqv_value + "]:" + document.QueryForm.aqi[real_index].value, combiner);
+      \}
+   \}
+
+   document.QueryForm.q.value += "(";
+   addIndexValue(document.QueryForm.q, document.QueryForm.fuq, "FU", "&");
+   addIndexValue(document.QueryForm.q, document.QueryForm.tmq, "TM", "&");
+   addIndexValue(document.QueryForm.q, document.QueryForm.syq, "SY", "&");
+   addIndexValue(document.QueryForm.q, document.QueryForm.maq, "MA", "&");
+   addIndexValue(document.QueryForm.q, document.QueryForm.deq, "DE", "&");
+   addIndexValue(document.QueryForm.q, document.QueryForm.stq, "ST", "&");
+   document.QueryForm.q.value = removeFromEnd(document.QueryForm.q.value, " & ");
+   document.QueryForm.q.value = removeFromEnd(document.QueryForm.q.value, " | ");
+   document.QueryForm.q.value += ")";
+
+   // Remove the trailing combiner
+   document.QueryForm.q.value = removeFromEnd(document.QueryForm.q.value, "()");
+   document.QueryForm.q.value = removeFromEnd(document.QueryForm.q.value, " & ");
+   document.QueryForm.q.value = removeFromEnd(document.QueryForm.q.value, " | ");
+   // alert(document.QueryForm.q.value);
+\}
+
+function addQueryTerm(query_field_reference, index_value, combiner)
+\{
+   if (index_value != "") \{
+      query_field_reference.value += "(" + index_value + ") " + combiner + " ";
+   \}
+\}
+
+function addIndexValue(query_field_reference, select_reference, index_code, combiner)
+\{
+   var index_value = "";
+   for (var i = 0; i < select_reference.options.length; i++) \{
+      if (select_reference.options[i].selected) \{
+         index_value += ((index_value != "") ? " " + combiner + " " : "");
+	 index_value += '["' + select_reference.options[i].value + '"]:' + index_code;
+      \}
+   \}
+   addQueryTerm(query_field_reference, index_value, "&");
+\}
+
+function removeFromEnd(source_string, offender)
+\{
+   if (source_string.length < offender.length) \{
+      return source_string;
+   \}
+
+   if (source_string.substring(source_string.length - offender.length, source_string.length) != offender) \{
+      return source_string;
+   \}
+
+   return source_string.substring(0, source_string.length - offender.length);
+\}
+}
+
+_pagefooterextra_ {
+_cicblankline_
+<table cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td align="left">_If_(_prevfirst_,<a href="_gwcgi_?e=_compressedoptions_&amp;a=q&amp;r=_prevfirst_">_textmatches__prevfirst_ - _prevlast_</a>)</td>
+<td align="right">_If_(_nextfirst_,<a href="_gwcgi_?e=_compressedoptions_&amp;a=q&amp;r=_nextfirst_">_textmatches__nextfirst_ - _nextlast_</a>)</td>
+</tr>
+</table>
+}
+
+
+
+# ------------------------------------------------------------------------------------------
+#   ANYLINK MENU
+# ------------------------------------------------------------------------------------------
+
+package anylink
+
+_anylinkjavascript_ {
+/***********************************************
+* AnyLink Drop Down Menu- © Dynamic Drive (www.dynamicdrive.com)
+* This notice MUST stay intact for legal use
+* Visit http://www.dynamicdrive.com/ for full source code
+***********************************************/
+
+/////No further editting needed
+
+var ie4=document.all
+var ns6=document.getElementById&&!document.all
+
+if (ie4||ns6) \{
+document.write('<div id="dropmenudiv" style="visibility:hidden;width:'+menuwidth+';background-color:'+menubgcolor+'" onMouseover="clearhidemenu()" onMouseout="dynamichide(event)"><\\/div>')
+/* Change to fix IE problem with select boxes, as described at http://dotnetjunkies.com/WebLog/jking/archive/category/139.aspx */
+document.write('<iframe id="dropmenuiframe" style="display:none; position: absolute; background-color: white; left: 0px; top: 0px" src="javascript:false" frameBorder="0" scrolling="no"><\\/iframe>')
+\}
+
+function getposOffset(what, offsettype)\{
+var totaloffset=(offsettype=="left")? what.offsetLeft : what.offsetTop;
+var parentEl=what.offsetParent;
+while (parentEl!=null)\{
+totaloffset=(offsettype=="left")? totaloffset+parentEl.offsetLeft : totaloffset+parentEl.offsetTop;
+parentEl=parentEl.offsetParent;
+\}
+return totaloffset;
+\}
+
+
+function showhide(obj, e, visible, hidden, menuwidth)\{
+if (ie4||ns6)
+dropmenuobj.style.left = "-500px";
+dropmenuobj.style.top = "-500px";
+if (menuwidth!="")\{
+dropmenuobj.widthobj=dropmenuobj.style
+dropmenuobj.widthobj.width=menuwidth
+\}
+if (e.type=="click" && obj.visibility==hidden || e.type=="mouseover")
+obj.visibility=visible
+else if (e.type=="click")
+obj.visibility=hidden
+\}
+
+function iecompattest()\{
+return (document.compatMode && document.compatMode!="BackCompat")? document.documentElement : document.body
+\}
+
+function clearbrowseredge(obj, whichedge)\{
+var edgeoffset=0
+if (whichedge=="rightedge")\{
+var windowedge=ie4 && !window.opera? iecompattest().scrollLeft+iecompattest().clientWidth-15 : window.pageXOffset+window.innerWidth-15
+dropmenuobj.contentmeasure=dropmenuobj.offsetWidth
+if (windowedge-dropmenuobj.x < dropmenuobj.contentmeasure)
+edgeoffset=dropmenuobj.contentmeasure-obj.offsetWidth
+\}
+else\{
+var topedge=ie4 && !window.opera? iecompattest().scrollTop : window.pageYOffset
+var windowedge=ie4 && !window.opera? iecompattest().scrollTop+iecompattest().clientHeight-15 : window.pageYOffset+window.innerHeight-18
+dropmenuobj.contentmeasure=dropmenuobj.offsetHeight
+if (windowedge-dropmenuobj.y < dropmenuobj.contentmeasure)\{ //move up?
+edgeoffset=dropmenuobj.contentmeasure+obj.offsetHeight
+if ((dropmenuobj.y-topedge)<dropmenuobj.contentmeasure) //up no good either?
+edgeoffset=dropmenuobj.y+obj.offsetHeight-topedge
+\}
+\}
+return edgeoffset
+\}
+
+function populatemenu(what)\{
+if (ie4||ns6)
+dropmenuobj.innerHTML=what.join("")
+\}
+
+
+function dropdownmenu(obj, e, menucontents, menuwidth)\{
+if (window.event) event.cancelBubble=true
+else if (e.stopPropagation) e.stopPropagation()
+clearhidemenu()
+dropmenuobj=document.getElementById? document.getElementById("dropmenudiv") : dropmenudiv
+populatemenu(menucontents)
+
+if (ie4||ns6)\{
+  showhide(dropmenuobj.style, e, "visible", "hidden", menuwidth)
+  dropmenuobj.x=getposOffset(obj, "left")
+  dropmenuobj.y=getposOffset(obj, "top")
+  dropmenuobj.style.left=dropmenuobj.x-clearbrowseredge(obj, "rightedge")+"px"
+  dropmenuobj.style.top=dropmenuobj.y-clearbrowseredge(obj, "bottomedge")+obj.offsetHeight+"px"
+  /* Change to fix IE problem with select boxes, as described at http://dotnetjunkies.com/WebLog/jking/archive/category/139.aspx */
+  iframeobj = document.getElementById("dropmenuiframe");
+  iframeobj.style.left = dropmenuobj.style.left;
+  iframeobj.style.top = dropmenuobj.style.top;
+  iframeobj.style.width = dropmenuobj.style.width;
+  iframeobj.style.zIndex = 99;
+  if (ie4) \{
+    iframeobj.style.height = dropmenuobj.offsetHeight;
+    iframeobj.style.display = "block";
+  \}
+\}
+
+return clickreturnvalue()
+\}
+
+function clickreturnvalue()\{
+if (ie4||ns6) return false
+else return true
+\}
+
+function contains_ns6(a, b) \{
+while (b.parentNode)
+if ((b = b.parentNode) == a)
+return true;
+return false;
+\}
+
+function dynamichide(e)\{
+if (ie4&&!dropmenuobj.contains(e.toElement))
+delayhidemenu()
+else if (ns6&&e.currentTarget!= e.relatedTarget&& !contains_ns6(e.currentTarget, e.relatedTarget))
+delayhidemenu()
+\}
+
+function hidemenu(e)\{
+if (typeof dropmenuobj!="undefined")\{
+if (ie4||ns6)
+dropmenuobj.style.visibility="hidden"
+/* Change to fix IE problem with select boxes, as described at http://dotnetjunkies.com/WebLog/jking/archive/category/139.aspx */
+iframeobj.style.display = "none"
+\}
+\}
+
+function delayhidemenu()\{
+if (ie4||ns6)
+delayhide=setTimeout("hidemenu()",disappeardelay)
+\}
+
+function clearhidemenu()\{
+if (typeof delayhide!="undefined")
+clearTimeout(delayhide)
+\}
+
+if (hidemenu_onclick=="yes")
+document.onclick=hidemenu
+}
Index: collections/trunk/cic-hcap/macros/style.css
===================================================================
--- collections/trunk/cic-hcap/macros/style.css	(revision 14139)
+++ collections/trunk/cic-hcap/macros/style.css	(revision 14139)
@@ -0,0 +1,223 @@
+A {
+   color: #3333CC;
+}
+
+IMG {
+   border: 0px;
+}
+
+
+.ciccontent {
+   width: 947px; 
+   margin: 0 auto;
+}
+
+#cichomephotoarea {
+   padding-left: 12px;
+   padding-right: 12px;
+   padding-top: 0px;
+   padding-bottom: 0px;
+}
+
+#cichomephoto {
+   width: 457px;
+   height: 368px;
+}
+
+#cichomephotocaption {
+   font-size: 0.8em;
+}
+
+#cichometext {
+   font-size: 1.1em;
+   line-height: 1.6em;
+}
+
+.cicglossaryentry {
+   clear: both;
+   padding-top: 12px;
+}
+
+.cicglossaryphoto {
+   float: right;
+   padding-left: 12px;
+}
+
+.cicheading {
+   font-size: 1.5em;
+   line-height: 1.2em;
+   font-weight: bold;
+}
+
+.cicplaceimage {
+   padding-bottom: 2em;
+}
+
+.ciccaption {
+   font-size: 0.8em;
+}
+
+#cicplaceconstructiondatestable {
+   padding-left: 2em;
+}
+
+.cicplaceconstructiondatetd {
+   padding-right: 1em;
+   white-space: nowrap;
+}
+
+#cicplacefunctionstable {
+   padding-left: 2em;
+}
+
+.cicplacefunctionyeartd {
+   padding-right: 1em;
+   white-space: nowrap;
+}
+
+#cicplacematerialstable {
+   padding-left: 2em;
+}
+
+.cicreference {
+   margin-top: 0px;
+   margin-left: 40px;
+   text-indent: -40px;
+}
+
+.cicsubheading {
+   font-size: 1.2em;
+   font-weight: bold;
+}
+
+
+/* CSS changes for printing: no navigation bar, and maximum 720 pixels wide. */
+@media print {
+   .cicprinthide {
+      display: none;
+   }
+
+   .cicmastheadimage {
+      width: 720px;
+   }
+
+   .ciccontent {
+      width: 720px; 
+      margin: 0 auto;
+   }
+}
+
+
+#dropmenudiv {
+   position:absolute;
+   border:1px solid black;
+   border-bottom-width: 0;
+   font: normal 12px Verdana;
+   line-height:18px;
+   z-index:100;
+}
+
+#dropmenudiv a {
+   width: 100%;
+   display: block;
+   text-indent: 3px;
+   border-bottom: 1px solid black;
+   padding: 1px 0;
+   text-decoration: none;
+   font-weight: bold;
+}
+
+#dropmenudiv a:hover { /*hover background color*/
+   background-color: yellow;
+}
+
+
+
+
+
+html, body {
+   background: #fff;
+   color: #212474;
+}
+
+html, body, form, textarea, input, select {
+   margin: 0;
+   padding: 0;
+   font: 12px/1.4em Arial, Verdana, Helvetica, sans-serif; 
+}
+
+#topnav {
+   position: relative;
+   left: 0px;
+   height: 3.7em;
+   margin: 0;
+   padding: 0;
+}
+
+#topnav li {
+   list-style: none;
+   margin: 0;
+   padding: 0;
+}
+
+#topnav li a, #topnav li form {
+   position: absolute; 
+   display: block;
+   top: 0px;
+   width: 216px;
+   height: 20px;
+   padding: 6px 0 4px 17px;
+   border: 1px solid #22228c;
+   color: #192077;
+   text-decoration: none;
+   font-size: 0.95em;
+   font-weight: bold;
+   letter-spacing: 0.1em;
+   text-transform: uppercase;
+}
+
+#topnav li a:hover {
+   color: #000;
+}
+				
+#btn_about {
+   left: 0;		
+   background: #7e9e53;
+}
+
+#btn_browse {
+   left: 234px; 
+   background: #7ed0e0;
+}
+
+#btn_search {
+   left: 468px; 
+   background: #e89419;
+}
+
+#btn_quick form {
+   left: 713px; 
+   background: #d4be55;
+   padding: 0;
+}
+
+#search_query {
+   margin: -1px 3px 0 0;
+   float: left;
+   width: 130px; 
+   font-size: 1em;
+}
+
+.inputfocus {
+   color: #000;
+}
+
+.inputblur {
+   color: #555;
+}
+
+#search_submit {
+   border: none;
+   background: transparent;
+   color: #192077;
+}
Index: collections/trunk/cic-hcap/metadata/ex.mds
===================================================================
--- collections/trunk/cic-hcap/metadata/ex.mds	(revision 14139)
+++ collections/trunk/cic-hcap/metadata/ex.mds	(revision 14139)
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE MetadataSet [
+
+  <!-- The outer tag of any metadata set. Contains some number of elements.             -->
+  <!-- @param contact     A contact address for the creator.                            -->
+  <!-- @param creator     The name of the entity resposibly for this set.               -->
+  <!-- @param family      The name of this sets family.                                 -->
+  <!-- @param lastchanged The full date, user name and machine name of the last editor. --> 
+  <!--   uses the form:                                                                 -->
+  <!--   Day Mon(th) dd hh:mm:ss yyyy '-' <username> on <machine>                       -->
+  <!-- @param namespace   The namespace of this metadata set.                           -->
+  <!ELEMENT MetadataSet ((Name|Description|Element)+)>
+  <!ATTLIST MetadataSet
+				contact     CDATA #REQUIRED
+				creator     CDATA #REQUIRED
+				description CDATA #REQUIRED
+            family      CDATA #REQUIRED
+				lastchanged CDATA #REQUIRED
+            name        CDATA #REQUIRED
+				namespace   CDATA #REQUIRED>
+
+  <!-- The name of a metadata set. Is language specific. -->
+  <!ELEMENT Name (#PCDATA)>
+  <!ATTLIST Name
+            language CDATA "en">
+
+  <!-- The description of a metadata set. Is language specific. -->
+  <!ELEMENT Description (#PCDATA)>
+  <!ATTLIST Description
+            language CDATA "en">
+
+  <!-- An element in the metadata set. -->
+  <!ELEMENT Element (Attribute*,OptionList?)>
+  <!ATTLIST Element
+            name       CDATA #REQUIRED
+				occurances CDATA "0">
+
+  <!-- Each element has several attribute children. -->
+  <!ELEMENT Attribute (#PCDATA)>
+  <!ATTLIST Attribute
+            name CDATA #REQUIRED>
+
+  <!-- For listing predefined values for this element. -->
+  <!ELEMENT OptionList (Value+)>
+  <!ATTLIST OptionList
+            restricted (true|false) "false">
+]>
+
+<MetadataSet contact="nzdl.org" creator="New Zealand Digital Libraries Project: Greenstone" family="Extracted Greenstone" lastchanged="Tue May 20 10:30:32 2003 - jmt12 on narya" namespace="ex" >
+
+  <Name language="en">Extracted Greenstone Metadata 1.0</Name>
+
+  <Description language="en">This document is the reference description, version 1.0 of the automatically extracted Greenstone Metadata Element Set.</Description>
+
+  <Element name="Encoding">
+    <Attribute name="comment" language="en">Not always available.</Attribute>
+    <Attribute name="definition" language="en">The encoding of the imported document as extracted by Greenstone.</Attribute>
+    <Attribute name="identifier" language="en">Encoding</Attribute>
+  </Element>
+
+  <Element name="Language">
+    <Attribute name="comment" language="en">Not always available.</Attribute>
+    <Attribute name="definition" language="en">The language of the imported document as extracted by Greenstone.</Attribute>
+    <Attribute name="identifier" language="en">Language</Attribute>
+  </Element>
+
+  <Element name="Source">
+    <Attribute name="comment" language="en">Hidden in the Librarian Interface as it already shown by the various file trees.</Attribute>
+    <Attribute name="definition" language="en">The filename of the document imported by Greenstone.</Attribute>
+    <Attribute name="identifier" language="en">Source</Attribute>
+  </Element>
+
+  <Element name="Title">
+    <Attribute name="comment" language="en">Not always available.</Attribute>
+    <Attribute name="definition" language="en">The title of the imported document as extracted by Greenstone.</Attribute>
+    <Attribute name="identifier" language="en">Title</Attribute>
+  </Element>
+
+</MetadataSet>
Index: collections/trunk/cic-hcap/metadata/profile.xml
===================================================================
--- collections/trunk/cic-hcap/metadata/profile.xml	(revision 14139)
+++ collections/trunk/cic-hcap/metadata/profile.xml	(revision 14139)
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE Profiles [
+<!ELEMENT Profiles (Action*)>
+<!ELEMENT Action (#PCDATA)>
+<!ATTLIST Action
+                source     CDATA #REQUIRED
+                target     CDATA "">
+]>
+<Profiles/>
Index: collections/trunk/cic-hcap/perllib/plugins/CICPlug.pm
===================================================================
--- collections/trunk/cic-hcap/perllib/plugins/CICPlug.pm	(revision 14139)
+++ collections/trunk/cic-hcap/perllib/plugins/CICPlug.pm	(revision 14139)
@@ -0,0 +1,1445 @@
+###########################################################################
+#
+# CICPlug.pm
+#
+# Copyright (C) 2005 New Zealand Digital Library Project
+#
+# 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.
+#
+###########################################################################
+
+package CICPlug;
+
+
+use BasPlug;
+use DBI;
+use strict;
+no strict 'refs';
+
+
+sub BEGIN {
+    @CICPlug::ISA = ('BasPlug');
+}
+
+
+my $arguments =
+  [ 
+    { 'name' => "images_directory",
+      'type' => "string",
+      'deft' => "",
+      'reqd' => "yes" },
+    { 'name' => "cache_directory",
+      'type' => "string",
+      'deft' => &util::filename_cat($ENV{'GSDLHOME'}, "tmp"),
+      'reqd' => "no" },
+    { 'name' => "large_image_options",
+      'type' => "string",
+      'deft' => "",
+      'reqd' => "no" },
+    { 'name' => "large_image_type",
+      'type' => "string",
+      'deft' => "jpg",
+      'reqd' => "no" },
+    { 'name' => "large_image_width",
+      'type' => "string",
+      'deft' => "800",
+      'reqd' => "no" },
+    { 'name' => "medium_image_options",
+      'type' => "string",
+      'deft' => "",
+      'reqd' => "no" },
+    { 'name' => "medium_image_type",
+      'type' => "string",
+      'deft' => "jpg",
+      'reqd' => "no" },
+    { 'name' => "medium_image_width",
+      'type' => "string",
+      'deft' => "375",
+      'reqd' => "no" },
+    { 'name' => "small_image_options",
+      'type' => "string",
+      'deft' => "",
+      'reqd' => "no" },
+    { 'name' => "small_image_type",
+      'type' => "string",
+      'deft' => "jpg",
+      'reqd' => "no" },
+    { 'name' => "small_image_width",
+      'type' => "string",
+      'deft' => "225",
+      'reqd' => "no" }
+  ];
+
+my $options = { 'name'     => "CICPlug",
+		'desc'     => "{CICPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes" };
+
+
+sub get_default_process_exp
+{
+    return q^(?i)\.mdb$^;
+}
+
+
+sub new
+{
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if (defined $arguments) { push(@{$hashArgOptLists->{"ArgList"}}, @{$arguments}); }
+    if (defined $options) { push(@{$hashArgOptLists->{"OptList"}}, $options); }
+
+    my $self = new BasPlug($pluginlist, $inputargs, $hashArgOptLists);
+
+    return bless $self, $class;
+}
+
+
+my $state_abbr_to_name_mapping = {
+    "AL" => "Alabama",
+    "AK" => "Alaska",
+    "AZ" => "Arizona",
+    "AR" => "Arkansas",
+    "CA" => "California",
+    "CO" => "Colorado",
+    "CT" => "Connecticut",
+    "DC" => "District of Columbia",
+    "DE" => "Delaware",
+    "FL" => "Florida",
+    "GA" => "Georgia",
+    "HI" => "Hawaii",
+    "ID" => "Idaho",
+    "IL" => "Illinois",
+    "IN" => "Indiana",
+    "IA" => "Iowa",
+    "KS" => "Kansas",
+    "KY" => "Kentucky",
+    "LA" => "Louisiana",
+    "ME" => "Maine",
+    "MD" => "Maryland",
+    "MA" => "Massachusetts",
+    "MI" => "Michigan",
+    "MN" => "Minnesota",
+    "MS" => "Mississippi",
+    "MO" => "Missouri",
+    "MT" => "Montana",
+    "NE" => "Nebraska",
+    "NV" => "Nevada",
+    "NH" => "New Hampshire",
+    "NJ" => "New Jersey",
+    "NM" => "New Mexico",
+    "NY" => "New York",
+    "NC" => "North Carolina",
+    "ND" => "North Dakota",
+    "OH" => "Ohio",
+    "OK" => "Oklahoma",
+    "OR" => "Oregon",
+    "PA" => "Pennsylvania",
+    "RI" => "Rhode Island",
+    "SC" => "South Carolina",
+    "SD" => "South Dakota",
+    "TN" => "Tennessee",
+    "TX" => "Texas",
+    "UT" => "Utah",
+    "VT" => "Vermont",
+    "VA" => "Virginia",
+    "WA" => "Washington",
+    "WV" => "West Virginia",
+    "WI" => "Wisconsin",
+    "WY" => "Wyoming"
+    };
+
+my %state_name_to_abbr_mapping = reverse(%{$state_abbr_to_name_mapping});
+
+my $state_abbr_to_area_mapping = {
+    "AL" => "Southeast",
+    "AK" => "West",
+    "AZ" => "Southwest",
+    "AR" => "Southeast",
+    "CA" => "West",
+    "CO" => "Mountain",
+    "CT" => "Northeast",
+    "DC" => "Northeast",
+    "DE" => "Northeast",
+    "FL" => "Southeast",
+    "GA" => "Southeast",
+    "HI" => "West",
+    "ID" => "Mountain",
+    "IL" => "Midwest",
+    "IN" => "Midwest",
+    "IA" => "Midwest",
+    "KS" => "Midwest",
+    "KY" => "Southeast",
+    "LA" => "Southeast",
+    "ME" => "Northeast",
+    "MD" => "Northeast",
+    "MA" => "Northeast",
+    "MI" => "Midwest",
+    "MN" => "Midwest",
+    "MS" => "Southeast",
+    "MO" => "Midwest",
+    "MT" => "Mountain",
+    "NE" => "Midwest",
+    "NV" => "West",
+    "NH" => "Northeast",
+    "NJ" => "Northeast",
+    "NM" => "Southwest",
+    "NY" => "Northeast",
+    "NC" => "Southeast",
+    "ND" => "Midwest",
+    "OH" => "Midwest",
+    "OK" => "Southwest",
+    "OR" => "West",
+    "PA" => "Northeast",
+    "RI" => "Northeast",
+    "SC" => "Southeast",
+    "SD" => "Midwest",
+    "TN" => "Southeast",
+    "TX" => "Southwest",
+    "UT" => "Mountain",
+    "VT" => "Northeast",
+    "VA" => "Southeast",
+    "WA" => "West",
+    "WV" => "Southeast",
+    "WI" => "Midwest",
+    "WY" => "Mountain"
+    };
+
+
+my $place_type_id_to_name_mapping = {
+    "1" => "Individual building",
+    "2" => "Landscape site",
+    "3" => "Campus arrangement",
+    "4" => "Building group",
+};
+
+
+# This array must match the values in the tblArchTypes table
+my @place_styles_array = (
+    "American colonial",
+    "Federal",
+    "Greek revival",
+    "Italianate",
+    "Gothic revival",
+    "Romanesque revival",
+    "Victorian",
+    "Beaux-Arts classicism",
+    "Colonial revival",
+    "Mission/Mission revival",
+    "Modern/pre-WWII",
+    "Modern/post-WWII",
+    "Postmodern",
+    "Contemporary",
+    "Regionalist/Vernacular",
+    "Other"
+);
+
+
+my $place_functions_mapping = {
+    "academic department building" => "",
+    "administration" => "",
+    "admissions office" => "",
+    "alumni center" => "",
+    "arboretum" => "",
+    "archaeological site" => "",
+    "auditorium" => "",
+    "bell tower" => "",
+    "chapel" => "",
+    "classrooms" => "",
+    "debating society" => "",
+    "dining hall" => "",
+    "facility management building" => "",
+    "faculty offices" => "",
+    "gardens" => "",
+    "greek letter society" => "",
+    "gymnasium" => "",
+    "infirmary" => "",
+    "library" => "",
+    "master plan (campus)" => "",
+    "master plan (landscape)" => "",
+    "memorial site" => "",
+    "museum" => "",
+    "observatory" => "",
+    "old main" => "",
+    "outdoor space" => "",
+    "president's house" => "",
+    "private residence" => "",
+    "residence hall" => "",
+    "stadium" => "",
+    "student union" => "",
+    "theater" => "",
+    "other" => "",
+};
+
+
+my %designer_name_to_id_mapping;
+my %designer_name_to_place_ids_mapping;
+my $place_reference_id = 1;
+
+
+sub read
+{
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;
+
+    $self->{'filename'} = &util::filename_cat($base_dir, $file);
+    if ($self->{'filename'} !~ /$self->{'process_exp'}/ || !-f $self->{'filename'}) {
+	return undef;
+    }
+    $self->{'processor'} = $processor;
+    $self->{'gli'} = $gli;
+
+    # Open connection to Access database
+    my $dbh = DBI->connect('dbi:ODBC:CIC-HCAP');
+
+    $self->process_institutions($dbh);
+    $self->process_places($dbh);
+    $self->process_designers($dbh);
+
+    return 1;
+}
+
+
+sub process_institutions
+{
+    my $self = shift(@_);
+    my $dbh = shift(@_);
+    my $fail_log_handle = $self->{'failhandle'};
+
+    # Prepare SQL statement for getting everything from the Institution table
+    my $institution_sql_statement = "SELECT * FROM tblInstitution";  # WHERE Institution_ID<200";
+    my $institution_sql_handle = $dbh->prepare($institution_sql_statement);
+    $institution_sql_handle->{LongReadLen} = 65536;
+    $institution_sql_handle->execute() or die "Could not execute SQL statement.";
+
+    # Prepare SQL statement for getting the Institution places
+    my $institution_places_sql_statement = "SELECT Entry_ID,Current_name FROM tblPlace WHERE PlaceType>0 AND Institution_ID=?";
+    my $institution_places_sql_handle = $dbh->prepare($institution_places_sql_statement);
+    $institution_places_sql_handle->{LongReadLen} = 65536;
+
+    # Prepare SQL statement for getting the Institution best place image location
+    my $institution_best_place_image_location_sql_statement = "SELECT Location,Entry_ID FROM tblImages WHERE FileType=1 AND FileName=?";
+    my $institution_best_place_image_location_sql_handle = $dbh->prepare($institution_best_place_image_location_sql_statement);
+    $institution_best_place_image_location_sql_handle->{LongReadLen} = 65536;
+
+    # Prepare SQL statement for getting the Institution places images (only used to check if an institution has some images)
+    my $institution_places_images_sql_statement = "SELECT FileName FROM tblImages,tblPlace WHERE tblImages.FileType=1 AND tblImages.Entry_ID=tblPlace.Entry_ID AND tblPlace.Institution_ID=?";
+    my $institution_places_images_sql_handle = $dbh->prepare($institution_places_images_sql_statement);
+    $institution_places_images_sql_handle->{LongReadLen} = 65536;
+
+    # Prepare SQL statement for getting the Institution campus plans
+    my $institution_campus_plans_sql_statement = "SELECT * FROM tblCampusMaps WHERE Electronic=1 AND Institution_ID=?";
+    my $institution_campus_plans_sql_handle = $dbh->prepare($institution_campus_plans_sql_statement);
+    $institution_campus_plans_sql_handle->{LongReadLen} = 65536;
+
+    # Create a document object for each institution
+    my %institution_id_to_name_mapping;
+    my %institution_state_to_ids_mapping;
+    while (my $row_hashref = $institution_sql_handle->fetchrow_hashref) {
+	# Skip any institutions that didn't respond
+	next if !defined($row_hashref->{"City"});
+
+	my $institution_id = $row_hashref->{"Institution_ID"};
+	# print STDERR "       Institution $institution_id\n";
+	my $institution_doc_obj = new doc($self->{'filename'} . "-", "indexed_doc");
+	$institution_doc_obj->set_OID("i$institution_id");
+	&new_metadata_entry($institution_doc_obj, "DocumentType", "Institution");
+
+	# For some reason the hyphen seems to be lost from the Zip field, so add it back in
+	my $institution_zip = $row_hashref->{"Zip"};
+	if ($institution_zip =~ /^(\d\d\d\d\d)(\d\d\d\d)$/) {
+	    $row_hashref->{"Zip"} = $1 . "-" . $2;
+	}
+
+	# Fix up the links to the institution webpage
+	if ($row_hashref->{"Institution_webpage"} =~ /\#(.*?)\#/) {
+	    $row_hashref->{"Institution_webpage"} = $1;
+	}
+
+	# Map state to full name
+	$row_hashref->{"State"} = $state_abbr_to_name_mapping->{$row_hashref->{"State"}};
+
+	# Get the places in this institution
+	my $institution_random_place_id;
+	my $institution_places_list_html = "";
+	$institution_places_sql_handle->execute($institution_id) or die "Could not execute SQL statement.";
+	while (my $institution_places_match_hashref = $institution_places_sql_handle->fetchrow_hashref) {
+	    my $institution_place_id = $institution_places_match_hashref->{"Entry_ID"};
+	    my $institution_place_name = $institution_places_match_hashref->{"Current_name"};
+	    $institution_places_list_html .= "<a href=\"_gwcgi_?a=d&d=p$institution_place_id\">$institution_place_name</a><br />\n";
+	}
+	&new_metadata_entry($institution_doc_obj, "InstitutionPlacesListHTML", $institution_places_list_html);
+
+	# Get the best place image for this institution
+	my $institution_best_place_image_name = $row_hashref->{"Best_image"};
+	if (!defined($institution_best_place_image_name) || $institution_best_place_image_name eq "") {
+	    # Some institutions have no electronic images, and thus have no best image
+	    $institution_places_images_sql_handle->execute($institution_id) or die "Could not execute SQL statement.";
+	    if (defined($institution_places_images_sql_handle->fetchrow_hashref())) {
+		print STDERR "<ProcessingError n='Institution $institution_id' p='CICPlug' r='No best image'>\n" if ($self->{'gli'});
+		print STDERR "Error: Institution $institution_id -- No best image.\n";
+		print $fail_log_handle "Error: Institution $institution_id -- No best image.\n";
+		$self->{'num_not_processed'}++;
+		next;
+	    }
+	    &new_metadata_entry($institution_doc_obj, "InstitutionBestPlaceImageHTML", "");
+	}
+	else {
+	    # Get the file location of the best place image for this institution
+	    $institution_best_place_image_location_sql_handle->execute($institution_best_place_image_name) or die "Could not execute SQL statement.";
+	    my $institution_best_place_image_hashref = $institution_best_place_image_location_sql_handle->fetchrow_hashref();
+
+	    my $institution_best_place_image_location = $institution_best_place_image_hashref->{"Location"};
+	    if (!defined($institution_best_place_image_location) || $institution_best_place_image_location eq "") {
+		print STDERR "<ProcessingError n='Institution $institution_id' p='CICPlug' r='Could not match best image $institution_best_place_image_name to a file'>\n" if ($self->{'gli'});
+		print STDERR "Error: Institution $institution_id -- Could not match best image $institution_best_place_image_name to a file.\n";
+		print $fail_log_handle "Error: Institution $institution_id -- Could not match best image $institution_best_place_image_name to a file.\n";
+		$self->{'num_not_processed'}++;
+		next;
+	    }
+
+	    # PDFs are not allowed for institution best place images
+	    if ($institution_best_place_image_location =~ /.pdf$/i) {
+		print STDERR "<ProcessingError n='Institution $institution_id' p='CICPlug' r='PDF not allowed for best image'>\n" if ($self->{'gli'});
+		print STDERR "Error: Institution $institution_id -- PDF not allowed for best image.\n";
+		print $fail_log_handle "Error: Institution $institution_id -- PDF not allowed for best image.\n";
+		$self->{'num_not_processed'}++;
+		next;
+	    }
+
+	    my $institution_best_place_id = $institution_best_place_image_hashref->{"Entry_ID"};
+	    my $institution_best_place_image_medium_file_href = $self->generate_place_image_variant($institution_doc_obj, $institution_best_place_image_location, "medium");
+	    &new_metadata_entry($institution_doc_obj, "InstitutionBestPlaceImageHTML", "<a href=\"_gwcgi_?a=d&d=p$institution_best_place_id\"><img alt=\"$institution_best_place_image_name\" src=\"$institution_best_place_image_medium_file_href\"/><br />$institution_best_place_image_name</a>");
+	}
+
+	# Get institution campus plans
+	my $institution_campus_plans_list_html = "";
+	$institution_campus_plans_sql_handle->execute($institution_id) or die "Could not execute SQL statement.";
+	while (my $institution_campus_plans_match_hashref = $institution_campus_plans_sql_handle->fetchrow_hashref) {
+	    my $institution_campus_plan_name = $institution_campus_plans_match_hashref->{"NameAndFormat"};
+	    my $institution_campus_plan_image_location = $institution_campus_plans_match_hashref->{"Location_electronic"};
+
+	    # Deal with PDF files separately: don't convert, just associate
+	    if ($institution_campus_plan_image_location =~ /\.pdf$/i) {
+		# Convert the server location of the file into the local location of the file
+		my $institution_campus_plan_pdf_file_path = $institution_campus_plan_image_location;
+		$institution_campus_plan_pdf_file_path =~ s/^[A-Z]:/$self->{'images_directory'}/;
+
+		if (-f $institution_campus_plan_pdf_file_path) {
+		    my $institution_campus_plan_pdf_file_name = $institution_campus_plan_name . ".pdf";
+		    $institution_campus_plan_pdf_file_name =~ s/ /%20/g;
+		    my $institution_campus_plan_pdf_file_href = "_httpcollection_/index/assoc/[assocfilepath]/$institution_campus_plan_pdf_file_name";
+		    $institution_campus_plans_list_html .= "<a href=\"$institution_campus_plan_pdf_file_href\">$institution_campus_plan_name (PDF)</a><br />";
+
+		    $institution_doc_obj->associate_file($institution_campus_plan_pdf_file_path, $institution_campus_plan_name . ".pdf", undef, $institution_doc_obj->get_top_section());
+		}
+		else {
+		    print STDERR "<ProcessingError n='$institution_campus_plan_pdf_file_path' p='CICPlug' r='Does not exist'>\n" if ($self->{'gli'});
+		    print STDERR "Error: File $institution_campus_plan_pdf_file_path does not exist.\n";
+		    print $fail_log_handle "Error: File $institution_campus_plan_pdf_file_path does not exist.\n";
+		}
+	    }
+	    else {
+		my $institution_campus_plan_image_large_file_href = $self->generate_place_image_variant($institution_doc_obj, $institution_campus_plan_image_location, "large");
+
+		# Create a new section for each institution campus plan image
+		my $institution_campus_plan_image_section = $institution_doc_obj->insert_section($institution_doc_obj->get_end_child($institution_doc_obj->get_top_section()));
+		$institution_doc_obj->add_utf8_text($institution_campus_plan_image_section, "_");  # This is necessary
+		$institution_doc_obj->add_utf8_metadata($institution_campus_plan_image_section, "DocumentType", "Image");
+		$institution_doc_obj->add_utf8_metadata($institution_campus_plan_image_section, "Title", $institution_campus_plan_name);
+		$institution_doc_obj->add_utf8_metadata($institution_campus_plan_image_section, "ImagePath", $institution_campus_plan_image_large_file_href);
+
+		$institution_campus_plans_list_html .= "<a href=\"_gwcgi_?a=d&d=i$institution_id.$institution_campus_plan_image_section\">$institution_campus_plan_name</a><br />";
+	    }
+	}
+	&new_metadata_entry($institution_doc_obj, "InstitutionCampusPlansListHTML", $institution_campus_plans_list_html);
+
+	# Add each field from the table as metadata
+	foreach my $key (keys(%$row_hashref)) {
+	    my $value = $row_hashref->{$key};
+	    if (defined($value)) {
+		&new_metadata_entry($institution_doc_obj, $key, $value);
+	    }
+	}
+
+	$institution_doc_obj->add_utf8_text($institution_doc_obj->get_top_section(), "Some dummy text.");
+	$self->{'processor'}->process($institution_doc_obj);
+	$self->{'num_processed'}++;
+
+	# Build mappings for creating the static macrofiles
+	my $institution_name = $row_hashref->{"Institution_Name"};
+	$institution_id_to_name_mapping{$institution_doc_obj->get_OID()} = $institution_name;
+	my $institution_state = $row_hashref->{"State"};
+	push(@{$institution_state_to_ids_mapping{$institution_state}}, $institution_doc_obj->get_OID());
+    }
+
+    # Write the institutions.dm macrofile
+    &write_static_browser_macrofile("institutions", \%institution_id_to_name_mapping);
+
+    # Write the states.dm macrofile
+    &write_state_browser_macrofile("states", \%institution_state_to_ids_mapping, \%institution_id_to_name_mapping);
+}
+
+
+sub process_places
+{
+    my $self = shift(@_);
+    my $dbh = shift(@_);
+    my $fail_log_handle = $self->{'failhandle'};
+
+    # Prepare SQL statement for getting everything from the Place table
+    my $place_sql_statement = "SELECT * FROM tblPlace";  # WHERE Entry_ID<100";
+    my $place_sql_handle = $dbh->prepare($place_sql_statement);
+    $place_sql_handle->{LongReadLen} = 65536;
+    $place_sql_handle->execute() or die "Could not execute SQL statement.";
+
+    # Prepare SQL statement for getting the Place institution
+    my $place_institution_sql_statement = "SELECT Institution_Name FROM tblInstitution,tblPlace WHERE tblInstitution.Institution_ID=tblPlace.Institution_ID and tblPlace.Entry_ID=?";
+    my $place_institution_sql_handle = $dbh->prepare($place_institution_sql_statement);
+
+    # Prepare SQL statement for getting the Place construction dates
+    my $place_construction_dates_sql_statement = "SELECT Prefix,Date,Note,Architect_Name FROM tblConstruction_and_Dates WHERE Entry_ID=? ORDER BY Date";
+    my $place_construction_dates_sql_handle = $dbh->prepare($place_construction_dates_sql_statement);
+
+    # Prepare SQL statement for getting the Place images
+    my $place_images_sql_statement = "SELECT FileName,Location FROM tblImages WHERE FileType=1 AND Entry_ID=? ORDER BY Image_Order";
+    my $place_images_sql_handle = $dbh->prepare($place_images_sql_statement);
+    $place_images_sql_handle->{LongReadLen} = 65536;
+
+    # Prepare SQL statement for getting the Place materials
+    my $place_materials_sql_statement = "SELECT * FROM tblDescription_building WHERE Entry_ID=?";
+    my $place_materials_sql_handle = $dbh->prepare($place_materials_sql_statement);
+    $place_materials_sql_handle->{LongReadLen} = 65536;
+
+    # Prepare SQL statement for getting the Place building styles
+    my $place_styles_sql_statement = "SELECT ArchType_ID FROM ArchPlace WHERE Entry_ID=?";
+    my $place_styles_sql_handle = $dbh->prepare($place_styles_sql_statement);
+    $place_styles_sql_handle->{LongReadLen} = 65536;
+
+    # Prepare SQL statement for getting the Place functions
+    my $place_functions_sql_statement = "SELECT Function,Year,Prefix FROM tblFunction_and_dates WHERE Entry_ID=? ORDER BY Year";
+    my $place_functions_sql_handle = $dbh->prepare($place_functions_sql_statement);
+    $place_functions_sql_handle->{LongReadLen} = 65536;
+
+    # Prepare SQL statement for getting the Place significance
+    my $place_significance_sql_statement = "SELECT SigType FROM tblSigTypes,SigPlace WHERE tblSigTypes.SigTypes_ID=SigPlace.SigType_ID+1 AND SigPlace.Entry_ID=?";
+    my $place_significance_sql_handle = $dbh->prepare($place_significance_sql_statement);
+    $place_significance_sql_handle->{LongReadLen} = 65536;
+
+    # Prepare SQL statement for getting the Place references
+    my $place_references_sql_statement = "SELECT Bibliography FROM tblReferences WHERE Entry_ID=?";
+    my $place_references_sql_handle = $dbh->prepare($place_references_sql_statement);
+    $place_references_sql_handle->{LongReadLen} = 65536;
+
+    # Prepare SQL statement for getting the Place designations
+    my $place_designations_sql_statement = "SELECT National_Register,Federal_Agency,HABS,HAER,Local_Designation FROM tblReferences WHERE Entry_ID=?";
+    my $place_designations_sql_handle = $dbh->prepare($place_designations_sql_statement);
+    $place_designations_sql_handle->{LongReadLen} = 65536;
+
+    # Prepare SQL statement for getting the Place narrative
+    my $place_narrative_sql_statement = "SELECT Narrative FROM tblSignificance_Narrative WHERE Entry_ID=?";
+    my $place_narrative_sql_handle = $dbh->prepare($place_narrative_sql_statement);
+    $place_narrative_sql_handle->{LongReadLen} = 65536;
+
+    # Prepare SQL statement for getting the Place state
+    my $place_state_sql_statement = "SELECT State FROM tblInstitution,tblPlace WHERE tblInstitution.Institution_ID=tblPlace.Institution_ID AND Entry_ID=?";
+    my $place_state_sql_handle = $dbh->prepare($place_state_sql_statement);
+    $place_state_sql_handle->{LongReadLen} = 65536;
+
+    # Create a document object for each place
+    my %place_type_to_ids_mapping;
+    my %place_style_to_ids_mapping;
+    my %place_date_to_ids_mapping;
+    my %place_function_to_ids_mapping;
+    my %place_id_to_name_mapping;
+    my %place_id_to_institution_name_mapping;
+    while (my $row_hashref = $place_sql_handle->fetchrow_hashref) {
+	my $place_id = $row_hashref->{"Entry_ID"};
+	# print STDERR "       Place $place_id\n";
+	my $place_doc_obj = new doc($self->{'filename'} . "-", "indexed_doc");
+	$place_doc_obj->set_OID("p$place_id");
+	&new_metadata_entry($place_doc_obj, "DocumentType", "Place");
+
+	# Convert the place type ID into a name
+	$row_hashref->{"PlaceType"} = $place_type_id_to_name_mapping->{$row_hashref->{"PlaceType"}};
+
+	# Add each field from the table as metadata
+	foreach my $key (keys(%$row_hashref)) {
+	    my $value = $row_hashref->{$key};
+	    if (defined($value)) {
+		&new_metadata_entry($place_doc_obj, $key, $value);
+	    }
+	}
+
+	# Get place name
+	my $place_name = $row_hashref->{"Current_name"};
+	if (!defined($place_name)) {
+	    print STDERR "<ProcessingError n='Place $place_id' p='CICPlug' r='Missing place name'>\n" if ($self->{'gli'});
+	    print STDERR "Error: Place $place_id -- Missing place name.\n";
+	    print $fail_log_handle "Error: Place $place_id -- Missing place name.\n";
+	    $self->{'num_not_processed'}++;
+	    next;
+	}
+
+	# Get place type
+	my $place_type = $row_hashref->{"PlaceType"};
+	if (!defined($place_type)) {
+	    print STDERR "<ProcessingError n='Place $place_id' p='CICPlug' r='Missing place type'>\n" if ($self->{'gli'});
+	    print STDERR "Error: Place $place_id -- Missing place type.\n";
+	    print $fail_log_handle "Error: Place $place_id -- Missing place type.\n";
+	    $self->{'num_not_processed'}++;
+	    next;
+	}
+
+	# Create place styles mapping
+	$place_styles_sql_handle->execute($place_id) or die "Could not execute SQL statement.";
+	while (my $place_styles_match_hashref = $place_styles_sql_handle->fetchrow_hashref()) {
+	    # The ArchType_ID is actually an index into the tblArchType table, NOT a link
+	    my $place_style_index = $place_styles_match_hashref->{"ArchType_ID"};
+	    my $place_style = $place_styles_array[$place_style_index];
+	    push(@{$place_style_to_ids_mapping{$place_style}}, $place_doc_obj->get_OID());
+	    &new_metadata_entry($place_doc_obj, "Style", $place_style);
+	}
+
+	# Get place institution
+	$place_institution_sql_handle->execute($place_id) or die "Could not execute SQL statement.";
+	my $place_institution = $place_institution_sql_handle->fetchrow();
+	&new_metadata_entry($place_doc_obj, "Institution_name", $place_institution);
+	$place_id_to_institution_name_mapping{$place_doc_obj->get_OID()} = ", " . $place_institution;
+
+	# Get place state and area (for searching)
+	$place_state_sql_handle->execute($place_id) or die "Could not execute SQL statement.";
+	my $place_state_abbr = $place_state_sql_handle->fetchrow();
+	&new_metadata_entry($place_doc_obj, "State", $place_state_abbr . " " . $state_abbr_to_name_mapping->{$place_state_abbr} . " " . $state_abbr_to_area_mapping->{$place_state_abbr});
+
+	# Get place construction dates
+	my $place_construction_dates_table_html = "";
+	$place_construction_dates_sql_handle->execute($place_id) or die "Could not execute SQL statement.";
+	while (my $place_construction_dates_match_hashref = $place_construction_dates_sql_handle->fetchrow_hashref()) {
+	    my $place_construction_date = $place_construction_dates_match_hashref->{"Date"};
+	    if (!defined($place_construction_date)) {
+		# Landscape sites are allowed to have no construction information
+		next if ($place_type eq "Landscape site");
+
+		print STDERR "<ProcessingError n='Place $place_id' p='CICPlug' r='Missing construction date'>\n" if ($self->{'gli'});
+		print STDERR "Error: Place $place_id -- Missing construction date.\n";
+		print $fail_log_handle "Error: Place $place_id -- Missing construction date.\n";
+		next;
+	    }
+
+	    # Convert the construction date to a time period (for searching and browsing)
+	    if ($place_construction_date =~ /^(\d{1,4}).*$/) {
+		my $place_construction_year = $1;
+
+		my $place_time_period;
+		if ($place_construction_year < 1800) { $place_time_period = "pre-1800"; }
+		elsif ($place_construction_year < 1850) { $place_time_period = "1800-1850"; }
+		elsif ($place_construction_year < 1900) { $place_time_period = "1850-1900"; }
+		elsif ($place_construction_year < 1945) { $place_time_period = "1900-1945"; }
+		elsif ($place_construction_year <= 1995) { $place_time_period = "1945-1995"; }
+		elsif ($place_construction_year > 1995) { $place_time_period = "post-1995"; }
+		push(@{$place_date_to_ids_mapping{$place_time_period}}, $place_doc_obj->get_OID());
+		&new_metadata_entry($place_doc_obj, "Time_period", $place_time_period);
+	    }
+	    elsif ($place_construction_date ne "n.d." && $place_construction_date ne "unknown" && $place_construction_date ne "various") {
+		print STDERR "<ProcessingError n='Place $place_id' p='CICPlug' r='Warning: Unknown construction date: $place_construction_date'>\n" if ($self->{'gli'});
+		print STDERR "Warning: Place $place_id -- Unknown construction date: $place_construction_date.\n";
+		print $fail_log_handle "Warning: Place $place_id -- Unknown construction date: $place_construction_date.\n";
+	    }
+
+	    my $place_construction_note = $place_construction_dates_match_hashref->{"Note"};
+	    if (!defined($place_construction_note)) {
+		# "No date" entries are allowed to have no construction note
+		next if ($place_construction_date eq "n.d");
+ 
+		print STDERR "<ProcessingError n='Place $place_id' p='CICPlug' r='Missing construction note'>\n" if ($self->{'gli'});
+		print STDERR "Error: Place $place_id -- Missing construction note.\n";
+		print $fail_log_handle "Error: Place $place_id -- Missing construction note.\n";
+		next;
+	    }
+
+	    # Get the architects for this construction and remember them for later for the designer objects
+	    my $place_construction_architect = $place_construction_dates_match_hashref->{"Architect_Name"} || "";
+	    my $place_construction_architect_links = "";
+	    foreach my $designer_name (split(/;/, $place_construction_architect)) {
+		$designer_name =~ s/\(.*?\)//g;
+		$designer_name =~ s/^\s*//;
+		$designer_name =~ s/\s*$//;
+
+		my $designer_id = $designer_name_to_id_mapping{$designer_name};
+		if (!defined($designer_id)) {
+		    $designer_id = scalar(keys(%designer_name_to_id_mapping)) + 1;
+		    $designer_name_to_id_mapping{$designer_name} = $designer_id;
+		}
+		$place_construction_architect_links .= "<a href=\"_gwcgi_?a=d&d=d$designer_id\">$designer_name</a> ";
+		push(@{$designer_name_to_place_ids_mapping{$designer_name}}, $place_id);
+	    }
+
+	    my $place_construction_date_prefix = $place_construction_dates_match_hashref->{"Prefix"} || "";
+	    $place_construction_dates_table_html .= "<tr><td class=\"cicplaceconstructiondatetd\" valign=\"top\">$place_construction_date_prefix $place_construction_date</td><td valign=\"top\">$place_construction_note $place_construction_architect_links</td></tr>";
+	}
+	&new_metadata_entry($place_doc_obj, "PlaceConstructionDatesTableHTML", "<table id=\"cicplaceconstructiondatestable\" cellpadding=\"0\" cellspacing=\"0\">" . $place_construction_dates_table_html . "</table>");
+
+	# Get place materials (individual buildings only)
+	if ($row_hashref->{"PlaceType"} eq "Individual building") {
+	    $place_materials_sql_handle->execute($place_id) or die "Could not execute SQL statement.";
+	    my $place_materials_match_hashref = $place_materials_sql_handle->fetchrow_hashref();
+	    &new_metadata_entry($place_doc_obj, "MaterialFoundation", $place_materials_match_hashref->{"foundation"} || "");
+	    &new_metadata_entry($place_doc_obj, "MaterialRoof", $place_materials_match_hashref->{"roof"} || "");
+	    &new_metadata_entry($place_doc_obj, "MaterialWalls", $place_materials_match_hashref->{"walls"} || "");
+
+	    &new_metadata_entry($place_doc_obj, "Materials", $place_materials_match_hashref->{"foundation"} || "");
+	    &new_metadata_entry($place_doc_obj, "Materials", $place_materials_match_hashref->{"roof"} || "");
+	    &new_metadata_entry($place_doc_obj, "Materials", $place_materials_match_hashref->{"walls"} || "");
+	}
+
+	# Get place functions
+	my $place_functions = "";
+	my $place_functions_table_html = "";
+	$place_functions_sql_handle->execute($place_id) or die "Could not execute SQL statement.";
+	while (my $place_functions_match_hashref = $place_functions_sql_handle->fetchrow_hashref()) {
+	    my $place_function = $place_functions_match_hashref->{"Function"};
+	    if (!defined($place_function)) {
+		print STDERR "<ProcessingError n='Place $place_id' p='CICPlug' r='Missing function'>\n" if ($self->{'gli'});
+		print STDERR "Error: Place $place_id -- Missing function.\n";
+		print $fail_log_handle "Error: Place $place_id -- Missing function.\n";
+		next;
+	    }
+	    # Check for multiline values (these are errors)
+	    if ($place_function =~ /\n/) {
+		print STDERR "<ProcessingError n='Place $place_id' p='CICPlug' r='Multiline function'>\n" if ($self->{'gli'});
+		print STDERR "Error: Place $place_id -- Multiline function.\n";
+		print $fail_log_handle "Error: Place $place_id -- Multiline function.\n";
+		next;
+	    }
+	    my $place_year = $place_functions_match_hashref->{"Year"};
+	    if (!defined($place_year)) {
+		print STDERR "<ProcessingError n='Place $place_id' p='CICPlug' r='Missing function year'>\n" if ($self->{'gli'});
+		print STDERR "Error: Place $place_id -- Missing function year.\n";
+		print $fail_log_handle "Error: Place $place_id -- Missing function year.\n";
+		next;
+	    }
+	    my $place_year_prefix = $place_functions_match_hashref->{"Prefix"} || "";
+	    $place_functions_table_html .= "<tr><td class=\"cicplacefunctionyeartd\" valign=\"top\">$place_year_prefix $place_year</td><td valign=\"top\">$place_function</td></tr>";
+
+	    # Prepare function metadata for browsing and searching
+	    my $place_function_to_index = lc($place_function);  # Casefold
+	    $place_function_to_index =~ s/^\s*//;  # Remove whitespace from the start
+	    if ($place_function_to_index =~ /^master plan/) {
+		$place_function_to_index =~ s/ \(campus,.*/ \(campus\)/;
+		$place_function_to_index =~ s/ \(campus:.*/ \(campus\)/;
+		$place_function_to_index =~ s/ \(landscape,.*/ \(landscape\)/;
+	    }
+	    else {
+		$place_function_to_index =~ s/\(.*\)//g;  # Remove anything in parentheses
+	    }
+	    $place_function_to_index =~ s/\s*$//;  # Remove whitespace from the end
+
+	    # Deal with common plural cases
+  	    $place_function_to_index =~ s/classroom$/classrooms/;
+  	    $place_function_to_index =~ s/department buildings$/department building/;
+  	    $place_function_to_index =~ s/faculty office$/faculty offices/;
+  	    $place_function_to_index =~ s/garden$/gardens/;
+  	    $place_function_to_index =~ s/residence halls$/residence hall/;
+  	    $place_function_to_index =~ s/private residences$/private residence/;
+
+	    # Check it is one of the valid function values
+	    if (!defined($place_functions_mapping->{$place_function_to_index})) {
+		print STDERR "<ProcessingError n='Place $place_id' p='CICPlug' r='Warning: Unknown function: $place_function_to_index'>\n" if ($self->{'gli'});
+		print STDERR "Warning: Place $place_id -- Unknown function: $place_function_to_index.\n";
+		print $fail_log_handle "Warning: Place $place_id -- Unknown function: $place_function_to_index.\n";
+		next;
+	    }
+  	    push(@{$place_function_to_ids_mapping{$place_function_to_index}}, $place_doc_obj->get_OID());
+	    $place_functions .= "$place_function_to_index ";
+	}
+	&new_metadata_entry($place_doc_obj, "Functions", $place_functions);
+	&new_metadata_entry($place_doc_obj, "PlaceFunctionsTableHTML", "<table id=\"cicplacefunctionstable\" cellpadding=\"0\" cellspacing=\"0\">" . $place_functions_table_html . "</table>");
+
+	# Get place significance
+	$place_significance_sql_handle->execute($place_id) or die "Could not execute SQL statement.";
+	while (my $place_significance_match_hashref = $place_significance_sql_handle->fetchrow_hashref()) {
+	    my $place_significance = $place_significance_match_hashref->{"SigType"};
+	    &new_metadata_entry($place_doc_obj, "Significance", lc($place_significance));
+	}
+
+	# Get place references
+	$place_references_sql_handle->execute($place_id) or die "Could not execute SQL statement.";
+	my $place_references = $place_references_sql_handle->fetchrow();
+	if (defined($place_references)) {
+	    $self->process_place_references($place_doc_obj, $place_id, $place_name, $place_institution, $place_references);
+	}
+
+	# Get place designations
+	$place_designations_sql_handle->execute($place_id) or die "Could not execute SQL statement.";
+	my $place_designations_match_hashref = $place_designations_sql_handle->fetchrow_hashref();
+	if ($place_designations_match_hashref->{"National_Register"} eq "1") {
+	    &new_metadata_entry($place_doc_obj, "Designation", "National Register");
+	}
+	if ($place_designations_match_hashref->{"Federal_Agency"} eq "1") {
+	    &new_metadata_entry($place_doc_obj, "Designation", "National Historic Landmark");
+	}
+	if ($place_designations_match_hashref->{"HABS"} eq "1" || $place_designations_match_hashref->{"HAER"} eq "1") {
+	    &new_metadata_entry($place_doc_obj, "Designation", "HABS/HAER");
+	}
+	if ($place_designations_match_hashref->{"Local_Designation"} eq "1") {
+	    &new_metadata_entry($place_doc_obj, "Designation", "Local/State");
+	}
+
+	# Get place narrative
+	$place_narrative_sql_handle->execute($place_id) or die "Could not execute SQL statement.";
+	my $place_narrative = $place_narrative_sql_handle->fetchrow();
+	if (defined($place_narrative)) {
+	    my $place_narrative_html = &rtf_to_html($place_narrative);
+	    $place_narrative_html =~ s/(<br \/>(\s|\n)*)*$//;  # Remove any trailing <br /> tags
+	    &new_metadata_entry($place_doc_obj, "PlaceNarrativeHTML", $place_narrative_html);
+	}
+
+	# Get place images
+	my $place_images_html = "";
+	$place_images_sql_handle->execute($place_id) or die "Could not execute SQL statement.";
+	while (my $place_images_match_hashref = $place_images_sql_handle->fetchrow_hashref) {
+	    my $place_image_location = $place_images_match_hashref->{"Location"};
+	    my $place_image_name = $place_images_match_hashref->{"FileName"};
+
+	    # Deal with PDF files separately: don't convert, just associate
+	    if ($place_image_location =~ /\.pdf$/i) {
+		# Convert the server location of the PDF file into the local location of the file
+		my $place_pdf_file_path = $place_image_location;
+		$place_pdf_file_path =~ s/^[A-Z]:/$self->{'images_directory'}/;
+ 
+		if (-f $place_pdf_file_path) {
+		    my ($place_pdf_file_name) = ($place_pdf_file_path =~ /^.+\\(.+)$/);
+		    $place_doc_obj->associate_file($place_pdf_file_path, $place_pdf_file_name, undef, $place_doc_obj->get_top_section());
+
+		    $place_pdf_file_name =~ s/ /%20/g;
+		    my $place_pdf_file_href = "_httpcollection_/index/assoc/[assocfilepath]/$place_pdf_file_name";
+		    $place_images_html .= "<div class=\"cicplacepdf\"><a href=\"$place_pdf_file_href\">_iconpdf_</a><br /><a class=\"ciccaption\" href=\"$place_pdf_file_href\">$place_image_name (PDF)</a></div>\n";
+		}
+		else {
+		    print STDERR "<ProcessingError n='$place_pdf_file_path' p='CICPlug' r='Does not exist'>\n" if ($self->{'gli'});
+		    print STDERR "Error: File $place_pdf_file_path does not exist.\n";
+		    print $fail_log_handle "Error: File $place_pdf_file_path does not exist.\n";
+		}
+	    }
+	    else {
+		my $place_image_small_file_href = $self->generate_place_image_variant($place_doc_obj, $place_image_location, "small");
+		my $place_image_large_file_href = $self->generate_place_image_variant($place_doc_obj, $place_image_location, "large");
+
+		# Create a new section for each place image
+		my $place_image_section = $place_doc_obj->insert_section($place_doc_obj->get_end_child($place_doc_obj->get_top_section()));
+		$place_doc_obj->add_utf8_text($place_image_section, "_");  # This is necessary
+		$place_doc_obj->add_utf8_metadata($place_image_section, "DocumentType", "Image");
+		$place_doc_obj->add_utf8_metadata($place_image_section, "Title", $place_image_name);
+		$place_doc_obj->add_utf8_metadata($place_image_section, "ImagePath", $place_image_large_file_href);
+
+		$place_images_html .= "<div class=\"cicplaceimage\"><a href=\"_gwcgi_?a=d&d=p$place_id.$place_image_section\"><img alt=\"$place_image_name\" src=\"$place_image_small_file_href\"/></a><br /><a class=\"ciccaption\" href=\"_gwcgi_?a=d&d=p$place_id.$place_image_section\">$place_image_name</a></div>\n";
+	    }
+	}
+
+	&new_metadata_entry($place_doc_obj, "PlaceImagesHTML", $place_images_html);
+
+	$place_doc_obj->add_utf8_text($place_doc_obj->get_top_section(), "Some dummy text.");
+	$self->{'processor'}->process($place_doc_obj);
+	$self->{'num_processed'}++;
+
+	# Build mappings for creating the static macrofiles
+	$place_id_to_name_mapping{$place_doc_obj->get_OID()} = $place_name;
+	push(@{$place_type_to_ids_mapping{$place_type}}, $place_doc_obj->get_OID());
+    }
+
+    &write_bilevel_static_browser_macrofile("types", \%place_type_to_ids_mapping, \%place_id_to_name_mapping, \%place_id_to_institution_name_mapping);
+    &write_bilevel_static_browser_macrofile("styles", \%place_style_to_ids_mapping, \%place_id_to_name_mapping, \%place_id_to_institution_name_mapping);
+    &write_bilevel_static_browser_macrofile("dates", \%place_date_to_ids_mapping, \%place_id_to_name_mapping, \%place_id_to_institution_name_mapping);
+    &write_bilevel_static_browser_macrofile("functions", \%place_function_to_ids_mapping, \%place_id_to_name_mapping, \%place_id_to_institution_name_mapping);
+}
+
+
+sub process_place_references
+{
+    my $self = shift(@_);
+    my $place_doc_obj = shift(@_);
+    my $place_id = shift(@_);
+    my $place_name = shift(@_);
+    my $place_institution_name = shift(@_);
+    my $place_references_rtf_string = shift(@_);
+    my $fail_log_handle = $self->{'failhandle'};
+
+    # Convert the place references from RTF to HTML
+    my $place_references_html_raw = &rtf_to_html($place_references_rtf_string);
+    if ($place_references_html_raw =~ /[ <](http|www\.)/) {
+	print STDERR "<ProcessingError n='Place $place_id' p='CICPlug' r='Warning: Found possible web address in references without hyperlink tag.'>\n" if ($self->{'gli'});
+	print STDERR "Warning: Place $place_id -- Found possible web address in references without hyperlink tag.\n";
+	print $fail_log_handle "Warning: Place $place_id -- Found possible web address in references without hyperlink tag.\n";
+    }
+
+    # Split the references and try to parse title and author
+    my $place_references_html = "";
+    $place_references_html_raw =~ s/(\r|\n)//g;  # Remove all newlines
+    $place_references_html_raw =~ s/<br \/><i><br \/>/<br \/><br \/><i>/g;  # Move italic tags
+    my @place_references = split(/<br \/>\s*<br \/>/, $place_references_html_raw);
+    foreach my $place_reference (@place_references) {
+	$place_reference =~ s/^(<br \/>\s*)*//;
+	$place_reference =~ s/(<br \/>\s*)*$//;
+	next if ($place_reference !~ /\w/);
+	$place_references_html .= "<p class=\"cicreference\">" . $place_reference . "</p>\n";
+
+	my $place_reference_author = "";
+	my $place_reference_title = "";
+
+	# Case 0: A magic word in the first sentence
+	my $place_reference_first_sentence = $place_reference;
+	if ($place_reference =~ /^(.*?)\./) {
+	    $place_reference_first_sentence = $1;
+	}
+	if ($place_reference_first_sentence =~ /\b(collection|collections|papers|archives|database|letter|memo|inventory|photographs|minutes|reports|records)\b/i) {
+	    # Don't bother trying to parse the reference
+	}
+	# Case 1: Author (possibly empty), then title in italics or quotes
+	elsif ($place_reference =~ /^(.*?)<i>(.*?)<\/i>/ || $place_reference =~ /^(.*)"(.*?)"/) {
+	    $place_reference_author = $1;
+	    $place_reference_title = $2;
+	}
+	# Case 2: Zero or one fullstops, assume no author and title is complete text
+	elsif ($place_reference =~ /^[^\.]*\.[^\.]*$/ || $place_reference !~ /\./) {
+	    $place_reference_title = $place_reference;
+	}
+	else {
+	    print STDERR "<ProcessingError n='Place $place_id' p='CICPlug' r='Could not parse reference: $place_reference'>\n" if ($self->{'gli'});
+	    # print STDERR "Warning: Place $place_id -- Could not parse reference: $place_reference\n";
+	    print $fail_log_handle "Warning: Place $place_id -- Could not parse reference: $place_reference\n";
+	    next;
+	}
+
+	# Create a new Reference document for this place reference
+	my $place_reference_doc_obj = new doc($self->{'file'} . "-", "indexed_doc");
+	$place_reference_doc_obj->set_OID("pr$place_reference_id");
+	&new_metadata_entry($place_reference_doc_obj, "DocumentType", "PlaceReference");
+	&new_metadata_entry($place_reference_doc_obj, "PlaceID", $place_id);
+	&new_metadata_entry($place_reference_doc_obj, "PlaceName", $place_name);
+	&new_metadata_entry($place_reference_doc_obj, "PlaceInstitutionName", $place_institution_name);
+	&new_metadata_entry($place_reference_doc_obj, "Reference", $place_reference);
+	&new_metadata_entry($place_reference_doc_obj, "ReferenceAuthor", $place_reference_author);
+	&new_metadata_entry($place_reference_doc_obj, "ReferenceTitle", $place_reference_title);
+
+	$place_reference_doc_obj->add_utf8_text($place_reference_doc_obj->get_top_section(), "Some dummy text.");
+	$self->{'processor'}->process($place_reference_doc_obj);
+	$self->{'num_processed'}++;
+	$place_reference_id++;
+    }
+
+    &new_metadata_entry($place_doc_obj, "PlaceReferencesHTML", $place_references_html);
+}
+
+
+sub process_designers
+{
+    my $self = shift(@_);
+    my $dbh = shift(@_);
+    my $fail_log_handle = $self->{'failhandle'};
+
+    # Prepare SQL statement for getting the Place name
+    my $place_name_sql_statement = "SELECT Current_name FROM tblPlace WHERE Entry_ID=?";
+    my $place_name_sql_handle = $dbh->prepare($place_name_sql_statement);
+
+    # Prepare SQL statement for getting the Place institution
+    my $place_institution_sql_statement = "SELECT Institution_Name FROM tblInstitution,tblPlace WHERE tblInstitution.Institution_ID=tblPlace.Institution_ID and tblPlace.Entry_ID=?";
+    my $place_institution_sql_handle = $dbh->prepare($place_institution_sql_statement);
+
+    # Prepare SQL statement for getting the Place "date of construction"
+    my $place_construction_date_sql_statement = "SELECT Date FROM tblConstruction_and_Dates WHERE Entry_ID=?";
+    my $place_construction_date_sql_handle = $dbh->prepare($place_construction_date_sql_statement);
+
+    # Prepare SQL statement for getting the Place non-PDF images
+    my $place_images_sql_statement = "SELECT Location,FileName FROM tblImages WHERE FileType=1 AND Location NOT LIKE '%.pdf' AND Entry_ID=? ORDER BY Image_Order";
+    my $place_images_sql_handle = $dbh->prepare($place_images_sql_statement);
+    $place_images_sql_handle->{LongReadLen} = 65536;
+
+    # Create a document object for each designer
+    my %designer_id_to_name_mapping;
+    foreach my $designer_name (keys %designer_name_to_id_mapping) {
+  	my $designer_id = $designer_name_to_id_mapping{$designer_name};
+  	# print STDERR "       Designer $designer_id\n";
+  	my $designer_doc_obj = new doc($self->{'filename'} . "-", "indexed_doc");
+  	$designer_doc_obj->set_OID("d$designer_id");
+  	&new_metadata_entry($designer_doc_obj, "DocumentType", "Designer");
+
+  	&new_metadata_entry($designer_doc_obj, "Designer_name", $designer_name);
+
+	# Get designer places
+	my $designer_places_list_html = "";
+	my $last_designer_place_id = "";
+    	foreach my $designer_place_id (sort(@{$designer_name_to_place_ids_mapping{$designer_name}})) {
+	    # The designer may have worked on a place multiple times, so check for this
+	    next if ($designer_place_id eq $last_designer_place_id);
+	    $last_designer_place_id = $designer_place_id;
+
+	    # Get place name
+	    $place_name_sql_handle->execute($designer_place_id) or die "Could not execute SQL statement.";
+	    my $designer_place_name = $place_name_sql_handle->fetchrow();
+
+	    # Get place institution name
+	    $place_institution_sql_handle->execute($designer_place_id) or die "Could not execute SQL statement.";
+	    my $designer_place_institution_name = $place_institution_sql_handle->fetchrow();
+
+	    # Get place date of construction
+	    $place_construction_date_sql_handle->execute($designer_place_id) or die "Could not execute SQL statement.";
+	    my $designer_place_construction_date_value = $place_construction_date_sql_handle->fetchrow() || "";
+
+	    # Get the first non-PDF image for this place
+	    my $designer_place_image_small_file_href;
+    	    $place_images_sql_handle->execute($designer_place_id) or die "Could not execute SQL statement.";
+	    my $designer_place_images_match_hashref = $place_images_sql_handle->fetchrow_hashref();
+	    my $designer_place_image_location = $designer_place_images_match_hashref->{"Location"};
+	    my $designer_place_image_name = $designer_place_images_match_hashref->{"FileName"} || "No image";
+	    if (defined($designer_place_image_location)) {
+  		$designer_place_image_small_file_href = $self->generate_place_image_variant($designer_doc_obj, $designer_place_image_location, "small");
+	    }
+	    else {
+		# There is no non-PDF image for this place
+		$designer_place_image_small_file_href = "_httpcollection_/images/no_image-small.jpg";
+	    }
+
+	    $designer_places_list_html .= "<tr><td valign=\"top\"><a href=\"_gwcgi_?a=d&d=p$designer_place_id\"><img alt=\"$designer_place_image_name\" src=\"$designer_place_image_small_file_href\"/></a></td><td valign=\"top\"><a href=\"_gwcgi_?a=d&d=p$designer_place_id\">$designer_place_name</a>, $designer_place_institution_name<br /><b>Date of construction:</b> $designer_place_construction_date_value</td></tr>\n";
+	}
+
+  	&new_metadata_entry($designer_doc_obj, "DesignerPlacesListHTML", "<table>" . $designer_places_list_html . "</table>");
+
+  	$designer_doc_obj->add_utf8_text($designer_doc_obj->get_top_section(), "Some dummy text.");
+  	$self->{'processor'}->process($designer_doc_obj);
+	$self->{'num_processed'}++;
+
+	$designer_id_to_name_mapping{$designer_doc_obj->get_OID()} = $designer_name;
+    }
+
+    # Write the designers.dm macrofile
+    &write_static_browser_macrofile("designers", \%designer_id_to_name_mapping);
+}
+
+
+sub new_metadata_entry
+{
+    my ($doc_obj, $metadata_name, $metadata_value) = (@_);
+
+    # Don't bother with empty metadata
+    return if ($metadata_value eq "");
+
+    # Spaces aren't allowed in metadata names
+    $metadata_name =~ s/ /_/g;
+
+    # Anything from the database is Windows-1252 encoded, so convert to UTF-8
+    $metadata_value = &unicode::unicode2utf8(&unicode::convert2unicode("windows_1252", \$metadata_value));
+
+    # Escape any '[' and ']' characters so Greenstone doesn't try to treat the text as metadata...
+    $metadata_value =~ s/\[/&\#91;/g;
+    $metadata_value =~ s/\]/&\#93;/g;
+
+    # ...but don't mess up real metadata references!
+    $metadata_value =~ s/&\#91;assocfilepath&\#93;/\[assocfilepath\]/g;
+    $metadata_value =~ s/&\#91;parent\(Top\)\:assocfilepath&\#93;/\[parent(Top):assocfilepath\]/g;
+
+    # Escape any '&' characters so the metadata is HTML 4 compliant when displayed
+    $metadata_value =~ s/&([^\#])/&amp;$1/g;
+
+    $doc_obj->add_utf8_metadata($doc_obj->get_top_section(), $metadata_name, $metadata_value);
+}
+
+
+sub rtf_to_html
+{
+    my $rtf_string = shift(@_);
+ 
+    # Remove everything in curly braces, but keep any hyperlinks
+    while ($rtf_string =~ /\{(.*?)\}/) {
+	if ($1 =~ /HYPERLINK (.*)/) {
+	    my $link_url = $1;
+	    $link_url =~ s/^\"(.*?)\"$/$1/;  # Remove surrounding quotes
+	    $link_url =~ s/^\s*(.*?)\s*$/$1/;  # Remove surrounding whitespace
+	    $rtf_string =~ s/\{(.*?)\}/<a href=\"$link_url\">$link_url<\/a>/;
+	}
+	else {
+	    $rtf_string =~ s/\{(.*?)\}//;
+	}
+    }
+    $rtf_string =~ s/\\ldblquote\s/\"/g;
+    $rtf_string =~ s/\\ldblquote\b/\"/g;
+    $rtf_string =~ s/\\rdblquote\s/\"/g;
+    $rtf_string =~ s/\\rdblquote\b/\"/g;
+    $rtf_string =~ s/\\lquote\s/\'/g;
+    $rtf_string =~ s/\\lquote\b/\'/g;
+    $rtf_string =~ s/\\rquote\s/\'/g;
+    $rtf_string =~ s/\\rquote\b/\'/g;
+    $rtf_string =~ s/\\pard//g;
+    $rtf_string =~ s/\\par/<br \/>/g;
+    $rtf_string =~ s/\\ul\s/<i>/g;
+    $rtf_string =~ s/\\ul\b/<i>/g;
+    $rtf_string =~ s/\\ulnone\s/<\/i>/g;
+    $rtf_string =~ s/\\ulnone\b/<\/i>/g;
+    $rtf_string =~ s/\\i\s/<i>/g;
+    $rtf_string =~ s/\\i\b/<i>/g;
+    $rtf_string =~ s/\\i0\s/<\/i>/g;
+    $rtf_string =~ s/\\i0\b/<\/i>/g;
+    $rtf_string =~ s/\\super //g;
+    $rtf_string =~ s/\\nosupersub //g;
+    $rtf_string =~ s/\\~/ /g;
+    $rtf_string =~ s/\\([A-Za-z0-9\-]+)//g;
+    $rtf_string =~ s/\}//g;
+
+    # Assume non-ASCII is ISO 8859-1, and convert into HTML entities
+    while ($rtf_string =~ /\\'([a-z0-9][a-z0-9])/) {
+        my $dec = hex($1);
+	$rtf_string =~ s/\\'$1/&#$dec\;/;
+    }
+
+    # Remove extra less-than and greater-than symbols
+    $rtf_string =~ s/< </</g;
+    $rtf_string =~ s/<(<+)/</g;
+    $rtf_string =~ s/> >/>/g;
+    $rtf_string =~ s/>(>+)/>/g;
+
+    # Remove empty tags for HTML 4 compliance
+    $rtf_string =~ s/<i>\s*<\/i>/ /g;
+
+    return $rtf_string;
+}
+
+
+sub get_place_image_dimensions
+{
+    my $self = shift(@_);
+    my $place_image_file_path = shift(@_);
+    my $fail_log_handle = $self->{'failhandle'};
+
+    # Make sure the place image file actually exists
+    if (!-f $place_image_file_path) {
+	print STDERR "<ProcessingError n='$place_image_file_path' p='CICPlug' r='Does not exist'>\n" if ($self->{'gli'});
+	print STDERR "Error: Image $place_image_file_path does not exist.\n";
+	print $fail_log_handle "Error: Image $place_image_file_path does not exist.\n";
+	return;
+    }
+    my $place_image_file_date = (stat($place_image_file_path))[9];
+
+    # Check if this place image has already been identified by looking for a ".info" file in the same directory
+    my $place_image_info_file_path = $place_image_file_path . ".info";
+    if (-f $place_image_info_file_path) {
+	# A ".info" file exists, so read the cached place image information from it
+	open(PLACE_IMAGE_INFO_FILE, "<$place_image_info_file_path");
+	my @place_image_info = <PLACE_IMAGE_INFO_FILE>;
+	close(PLACE_IMAGE_INFO_FILE);
+
+  	# Read the cached place image file date and check that it matches
+  	my $cached_place_image_file_date = $place_image_info[0];
+  	$cached_place_image_file_date =~ s/\n$//;
+  	if ($cached_place_image_file_date == $place_image_file_date) {
+	    # It does match, so use the cached information from the ".info" file instead of re-identifying the file
+  	    my $place_image_width = $place_image_info[1];
+  	    $place_image_width =~ s/\n$//;
+  	    my $place_image_height = $place_image_info[2];
+  	    $place_image_height =~ s/\n$//;
+	    return ($place_image_width, $place_image_height);
+	}
+    }
+
+    # We haven't already identified the place image, so do it now
+    print STDERR "Identifying place image $place_image_file_path...\n";
+    my $identify_command = "identify -format \"%w %h\" \"$place_image_file_path\"";
+    my $identify_result = `$identify_command`;
+    print "Identify result: $identify_result\n" if ($self->{'verbosity'} > 2);
+
+    # Check that the output is what we're expecting
+    if ($identify_result !~ /(\d+) (\d+)/) {
+	print STDERR "<ProcessingError n='$place_image_file_path' p='CICPlug' r='Could not identify'>\n" if ($self->{'gli'});
+	print STDERR "Error: Place image $place_image_file_path could not be identified.\n";
+	print $fail_log_handle "Error: Place image $place_image_file_path could not be identified.\n";
+	return;
+    }
+
+    # Parse the place image width and height from the output
+    my $place_image_width = $1;
+    my $place_image_height = $2;
+
+    # Write the place image info file so we don't have to identify this exact image again in the future
+    open(PLACE_IMAGE_INFO_FILE, ">$place_image_info_file_path");
+    print PLACE_IMAGE_INFO_FILE "$place_image_file_date\n";
+    print PLACE_IMAGE_INFO_FILE "$place_image_width\n";
+    print PLACE_IMAGE_INFO_FILE "$place_image_height\n";
+    close(PLACE_IMAGE_INFO_FILE);
+    return ($place_image_width, $place_image_height);
+}
+
+
+sub generate_place_image_variant
+{
+    my $self = shift(@_);
+    my ($doc_obj, $place_image_location, $place_image_variant_size) = (@_);
+    my $fail_log_handle = $self->{'failhandle'};
+
+    # Convert the server location of the file into the local location of the file
+    my $place_image_file_path = $place_image_location;
+    $place_image_file_path =~ s/^[A-Z]:/$self->{'images_directory'}/;
+
+    # Get the width and height of the place image
+    my ($place_image_width, $place_image_height) = $self->get_place_image_dimensions($place_image_file_path);
+    if (!defined($place_image_width) || !defined($place_image_height)) {
+	# An error has occurred (error message generated by get_place_image_dimensions())
+	return;
+    }
+    my $place_image_file_date = (stat($place_image_file_path))[9];
+
+    # Generate the path of the place image variant (in the cache directory)
+    my $place_image_variant_file_suffix = "-$place_image_variant_size." . $self->{$place_image_variant_size . '_image_type'};
+    my $place_image_variant_file_path = $place_image_location;
+    $place_image_variant_file_path =~ s/^[A-Z]:/$self->{'cache_directory'}/;
+    $place_image_variant_file_path =~ s/^(.+)(\..*)/$1$place_image_variant_file_suffix/;
+    my ($place_image_variant_file_name) = ($place_image_variant_file_path =~ /^.+\\(.+)$/);
+
+    # Only scale down the place image if it is bigger than the desired width
+    my $place_image_variant_desired_width = $self->{$place_image_variant_size . '_image_width'};
+
+    if ($place_image_width > $place_image_variant_desired_width) {
+	# Only generate the place image variant if it doesn't already exist, or if the place image is newer
+	if (!-f $place_image_variant_file_path || $place_image_file_date > (stat($place_image_variant_file_path))[9]) {
+	    print STDERR "Generating place image variant $place_image_variant_file_path...\n";
+	    my ($place_image_variant_directory) = ($place_image_variant_file_path =~ /^(.+)\\.+$/);
+	    &util::mk_all_dir($place_image_variant_directory);
+	    my $place_image_variant_options = "-scale $place_image_variant_desired_width " . $self->{$place_image_variant_size . '_image_options'};
+	    my $convert_command = "convert $place_image_variant_options \"$place_image_file_path\" \"$place_image_variant_file_path\"";
+	    my $convert_result = `$convert_command`;
+	}
+    }
+    else {
+	# The desired width is bigger than the place image, so we just use the original
+	$place_image_variant_file_path = $place_image_file_path;
+    }
+
+    my ($place_image_variant_width, $place_image_variant_height) = $self->get_place_image_dimensions($place_image_variant_file_path);
+    if (!defined($place_image_variant_width) || !defined($place_image_variant_height)) {
+	# An error has occurred (error message generated by get_place_image_dimensions())
+	return;
+    }
+
+    # Associate the place image variant file
+    $doc_obj->associate_file($place_image_variant_file_path, $place_image_variant_file_name, undef, $doc_obj->get_top_section());
+
+    # Add various bits of metadata for the place image variant
+    my $place_image_variant_href = "_httpcollection_/index/assoc/{Or}{[parent(Top):assocfilepath],[assocfilepath]}/" . $place_image_variant_file_name;
+    $place_image_variant_href =~ s/ /%20/g;
+    return $place_image_variant_href;
+}
+
+
+sub write_static_browser_macrofile
+{
+    my $static_browser_package_name = shift(@_);
+    my $id_to_name_mapping = shift(@_);
+
+    my $static_browser_macrofile_path = "$ENV{'GSDLHOME'}\\collect\\cic-hcap\\macros\\$static_browser_package_name.dm";
+    print STDERR "Writing $static_browser_macrofile_path...\n";
+    open(BROWSER_MACROFILE, ">$static_browser_macrofile_path") or die "Error: Could not write to $static_browser_macrofile_path.\n";
+    &write_static_browser_macros($static_browser_package_name, $id_to_name_mapping);
+    close(BROWSER_MACROFILE);
+}
+
+
+sub write_static_browser_macros
+{
+    my $static_browser_package_name = shift(@_);
+    my $id_to_name_mapping = shift(@_);
+    my $id_to_extra_mapping = shift(@_);
+
+    print BROWSER_MACROFILE "package $static_browser_package_name\n\n";
+    print BROWSER_MACROFILE "_cicstaticbrowserquicklinks_ {\n";
+
+    my %letter_to_ids_mapping;
+    foreach my $id (keys %$id_to_name_mapping) {
+	my $name = $id_to_name_mapping->{$id};
+	my ($letter) = ($name =~ /([A-Za-z0-9])/);
+	push(@{$letter_to_ids_mapping{$letter}}, $id);
+    }
+
+    print BROWSER_MACROFILE "<b>";
+    foreach my $letter (split(//, "ABCDEFGHIJKLMNOPQRSTUVWXYZ")) {
+	if (defined($letter_to_ids_mapping{$letter})) {
+	    print BROWSER_MACROFILE "<a href=\"#$letter\">$letter</a>&nbsp;";
+	}
+	else {
+	    print BROWSER_MACROFILE "$letter&nbsp;";
+	}
+    }
+    print BROWSER_MACROFILE "</b>\n";
+    print BROWSER_MACROFILE "}\n\n";
+
+    print BROWSER_MACROFILE "_cicstaticbrowser_ {\n";
+    print BROWSER_MACROFILE "<table cellpadding=\"0\" cellspacing=\"0\" width=\"_pagewidth_\">\n";
+    foreach my $letter (sort(keys %letter_to_ids_mapping)) {
+	my @letter_ids = @{$letter_to_ids_mapping{$letter}};
+	my $anchor_name;
+	if ($letter =~ /^[A-Z]$/) {
+	    $anchor_name = $letter;
+	}
+	my $static_browser_macro_chunk = &get_static_browser_macro_chunk($letter, $anchor_name, \@letter_ids, $id_to_name_mapping, $id_to_extra_mapping);
+	print BROWSER_MACROFILE &unicode::unicode2utf8(&unicode::convert2unicode("windows_1252", \$static_browser_macro_chunk));
+    }
+    print BROWSER_MACROFILE "</table>\n";
+
+    print BROWSER_MACROFILE "}\n";
+}
+
+
+sub get_static_browser_macro_chunk
+{
+    my $chunk_title = shift(@_);
+    my $anchor_name = shift(@_);
+    my $chunk_ids_ref = shift(@_);
+    my $id_to_name_mapping = shift(@_);
+    my $id_to_extra_mapping = shift(@_);
+
+    my $static_browser_macro_chunk = "<tr><td width=\"50%\"><br />";
+    if (defined($anchor_name) && $anchor_name ne "") {
+	$static_browser_macro_chunk .= "<a name=\"$anchor_name\"/>";
+    }
+    $static_browser_macro_chunk .= "<span style=\"color: black;\"><b>$chunk_title</b></span></td><td width=\"50%\"></td></tr>";
+
+    my %full_name_to_id_mapping;
+    foreach my $id (@{$chunk_ids_ref}) {
+	my $full_name = $id_to_name_mapping->{$id};
+	if (defined($id_to_extra_mapping)) {
+	    $full_name .= " " . $id_to_extra_mapping->{$id};
+	}
+	$full_name_to_id_mapping{$full_name} = $id;
+    }
+ 
+    my @full_names = sort { lc($a) cmp lc($b) } (keys(%full_name_to_id_mapping));
+    my $half_point = ((scalar(@full_names) % 2 == 0) ? scalar(@full_names) / 2 : (scalar(@full_names) + 1) / 2);
+    for (my $i = 0; $i < $half_point; $i++) {
+	$static_browser_macro_chunk .= "<tr>";
+
+	my $id = $full_name_to_id_mapping{$full_names[$i]};
+	my $name = $id_to_name_mapping->{$id};
+	my $extra = $id_to_extra_mapping->{$id} || "";
+	$static_browser_macro_chunk .= "<td valign=\"top\"><a href=\"_gwcgi_?a=d&amp;d=$id\">" . &html_safe($name) . "</a>" . &html_safe($extra) . "</td>";
+
+	$static_browser_macro_chunk .= "<td valign=\"top\">";
+	if (defined($full_names[$i+$half_point])) {
+	    $id = $full_name_to_id_mapping{$full_names[$i+$half_point]};
+	    $name = $id_to_name_mapping->{$id};
+	    $extra = $id_to_extra_mapping->{$id} || "";
+	    $static_browser_macro_chunk .= "<a href=\"_gwcgi_?a=d&amp;d=$id\">" . &html_safe($name) . "</a>" . &html_safe($extra);
+	}
+	$static_browser_macro_chunk .= "</td>";
+
+	$static_browser_macro_chunk .= "</tr>";
+    }
+
+    return $static_browser_macro_chunk;
+}
+
+
+sub write_bilevel_static_browser_macrofile
+{
+    my $static_browser_package_root = shift(@_);
+    my $category_to_ids_mapping = shift(@_);
+    my $id_to_name_mapping = shift(@_);
+    my $id_to_extra_mapping = shift(@_);
+
+    my $static_browser_macrofile_path = "$ENV{'GSDLHOME'}\\collect\\cic-hcap\\macros\\$static_browser_package_root.dm";
+    print STDERR "Writing $static_browser_macrofile_path...\n";
+    open(BROWSER_MACROFILE, ">$static_browser_macrofile_path") or die "Error: Could not write to $static_browser_macrofile_path.\n";
+
+    foreach my $category (keys(%{$category_to_ids_mapping})) {
+	my $static_browser_package_name = $static_browser_package_root . $category;
+	$static_browser_package_name =~ s/\W//g;
+
+	my %id_to_name_mapping_for_category = ();
+	foreach my $id (@{$category_to_ids_mapping->{$category}}) {
+	    $id_to_name_mapping_for_category{$id} = $id_to_name_mapping->{$id};
+	}
+	&write_static_browser_macros($static_browser_package_name, \%id_to_name_mapping_for_category, $id_to_extra_mapping);
+    }
+
+    close(BROWSER_MACROFILE);
+}
+
+
+sub html_safe
+{
+    my $text = shift(@_);
+    $text =~ s/&/&amp;/g;
+    $text =~ s/\'/&\#39;/g;  # Apostrophes mess up Javascript on the Search by State page
+    return $text;
+}
+
+
+sub write_state_browser_macrofile
+{
+    my $static_browser_package_name = shift(@_);
+    my $state_to_ids_mapping = shift(@_);
+    my $id_to_name_mapping = shift(@_);
+
+    my $static_browser_macrofile_path = "$ENV{'GSDLHOME'}\\collect\\cic-hcap\\macros\\$static_browser_package_name.dm";
+    print STDERR "Writing $static_browser_macrofile_path...\n";
+    open(BROWSER_MACROFILE, ">$static_browser_macrofile_path") or die "Error: Could not write to $static_browser_macrofile_path.\n";
+    print BROWSER_MACROFILE "package $static_browser_package_name\n\n";
+    print BROWSER_MACROFILE "_cicstaticbrowser_ {\n";
+
+    print BROWSER_MACROFILE "<table cellpadding=\"0\" cellspacing=\"0\" width=\"_pagewidth_\">\n";
+    foreach my $state (sort(keys(%state_name_to_abbr_mapping))) {
+	my $state_abbr = $state_name_to_abbr_mapping{$state};
+	print BROWSER_MACROFILE "_cicstate" . $state_abbr . "_\n";
+    }
+    print BROWSER_MACROFILE "</table>\n";
+    print BROWSER_MACROFILE "}\n";
+
+    foreach my $state (sort(keys(%state_name_to_abbr_mapping))) {
+	my $state_sans_spaces = $state;
+	$state_sans_spaces =~ s/ //g;
+	my @state_ids = ();
+	if (defined($state_to_ids_mapping->{$state})) {
+	    @state_ids = @{$state_to_ids_mapping->{$state}};
+	}
+	my $state_abbr = $state_name_to_abbr_mapping{$state};
+
+	my $state_static_browser_macro_chunk = &get_static_browser_macro_chunk($state, $state_sans_spaces, \@state_ids, $id_to_name_mapping, undef);
+	if (!defined($state_to_ids_mapping->{$state})) {
+	    $state_static_browser_macro_chunk .= "<tr><td colspan=\"2\" valign=\"top\">No institutions for this state</td></tr>";
+	}
+
+	# Write out the normal macro chunk
+	print BROWSER_MACROFILE "\n_cicstate" . $state_abbr . "_ {";
+	print BROWSER_MACROFILE $state_static_browser_macro_chunk;
+	print BROWSER_MACROFILE "}\n";
+
+	# Write out a Javascript safe version
+	print BROWSER_MACROFILE "\n_cicstate" . $state_abbr . "js_ {";
+	print BROWSER_MACROFILE &javascript_safe($state_static_browser_macro_chunk);
+	print BROWSER_MACROFILE "}\n";
+    }
+
+    close(BROWSER_MACROFILE);
+}
+
+
+sub javascript_safe
+{
+    my $text = shift(@_);
+    $text =~ s/(\r|\n)//g;  # No newlines allowed
+    $text =~ s/<\//<\\\\\//g;
+    return $text;
+}
+
+
+1;
Index: collections/trunk/cic-hcap/perllib/plugins/CICWordPlug.pm
===================================================================
--- collections/trunk/cic-hcap/perllib/plugins/CICWordPlug.pm	(revision 14139)
+++ collections/trunk/cic-hcap/perllib/plugins/CICWordPlug.pm	(revision 14139)
@@ -0,0 +1,181 @@
+###########################################################################
+#
+# CICWordPlug.pm
+#
+# Copyright (C) 2006 New Zealand Digital Library Project
+#
+# 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.
+#
+###########################################################################
+
+package CICWordPlug;
+
+
+use ConvertToPlug;
+use strict;
+no strict 'refs';
+
+
+sub BEGIN {
+    @CICWordPlug::ISA = ('ConvertToPlug');
+}
+
+
+my $arguments = [ ];
+
+my $options = { 'name'     => "CICWordPlug",
+		'desc'     => "{CICWordPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+
+sub get_default_process_exp
+{
+    return q^(?i)\.doc$^;
+}
+
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = new ConvertToPlug($pluginlist, $inputargs, $hashArgOptLists);
+
+    return bless $self, $class;
+}
+
+
+sub read
+{
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;
+
+    $self->{'file'} = $file;
+    $self->{'processor'} = $processor;
+    $self->{'gli'} = $gli;
+
+    $self->SUPER::read($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli);
+}
+
+
+sub convert_post_process
+{
+    my $self = shift(@_);
+    my $conv_filename = shift(@_);
+    my $fail_log_handle = $self->{'failhandle'};
+
+    my $in_record = 0;
+    my $num_records = 0;
+    open(HTML_IN, $conv_filename);
+    while (my $line = <HTML_IN>) {
+	# Is this the end of a record?
+	if ($line =~ /^<\/p>/) {
+	    $in_record = 0;
+	}
+	# Is this the start of a possible record?
+	if ($line =~ /^<p /) {
+	    $in_record = 1;
+	}
+	elsif ($in_record == 1) {
+	    # Ignore lines completely in bold
+	    next if ($line =~ /^<b>(.*)<\/b>$/);
+
+	    my $line_sans_tags = $line;
+	    $line_sans_tags =~ s/<.*?>//g;
+
+	    # Type 1: No author, title in double quotes
+	    if ($line =~ /^&ldquo;(.*)&rdquo;/) {
+		$num_records++;
+		$self->add_reference_document($num_records, $line, $1, "");
+	    }
+
+	    # Type 2: Author, title in italics or quotes
+	    elsif ($line =~ /^(.*)<i>(.*)<\/i>/ || $line =~ /^(.*)&quot;(.*)&quot;/ || $line =~ /^(.*)&ldquo;(.*)&rdquo;/) {
+		$num_records++;
+		$self->add_reference_document($num_records, $line, $2, $1);
+	    }
+
+	    # Warning: Could not parse record
+	    elsif ($line_sans_tags =~ /\w/) {
+		print STDERR "<ProcessingError n='Bibliography' p='CICWordPlug' r='Could not parse reference: $line'>\n" if ($self->{'gli'});
+		print STDERR "Warning: Bibliography -- Could not parse reference: $line\n";
+		print $fail_log_handle "Warning: Bibliography -- Could not parse reference: $line\n";
+		$num_records++;
+		$self->add_reference_document($num_records, $line, "", "");
+	    }
+	}
+    }
+    close(HTML_IN);
+}
+
+
+sub add_reference_document
+{
+    my $self = shift(@_);
+    my $reference_id = shift(@_);
+    my $reference = shift(@_);
+    my $reference_title = shift(@_);
+    my $reference_author = shift(@_);
+
+    my $reference_doc_obj = new doc($self->{'file'} . "-", "indexed_doc");
+    $reference_doc_obj->set_OID("r$reference_id");
+    &new_metadata_entry($reference_doc_obj, "DocumentType", "Reference");
+    &new_metadata_entry($reference_doc_obj, "Reference", $reference);
+    &new_metadata_entry($reference_doc_obj, "ReferenceAuthor", $reference_author);
+    &new_metadata_entry($reference_doc_obj, "ReferenceTitle", $reference_title);
+
+    $reference_doc_obj->add_utf8_text($reference_doc_obj->get_top_section(), "Some dummy text.");
+    $self->{'processor'}->process($reference_doc_obj);
+    $self->{'num_processed'}++;
+}
+
+
+sub new_metadata_entry
+{
+    my ($doc_obj, $metadata_name, $metadata_value) = (@_);
+
+    # Don't bother with empty metadata
+    return if ($metadata_value eq "");
+
+    # Spaces aren't allowed in metadata names
+    $metadata_name =~ s/ /_/g;
+
+    # Anything from the database is ISO 8859-1 encoded, so convert to UTF-8
+    $metadata_value = &unicode::ascii2utf8(\$metadata_value);
+
+    # Remove '#' characters around links
+    if ($metadata_value =~ /\#(.*?)\#/) {
+	$metadata_value = $1;
+    }
+
+    # Escape any '[' and ']' characters so Greenstone doesn't try to treat the text as metadata...
+    $metadata_value =~ s/\[/&\#91;/g;
+    $metadata_value =~ s/\]/&\#93;/g;
+
+    # Remove any superscript tags
+    $metadata_value =~ s/\<sup\>//g;
+    $metadata_value =~ s/\<\/sup\>//g;
+
+    $doc_obj->add_utf8_metadata($doc_obj->get_top_section(), $metadata_name, $metadata_value);
+}
+
+
+1;
+
